aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java
blob: 4cef67865e2b12e8d85b5a628bf82214d5dd08db (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package tools.refinery.store.statecoding.neighbourhood;

import org.eclipse.collections.api.factory.primitive.IntLongMaps;
import org.eclipse.collections.api.map.primitive.MutableIntLongMap;
import org.eclipse.collections.api.set.primitive.IntSet;
import tools.refinery.store.model.AnyInterpretation;
import tools.refinery.store.model.Interpretation;
import tools.refinery.store.model.Model;
import tools.refinery.store.statecoding.ObjectCode;
import tools.refinery.store.tuple.Tuple;
import tools.refinery.store.tuple.Tuple0;

import java.util.*;

public abstract class AbstractNeighbourhoodCalculator {
	protected final Model model;
	protected final List<AnyInterpretation> nullImpactValues;
	protected final LinkedHashMap<AnyInterpretation, long[]> impactValues;
	protected final MutableIntLongMap individualHashValues = IntLongMaps.mutable.empty();

	protected static final long PRIME = 31;

	protected AbstractNeighbourhoodCalculator(Model model, List<? extends AnyInterpretation> interpretations,
											  IntSet individuals) {
		this.model = model;
		this.nullImpactValues = new ArrayList<>();
		this.impactValues = new LinkedHashMap<>();
		// Random isn't used for cryptographical purposes but just to assign distinguishable identifiers to symbols.
		@SuppressWarnings("squid:S2245")
		Random random = new Random(1);

		var individualsInOrder = individuals.toSortedList(Integer::compare);
		for(int i = 0; i<individualsInOrder.size(); i++) {
			individualHashValues.put(individualsInOrder.get(i), random.nextLong());
		}

		for (AnyInterpretation interpretation : interpretations) {
			int arity = interpretation.getSymbol().arity();
			if (arity == 0) {
				nullImpactValues.add(interpretation);
			} else {
				long[] impact = new long[arity];
				for (int i = 0; i < arity; i++) {
					impact[i] = random.nextInt();
				}
				impactValues.put(interpretation, impact);
			}
		}
	}

	protected void initializeWithIndividuals(ObjectCodeImpl previous) {
		for (var entry : individualHashValues.keyValuesView()) {
			previous.set(entry.getOne(), entry.getTwo());
		}
	}

	protected long getTupleHash1(Tuple tuple, Object value, ObjectCode objectCodeImpl) {
		long result = Objects.hashCode(value);
		result = result * PRIME + objectCodeImpl.get(tuple.get(0));
		return result;
	}

	protected long getTupleHash2(Tuple tuple, Object value, ObjectCode objectCodeImpl) {
		long result = Objects.hashCode(value);
		result = result * PRIME + objectCodeImpl.get(tuple.get(0));
		result = result * PRIME + objectCodeImpl.get(tuple.get(1));
		if (tuple.get(0) == tuple.get(1)) {
			result += PRIME;
			result *= PRIME;
		}
		return result;
	}

	protected long getTupleHashN(Tuple tuple, Object value, ObjectCode objectCodeImpl) {
		long result = Objects.hashCode(value);
		for (int i = 0; i < tuple.getSize(); i++) {
			result = result * PRIME + objectCodeImpl.get(tuple.get(i));
		}
		return result;
	}

	protected void addHash(ObjectCodeImpl objectCodeImpl, int o, long impact, long tupleHash) {
		long x = tupleHash * impact;
		objectCodeImpl.set(o, objectCodeImpl.get(o) + x);
	}

	protected long calculateModelCode(long lastSum) {
		long result = 0;
		for (var nullImpactValue : nullImpactValues) {
			result = result * PRIME + Objects.hashCode(((Interpretation<?>) nullImpactValue).get(Tuple0.INSTANCE));
		}
		result += lastSum;
		return result;
	}
}