aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store
diff options
context:
space:
mode:
authorLibravatar Oszkár Semeráth <semerath@mit.bme.hu>2023-08-08 19:42:50 +0200
committerLibravatar GitHub <noreply@github.com>2023-08-08 19:42:50 +0200
commitfbc593d07a31bcc4aaedc345ee0eb9f860ffc806 (patch)
tree13ca537dd08067933cb5d9cdcf95cd845f5df205 /subprojects/store
parentMerge pull request #34 from OszkarSemerath/datastructure (diff)
parentObjectCodeImpl.effectiveSize introduced to correctly handle models with diffe... (diff)
downloadrefinery-fbc593d07a31bcc4aaedc345ee0eb9f860ffc806.tar.gz
refinery-fbc593d07a31bcc4aaedc345ee0eb9f860ffc806.tar.zst
refinery-fbc593d07a31bcc4aaedc345ee0eb9f860ffc806.zip
Merge pull request #35 from OszkarSemerath/datastructure
New tests and improvements for state coding
Diffstat (limited to 'subprojects/store')
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculatorFactory.java15
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderBuilder.java16
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/StateEquivalenceChecker.java2
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderAdapterImpl.java12
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderBuilderImpl.java35
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java29
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java93
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/CollectionNeighbourhoodCalculator.java131
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculator.java115
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java174
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/ObjectCodeImpl.java39
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/statecoding/stateequivalence/StateEquivalenceCheckerImpl.java51
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java178
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java189
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java109
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java195
16 files changed, 958 insertions, 425 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculatorFactory.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculatorFactory.java
new file mode 100644
index 00000000..04e17a13
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculatorFactory.java
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.statecoding;
7
8import org.eclipse.collections.api.set.primitive.IntSet;
9import tools.refinery.store.model.Interpretation;
10
11import java.util.List;
12
13public interface StateCodeCalculatorFactory {
14 StateCodeCalculator create(List<? extends Interpretation<?>> interpretations, IntSet individuals);
15}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderBuilder.java
index 2f37584f..54650825 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderBuilder.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderBuilder.java
@@ -8,7 +8,9 @@ package tools.refinery.store.statecoding;
8import tools.refinery.store.adapter.ModelAdapterBuilder; 8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.store.model.ModelStore; 9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.representation.AnySymbol; 10import tools.refinery.store.representation.AnySymbol;
11import tools.refinery.store.tuple.Tuple1;
11 12
13import java.util.Arrays;
12import java.util.Collection; 14import java.util.Collection;
13import java.util.List; 15import java.util.List;
14 16
@@ -24,6 +26,20 @@ public interface StateCoderBuilder extends ModelAdapterBuilder {
24 return excludeAll(List.of(symbols)); 26 return excludeAll(List.of(symbols));
25 } 27 }
26 28
29 StateCoderBuilder individual(Tuple1 tuple);
30 default StateCoderBuilder individual(Collection<Tuple1> tuple1s) {
31 for(Tuple1 tuple : tuple1s){
32 individual(tuple);
33 }
34 return this;
35 }
36 default StateCoderBuilder individuals(Tuple1... tuple1s) {
37 return individual(Arrays.stream(tuple1s).toList());
38 }
39
40 StateCoderBuilder stateCodeCalculatorFactory(StateCodeCalculatorFactory codeCalculatorFactory);
41 StateCoderBuilder stateEquivalenceChecker(StateEquivalenceChecker stateEquivalenceChecker);
42
27 @Override 43 @Override
28 StateCoderStoreAdapter build(ModelStore store); 44 StateCoderStoreAdapter build(ModelStore store);
29} 45}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateEquivalenceChecker.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateEquivalenceChecker.java
index 6d8dc6c7..3fd8c8d8 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateEquivalenceChecker.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateEquivalenceChecker.java
@@ -5,6 +5,7 @@
5 */ 5 */
6package tools.refinery.store.statecoding; 6package tools.refinery.store.statecoding;
7 7
8import org.eclipse.collections.api.set.primitive.IntSet;
8import tools.refinery.store.model.Interpretation; 9import tools.refinery.store.model.Interpretation;
9 10
10import java.util.List; 11import java.util.List;
@@ -15,6 +16,7 @@ public interface StateEquivalenceChecker {
15 } 16 }
16 17
17 EquivalenceResult constructMorphism( 18 EquivalenceResult constructMorphism(
19 IntSet individuals,
18 List<? extends Interpretation<?>> interpretations1, 20 List<? extends Interpretation<?>> interpretations1,
19 ObjectCode code1, List<? 21 ObjectCode code1, List<?
20 extends Interpretation<?>> interpretations2, 22 extends Interpretation<?>> interpretations2,
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderAdapterImpl.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderAdapterImpl.java
index b66fc86d..a2471916 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderAdapterImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderAdapterImpl.java
@@ -6,28 +6,20 @@
6package tools.refinery.store.statecoding.internal; 6package tools.refinery.store.statecoding.internal;
7 7
8import tools.refinery.store.adapter.ModelStoreAdapter; 8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.store.model.Interpretation;
10import tools.refinery.store.model.Model; 9import tools.refinery.store.model.Model;
11import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.statecoding.StateCodeCalculator; 10import tools.refinery.store.statecoding.StateCodeCalculator;
13import tools.refinery.store.statecoding.StateCoderAdapter; 11import tools.refinery.store.statecoding.StateCoderAdapter;
14import tools.refinery.store.statecoding.StateCoderResult; 12import tools.refinery.store.statecoding.StateCoderResult;
15import tools.refinery.store.statecoding.neighbourhood.LazyNeighbourhoodCalculator;
16
17import java.util.Collection;
18import java.util.List;
19 13
20public class StateCoderAdapterImpl implements StateCoderAdapter { 14public class StateCoderAdapterImpl implements StateCoderAdapter {
21 final ModelStoreAdapter storeAdapter; 15 final ModelStoreAdapter storeAdapter;
22 final Model model; 16 final Model model;
23 final StateCodeCalculator calculator; 17 final StateCodeCalculator calculator;
24 18
25 StateCoderAdapterImpl(ModelStoreAdapter storeAdapter, Model model, Collection<Symbol<?>> symbols) { 19 StateCoderAdapterImpl(ModelStoreAdapter storeAdapter, StateCodeCalculator calculator, Model model) {
26 this.storeAdapter = storeAdapter; 20 this.storeAdapter = storeAdapter;
27 this.model = model; 21 this.model = model;
28 22 this.calculator = calculator;
29 List<? extends Interpretation<?>> interpretations = symbols.stream().map(model::getInterpretation).toList();
30 calculator = new LazyNeighbourhoodCalculator(interpretations);
31 } 23 }
32 24
33 @Override 25 @Override
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderBuilderImpl.java
index 700723f4..05b47c52 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderBuilderImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderBuilderImpl.java
@@ -5,19 +5,24 @@
5 */ 5 */
6package tools.refinery.store.statecoding.internal; 6package tools.refinery.store.statecoding.internal;
7 7
8import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet;
8import tools.refinery.store.model.ModelStore; 9import tools.refinery.store.model.ModelStore;
9import tools.refinery.store.model.ModelStoreBuilder; 10import tools.refinery.store.model.ModelStoreBuilder;
10import tools.refinery.store.representation.AnySymbol; 11import tools.refinery.store.representation.AnySymbol;
11import tools.refinery.store.representation.Symbol; 12import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.statecoding.StateCoderBuilder; 13import tools.refinery.store.statecoding.*;
13import tools.refinery.store.statecoding.StateCoderStoreAdapter; 14import tools.refinery.store.statecoding.neighbourhood.NeighbourhoodCalculator;
15import tools.refinery.store.statecoding.stateequivalence.StateEquivalenceCheckerImpl;
16import tools.refinery.store.tuple.Tuple1;
14 17
15import java.util.HashSet; 18import java.util.*;
16import java.util.LinkedHashSet;
17import java.util.Set;
18 19
19public class StateCoderBuilderImpl implements StateCoderBuilder { 20public class StateCoderBuilderImpl implements StateCoderBuilder {
20 Set<AnySymbol> excluded = new HashSet<>(); 21 Set<AnySymbol> excluded = new HashSet<>();
22 IntHashSet individuals = new IntHashSet();
23
24 StateCodeCalculatorFactory calculator = NeighbourhoodCalculator::new;
25 StateEquivalenceChecker checker = new StateEquivalenceCheckerImpl();
21 26
22 @Override 27 @Override
23 public StateCoderBuilder exclude(AnySymbol symbol) { 28 public StateCoderBuilder exclude(AnySymbol symbol) {
@@ -26,6 +31,24 @@ public class StateCoderBuilderImpl implements StateCoderBuilder {
26 } 31 }
27 32
28 @Override 33 @Override
34 public StateCoderBuilder individual(Tuple1 tuple) {
35 individuals.add(tuple.get(0));
36 return this;
37 }
38
39 @Override
40 public StateCoderBuilder stateEquivalenceChecker(StateEquivalenceChecker stateEquivalenceChecker) {
41 this.checker = stateEquivalenceChecker;
42 return this;
43 }
44
45 @Override
46 public StateCoderBuilder stateCodeCalculatorFactory(StateCodeCalculatorFactory codeCalculatorFactory) {
47 this.calculator = codeCalculatorFactory;
48 return this;
49 }
50
51 @Override
29 public boolean isConfigured() { 52 public boolean isConfigured() {
30 return true; 53 return true;
31 } 54 }
@@ -43,6 +66,6 @@ public class StateCoderBuilderImpl implements StateCoderBuilder {
43 symbols.add(typed); 66 symbols.add(typed);
44 } 67 }
45 } 68 }
46 return new StateCoderStoreAdapterImpl(store, symbols); 69 return new StateCoderStoreAdapterImpl(store, calculator, checker, symbols, individuals);
47 } 70 }
48} 71}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java
index 5374755d..89586bfb 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java
@@ -5,14 +5,15 @@
5 */ 5 */
6package tools.refinery.store.statecoding.internal; 6package tools.refinery.store.statecoding.internal;
7 7
8import org.eclipse.collections.api.set.primitive.IntSet;
8import tools.refinery.store.map.Version; 9import tools.refinery.store.map.Version;
9import tools.refinery.store.model.Model; 10import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelStore; 11import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.representation.Symbol; 12import tools.refinery.store.representation.Symbol;
13import tools.refinery.store.statecoding.StateCodeCalculatorFactory;
12import tools.refinery.store.statecoding.StateCoderAdapter; 14import tools.refinery.store.statecoding.StateCoderAdapter;
13import tools.refinery.store.statecoding.StateCoderStoreAdapter; 15import tools.refinery.store.statecoding.StateCoderStoreAdapter;
14import tools.refinery.store.statecoding.StateEquivalenceChecker; 16import tools.refinery.store.statecoding.StateEquivalenceChecker;
15import tools.refinery.store.statecoding.stateequivalence.StateEquivalenceCheckerImpl;
16 17
17import java.util.Collection; 18import java.util.Collection;
18import java.util.Objects; 19import java.util.Objects;
@@ -20,12 +21,22 @@ import java.util.Objects;
20public class StateCoderStoreAdapterImpl implements StateCoderStoreAdapter { 21public class StateCoderStoreAdapterImpl implements StateCoderStoreAdapter {
21 final ModelStore store; 22 final ModelStore store;
22 final Collection<Symbol<?>> symbols; 23 final Collection<Symbol<?>> symbols;
24 final IntSet individuals;
23 25
24 final StateEquivalenceChecker equivalenceChecker = new StateEquivalenceCheckerImpl(); 26 final StateEquivalenceChecker equivalenceChecker;
27 final StateCodeCalculatorFactory codeCalculatorFactory;
25 28
26 StateCoderStoreAdapterImpl(ModelStore store, Collection<Symbol<?>> symbols) { 29 StateCoderStoreAdapterImpl(ModelStore store,
30 StateCodeCalculatorFactory codeCalculatorFactory,
31 StateEquivalenceChecker equivalenceChecker,
32 Collection<Symbol<?>> symbols,
33 IntSet individuals)
34 {
35 this.codeCalculatorFactory = codeCalculatorFactory;
36 this.equivalenceChecker = equivalenceChecker;
27 this.store = store; 37 this.store = store;
28 this.symbols = symbols; 38 this.symbols = symbols;
39 this.individuals = individuals;
29 } 40 }
30 41
31 @Override 42 @Override
@@ -35,7 +46,7 @@ public class StateCoderStoreAdapterImpl implements StateCoderStoreAdapter {
35 46
36 @Override 47 @Override
37 public StateEquivalenceChecker.EquivalenceResult checkEquivalence(Version v1, Version v2) { 48 public StateEquivalenceChecker.EquivalenceResult checkEquivalence(Version v1, Version v2) {
38 if(Objects.equals(v1,v2)) { 49 if (Objects.equals(v1, v2)) {
39 return StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC; 50 return StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC;
40 } 51 }
41 var model1 = this.getStore().createModelForState(v1); 52 var model1 = this.getStore().createModelForState(v1);
@@ -44,20 +55,20 @@ public class StateCoderStoreAdapterImpl implements StateCoderStoreAdapter {
44 var s1 = model1.getAdapter(StateCoderAdapter.class).calculateStateCode(); 55 var s1 = model1.getAdapter(StateCoderAdapter.class).calculateStateCode();
45 var s2 = model2.getAdapter(StateCoderAdapter.class).calculateStateCode(); 56 var s2 = model2.getAdapter(StateCoderAdapter.class).calculateStateCode();
46 57
47 if(s1.modelCode() != s2.modelCode()) { 58 if (s1.modelCode() != s2.modelCode()) {
48 return StateEquivalenceChecker.EquivalenceResult.DIFFERENT; 59 return StateEquivalenceChecker.EquivalenceResult.DIFFERENT;
49 } 60 }
50 61
51 var i1 = symbols.stream().map(model1::getInterpretation).toList(); 62 var i1 = symbols.stream().map(model1::getInterpretation).toList();
52 var i2 = symbols.stream().map(model2::getInterpretation).toList(); 63 var i2 = symbols.stream().map(model2::getInterpretation).toList();
53 64
54 return equivalenceChecker.constructMorphism(i1,s1.objectCode(),i2,s2.objectCode()); 65 return equivalenceChecker.constructMorphism(individuals, i1, s1.objectCode(), i2, s2.objectCode());
55 } 66 }
56 67
57 @Override 68 @Override
58 public StateCoderAdapter createModelAdapter(Model model) { 69 public StateCoderAdapter createModelAdapter(Model model) {
59 return new StateCoderAdapterImpl(this,model,symbols); 70 var interpretations = symbols.stream().map(model::getInterpretation).toList();
71 var coder = codeCalculatorFactory.create(interpretations, individuals);
72 return new StateCoderAdapterImpl(this, coder, model);
60 } 73 }
61
62
63} 74}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java
new file mode 100644
index 00000000..8fcf24b1
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java
@@ -0,0 +1,93 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.statecoding.neighbourhood;
7
8import org.eclipse.collections.api.set.primitive.IntSet;
9import org.eclipse.collections.impl.map.mutable.primitive.IntLongHashMap;
10import tools.refinery.store.model.Interpretation;
11import tools.refinery.store.statecoding.ObjectCode;
12import tools.refinery.store.tuple.Tuple;
13import tools.refinery.store.tuple.Tuple0;
14
15import java.util.*;
16
17public abstract class AbstractNeighbourhoodCalculator {
18 protected final List<Interpretation<?>> nullImpactValues;
19 protected final LinkedHashMap<Interpretation<?>, long[]> impactValues;
20 protected final IntLongHashMap individualHashValues;
21
22 protected static final long PRIME = 31;
23
24 protected AbstractNeighbourhoodCalculator(List<? extends Interpretation<?>> interpretations, IntSet individuals) {
25 this.nullImpactValues = new ArrayList<>();
26 this.impactValues = new LinkedHashMap<>();
27 Random random = new Random(1);
28
29 individualHashValues = new IntLongHashMap();
30 var individualsInOrder = individuals.toSortedList(Integer::compare);
31 for(int i = 0; i<individualsInOrder.size(); i++) {
32 individualHashValues.put(individualsInOrder.get(i), random.nextLong());
33 }
34
35 for (Interpretation<?> interpretation : interpretations) {
36 int arity = interpretation.getSymbol().arity();
37 if (arity == 0) {
38 nullImpactValues.add(interpretation);
39 } else {
40 long[] impact = new long[arity];
41 for (int i = 0; i < arity; i++) {
42 impact[i] = random.nextInt();
43 }
44 impactValues.put(interpretation, impact);
45 }
46 }
47 }
48
49 protected void initializeWithIndividuals(ObjectCodeImpl previous) {
50 for (var entry : individualHashValues.keyValuesView()) {
51 previous.set(entry.getOne(), entry.getTwo());
52 }
53 }
54
55 protected long getTupleHash1(Tuple tuple, Object value, ObjectCode objectCodeImpl) {
56 long result = Objects.hashCode(value);
57 result = result * PRIME + objectCodeImpl.get(tuple.get(0));
58 return result;
59 }
60
61 protected long getTupleHash2(Tuple tuple, Object value, ObjectCode objectCodeImpl) {
62 long result = Objects.hashCode(value);
63 result = result * PRIME + objectCodeImpl.get(tuple.get(0));
64 result = result * PRIME + objectCodeImpl.get(tuple.get(1));
65 if (tuple.get(0) == tuple.get(1)) {
66 result += PRIME;
67 result *= PRIME;
68 }
69 return result;
70 }
71
72 protected long getTupleHashN(Tuple tuple, Object value, ObjectCode objectCodeImpl) {
73 long result = Objects.hashCode(value);
74 for (int i = 0; i < tuple.getSize(); i++) {
75 result = result * PRIME + objectCodeImpl.get(tuple.get(i));
76 }
77 return result;
78 }
79
80 protected void addHash(ObjectCodeImpl objectCodeImpl, int o, long impact, long tupleHash) {
81 long x = tupleHash * impact;
82 objectCodeImpl.set(o, objectCodeImpl.get(o) + x);
83 }
84
85 protected long calculateModelCode(long lastSum) {
86 long result = 0;
87 for (var nullImpactValue : nullImpactValues) {
88 result = result * PRIME + Objects.hashCode(nullImpactValue.get(Tuple0.INSTANCE));
89 }
90 result += lastSum;
91 return result;
92 }
93}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/CollectionNeighbourhoodCalculator.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/CollectionNeighbourhoodCalculator.java
deleted file mode 100644
index 058750ee..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/CollectionNeighbourhoodCalculator.java
+++ /dev/null
@@ -1,131 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.statecoding.neighbourhood;
7
8import org.eclipse.collections.api.set.primitive.MutableLongSet;
9import org.eclipse.collections.impl.set.mutable.primitive.LongHashSet;
10import tools.refinery.store.model.Interpretation;
11import tools.refinery.store.statecoding.StateCodeCalculator;
12import tools.refinery.store.statecoding.StateCoderResult;
13import tools.refinery.store.tuple.Tuple;
14import tools.refinery.store.tuple.Tuple0;
15
16import java.util.ArrayList;
17import java.util.LinkedHashMap;
18import java.util.List;
19import java.util.Random;
20
21public class CollectionNeighbourhoodCalculator implements StateCodeCalculator {
22 protected final List<Interpretation<?>> nullImpactValues;
23 protected final LinkedHashMap<Interpretation<?>, long[]> impactValues;
24
25 public CollectionNeighbourhoodCalculator(List<? extends Interpretation<?>> interpretations) {
26 this.nullImpactValues = new ArrayList<>();
27 this.impactValues = new LinkedHashMap<>();
28 Random random = new Random(1);
29
30 for (Interpretation<?> interpretation : interpretations) {
31 int arity = interpretation.getSymbol().arity();
32 if (arity == 0) {
33 nullImpactValues.add(interpretation);
34 } else {
35 long[] impact = new long[arity];
36 for (int i = 0; i < arity; i++) {
37 impact[i] = random.nextLong();
38 }
39 impactValues.put(interpretation, impact);
40 }
41 }
42 }
43
44 @Override
45 public StateCoderResult calculateCodes() {
46 ObjectCodeImpl previous = new ObjectCodeImpl();
47 ObjectCodeImpl next = new ObjectCodeImpl();
48
49 int previousSize = 1;
50 long lastSum;
51 boolean grows;
52
53 do{
54 for (var impactValueEntry : this.impactValues.entrySet()) {
55 Interpretation<?> interpretation = impactValueEntry.getKey();
56 long[] impact = impactValueEntry.getValue();
57 var cursor = interpretation.getAll();
58 while (cursor.move()) {
59 Tuple tuple = cursor.getKey();
60 Object value = cursor.getValue();
61 long tupleHash = getTupleHash(tuple, value, previous);
62 addHash(next, tuple, impact, tupleHash);
63 }
64 }
65
66 previous = next;
67 next = null;
68 lastSum = 0;
69 MutableLongSet codes = new LongHashSet();
70 for (int i = 0; i < previous.getSize(); i++) {
71 long objectHash = previous.get(i);
72 codes.add(objectHash);
73
74 final long shifted1 = objectHash>>> 32;
75 final long shifted2 = objectHash << 32;
76 lastSum += shifted1 + shifted2;
77 }
78 int nextSize = codes.size();
79 grows = previousSize < nextSize;
80 previousSize = nextSize;
81
82 if(grows) {
83 next = new ObjectCodeImpl(previous);
84 }
85 } while (grows);
86
87 long result = 1;
88 for (var nullImpactValue : nullImpactValues) {
89 result = result * 31 + nullImpactValue.get(Tuple0.INSTANCE).hashCode();
90 }
91 result += lastSum;
92
93 return new StateCoderResult((int) result, previous);
94 }
95
96 protected long getTupleHash(Tuple tuple, Object value, ObjectCodeImpl objectCodeImpl) {
97 long result = value.hashCode();
98 int arity = tuple.getSize();
99 if (arity == 1) {
100 result = result * 31 + objectCodeImpl.get(tuple.get(0));
101 } else if (arity == 2) {
102 result = result * 31 + objectCodeImpl.get(tuple.get(0));
103 result = result * 31 + objectCodeImpl.get(tuple.get(1));
104 if (tuple.get(0) == tuple.get(1)) {
105 result++;
106 }
107 } else if (arity > 2) {
108 for (int i = 0; i < arity; i++) {
109 result = result * 31 + objectCodeImpl.get(tuple.get(i));
110 }
111 }
112 return result;
113 }
114
115 protected void addHash(ObjectCodeImpl objectCodeImpl, Tuple tuple, long[] impact, long tupleHashCode) {
116 if (tuple.getSize() == 1) {
117 addHash(objectCodeImpl, tuple.get(0), impact[0], tupleHashCode);
118 } else if (tuple.getSize() == 2) {
119 addHash(objectCodeImpl, tuple.get(0), impact[0], tupleHashCode);
120 addHash(objectCodeImpl, tuple.get(1), impact[1], tupleHashCode);
121 } else if (tuple.getSize() > 2) {
122 for (int i = 0; i < tuple.getSize(); i++) {
123 addHash(objectCodeImpl, tuple.get(i), impact[i], tupleHashCode);
124 }
125 }
126 }
127
128 protected void addHash(ObjectCodeImpl objectCodeImpl, int o, long impact, long tupleHash) {
129 objectCodeImpl.set(o, objectCodeImpl.get(o) + tupleHash * impact);
130 }
131}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculator.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculator.java
index 79317679..2ffbef5e 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculator.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculator.java
@@ -6,76 +6,57 @@
6package tools.refinery.store.statecoding.neighbourhood; 6package tools.refinery.store.statecoding.neighbourhood;
7 7
8import org.eclipse.collections.api.map.primitive.LongIntMap; 8import org.eclipse.collections.api.map.primitive.LongIntMap;
9import org.eclipse.collections.api.set.primitive.IntSet;
9import org.eclipse.collections.impl.map.mutable.primitive.LongIntHashMap; 10import org.eclipse.collections.impl.map.mutable.primitive.LongIntHashMap;
10import tools.refinery.store.map.Cursor; 11import tools.refinery.store.map.Cursor;
11import tools.refinery.store.model.Interpretation; 12import tools.refinery.store.model.Interpretation;
12import tools.refinery.store.statecoding.StateCodeCalculator; 13import tools.refinery.store.statecoding.StateCodeCalculator;
13import tools.refinery.store.statecoding.StateCoderResult; 14import tools.refinery.store.statecoding.StateCoderResult;
14import tools.refinery.store.tuple.Tuple; 15import tools.refinery.store.tuple.Tuple;
15import tools.refinery.store.tuple.Tuple0;
16 16
17import java.util.ArrayList;
18import java.util.LinkedHashMap;
19import java.util.List; 17import java.util.List;
20import java.util.Random;
21 18
22public class LazyNeighbourhoodCalculator implements StateCodeCalculator { 19public class LazyNeighbourhoodCalculator extends AbstractNeighbourhoodCalculator implements StateCodeCalculator {
23 protected final List<Interpretation<?>> nullImpactValues; 20 public LazyNeighbourhoodCalculator(List<? extends Interpretation<?>> interpretations, IntSet individuals) {
24 protected final LinkedHashMap<Interpretation<?>, long[]> impactValues; 21 super(interpretations, individuals);
25
26 public LazyNeighbourhoodCalculator(List<? extends Interpretation<?>> interpretations) {
27 this.nullImpactValues = new ArrayList<>();
28 this.impactValues = new LinkedHashMap<>();
29 Random random = new Random(1);
30
31 for (Interpretation<?> interpretation : interpretations) {
32 int arity = interpretation.getSymbol().arity();
33 if (arity == 0) {
34 nullImpactValues.add(interpretation);
35 } else {
36 long[] impact = new long[arity];
37 for (int i = 0; i < arity; i++) {
38 impact[i] = random.nextInt();
39 }
40 impactValues.put(interpretation, impact);
41 }
42 }
43 } 22 }
44 23
45 public StateCoderResult calculateCodes() { 24 public StateCoderResult calculateCodes() {
46 ObjectCodeImpl previous = new ObjectCodeImpl(); 25 ObjectCodeImpl previousObjectCode = new ObjectCodeImpl();
47 ObjectCodeImpl next = new ObjectCodeImpl(); 26 LongIntHashMap prevHash2Amount = new LongIntHashMap();
48 LongIntMap hash2Amount = new LongIntHashMap();
49 27
50 long lastSum; 28 long lastSum;
29 // All hash code is 0, except to the individuals.
51 int lastSize = 1; 30 int lastSize = 1;
52 boolean grows; 31 boolean first = true;
53 32
33 boolean grows;
34 int rounds = 0;
54 do { 35 do {
55 constructNextObjectCodes(previous, next, hash2Amount); 36 final ObjectCodeImpl nextObjectCode;
37 if (first) {
38 nextObjectCode = new ObjectCodeImpl();
39 initializeWithIndividuals(nextObjectCode);
40 } else {
41 nextObjectCode = new ObjectCodeImpl(previousObjectCode);
42 }
43 constructNextObjectCodes(previousObjectCode, nextObjectCode, prevHash2Amount);
56 44
57 LongIntHashMap nextHash2Amount = new LongIntHashMap(); 45 LongIntHashMap nextHash2Amount = new LongIntHashMap();
58 lastSum = calculateLastSum(previous, next, hash2Amount, nextHash2Amount); 46 lastSum = calculateLastSum(previousObjectCode, nextObjectCode, prevHash2Amount, nextHash2Amount);
59
60 previous = next;
61 next = null;
62 47
63 int nextSize = nextHash2Amount.size(); 48 int nextSize = nextHash2Amount.size();
64 grows = nextSize > lastSize; 49 grows = nextSize > lastSize;
65 lastSize = nextSize; 50 lastSize = nextSize;
51 first = false;
66 52
67 if (grows) { 53 previousObjectCode = nextObjectCode;
68 next = new ObjectCodeImpl(previous); 54 prevHash2Amount = nextHash2Amount;
69 } 55 } while (grows && rounds++ < 4/*&& lastSize < previousObjectCode.getSize()*/);
70 } while (grows);
71 56
72 long result = 1; 57 long result = calculateModelCode(lastSum);
73 for (var nullImpactValue : nullImpactValues) {
74 result = result * 31 + nullImpactValue.get(Tuple0.INSTANCE).hashCode();
75 }
76 result += lastSum;
77 58
78 return new StateCoderResult((int) result, previous); 59 return new StateCoderResult((int) result, previousObjectCode);
79 } 60 }
80 61
81 private long calculateLastSum(ObjectCodeImpl previous, ObjectCodeImpl next, LongIntMap hash2Amount, 62 private long calculateLastSum(ObjectCodeImpl previous, ObjectCodeImpl next, LongIntMap hash2Amount,
@@ -96,7 +77,7 @@ public class LazyNeighbourhoodCalculator implements StateCodeCalculator {
96 final long shifted1 = hash >>> 8; 77 final long shifted1 = hash >>> 8;
97 final long shifted2 = hash << 8; 78 final long shifted2 = hash << 8;
98 final long shifted3 = hash >> 2; 79 final long shifted3 = hash >> 2;
99 lastSum += shifted1*shifted3 + shifted2; 80 lastSum += shifted1 * shifted3 + shifted2;
100 } 81 }
101 return lastSum; 82 return lastSum;
102 } 83 }
@@ -126,7 +107,7 @@ public class LazyNeighbourhoodCalculator implements StateCodeCalculator {
126 107
127 private boolean isUnique(LongIntMap hash2Amount, ObjectCodeImpl objectCodeImpl, int object) { 108 private boolean isUnique(LongIntMap hash2Amount, ObjectCodeImpl objectCodeImpl, int object) {
128 final long hash = objectCodeImpl.get(object); 109 final long hash = objectCodeImpl.get(object);
129 if(hash == 0) { 110 if (hash == 0) {
130 return false; 111 return false;
131 } 112 }
132 final int amount = hash2Amount.get(hash); 113 final int amount = hash2Amount.get(hash);
@@ -149,12 +130,12 @@ public class LazyNeighbourhoodCalculator implements StateCodeCalculator {
149 } 130 }
150 131
151 private void lazyImpactCalculation2(LongIntMap hash2Amount, ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) { 132 private void lazyImpactCalculation2(LongIntMap hash2Amount, ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) {
152 Tuple tuple = cursor.getKey(); 133 final Tuple tuple = cursor.getKey();
153 int o1 = tuple.get(0); 134 final int o1 = tuple.get(0);
154 int o2 = tuple.get(1); 135 final int o2 = tuple.get(1);
155 136
156 boolean u1 = isUnique(hash2Amount, previous, o1); 137 final boolean u1 = isUnique(hash2Amount, previous, o1);
157 boolean u2 = isUnique(hash2Amount, previous, o2); 138 final boolean u2 = isUnique(hash2Amount, previous, o2);
158 139
159 if (u1 && u2) { 140 if (u1 && u2) {
160 next.ensureSize(o1); 141 next.ensureSize(o1);
@@ -175,9 +156,9 @@ public class LazyNeighbourhoodCalculator implements StateCodeCalculator {
175 } 156 }
176 157
177 private void lazyImpactCalculationN(LongIntMap hash2Amount, ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) { 158 private void lazyImpactCalculationN(LongIntMap hash2Amount, ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) {
178 Tuple tuple = cursor.getKey(); 159 final Tuple tuple = cursor.getKey();
179 160
180 boolean[] uniques = new boolean[tuple.getSize()]; 161 final boolean[] uniques = new boolean[tuple.getSize()];
181 boolean allUnique = true; 162 boolean allUnique = true;
182 for (int i = 0; i < tuple.getSize(); i++) { 163 for (int i = 0; i < tuple.getSize(); i++) {
183 final boolean isUnique = isUnique(hash2Amount, previous, tuple.get(i)); 164 final boolean isUnique = isUnique(hash2Amount, previous, tuple.get(i));
@@ -204,32 +185,4 @@ public class LazyNeighbourhoodCalculator implements StateCodeCalculator {
204 } 185 }
205 } 186 }
206 187
207 private long getTupleHash1(Tuple tuple, Object value, ObjectCodeImpl objectCodeImpl) {
208 long result = value.hashCode();
209 result = result * 31 + objectCodeImpl.get(tuple.get(0));
210 return result;
211 }
212
213 private long getTupleHash2(Tuple tuple, Object value, ObjectCodeImpl objectCodeImpl) {
214 long result = value.hashCode();
215 result = result * 31 + objectCodeImpl.get(tuple.get(0));
216 result = result * 31 + objectCodeImpl.get(tuple.get(1));
217 if (tuple.get(0) == tuple.get(1)) {
218 result*=31;
219 }
220 return result;
221 }
222
223 private long getTupleHashN(Tuple tuple, Object value, ObjectCodeImpl objectCodeImpl) {
224 long result = value.hashCode();
225 for (int i = 0; i < tuple.getSize(); i++) {
226 result = result * 31 + objectCodeImpl.get(tuple.get(i));
227 }
228 return result;
229 }
230
231 protected void addHash(ObjectCodeImpl objectCodeImpl, int o, long impact, long tupleHash) {
232 long x = tupleHash * impact;
233 objectCodeImpl.set(o, objectCodeImpl.get(o) + x);
234 }
235} 188}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java
index 212291c3..5b3e5ea3 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java
@@ -5,128 +5,108 @@
5 */ 5 */
6package tools.refinery.store.statecoding.neighbourhood; 6package tools.refinery.store.statecoding.neighbourhood;
7 7
8import org.eclipse.collections.api.set.primitive.MutableLongSet; 8import org.eclipse.collections.api.set.primitive.IntSet;
9import org.eclipse.collections.impl.set.mutable.primitive.LongHashSet; 9import tools.refinery.store.map.Cursor;
10import tools.refinery.store.model.Interpretation; 10import tools.refinery.store.model.Interpretation;
11import tools.refinery.store.statecoding.ObjectCode;
11import tools.refinery.store.statecoding.StateCodeCalculator; 12import tools.refinery.store.statecoding.StateCodeCalculator;
12import tools.refinery.store.statecoding.StateCoderResult; 13import tools.refinery.store.statecoding.StateCoderResult;
13import tools.refinery.store.tuple.Tuple; 14import tools.refinery.store.tuple.Tuple;
14import tools.refinery.store.tuple.Tuple0; 15import tools.refinery.store.tuple.Tuple0;
15 16
16import java.util.ArrayList;
17import java.util.LinkedHashMap;
18import java.util.List; 17import java.util.List;
19import java.util.Random; 18import java.util.Objects;
20 19
21public class NeighbourhoodCalculator implements StateCodeCalculator { 20public class NeighbourhoodCalculator extends AbstractNeighbourhoodCalculator implements StateCodeCalculator {
22 protected final List<Interpretation<?>> nullImpactValues; 21 public NeighbourhoodCalculator(List<? extends Interpretation<?>> interpretations, IntSet individuals) {
23 protected final LinkedHashMap<Interpretation<?>, long[]> impactValues; 22 super(interpretations, individuals);
24
25 public NeighbourhoodCalculator(List<? extends Interpretation<?>> interpretations) {
26 this.nullImpactValues = new ArrayList<>();
27 this.impactValues = new LinkedHashMap<>();
28 Random random = new Random(1);
29
30 for (Interpretation<?> interpretation : interpretations) {
31 int arity = interpretation.getSymbol().arity();
32 if (arity == 0) {
33 nullImpactValues.add(interpretation);
34 } else {
35 long[] impact = new long[arity];
36 for (int i = 0; i < arity; i++) {
37 impact[i] = random.nextLong();
38 }
39 impactValues.put(interpretation, impact);
40 }
41 }
42 } 23 }
43 24
44 @Override
45 public StateCoderResult calculateCodes() { 25 public StateCoderResult calculateCodes() {
46 ObjectCodeImpl previous = new ObjectCodeImpl(); 26 ObjectCodeImpl previousObjectCode = new ObjectCodeImpl();
47 ObjectCodeImpl next = new ObjectCodeImpl(); 27 initializeWithIndividuals(previousObjectCode);
48
49 int previousSize = 1;
50 long lastSum;
51 boolean grows;
52
53 do{
54 for (var impactValueEntry : this.impactValues.entrySet()) {
55 Interpretation<?> interpretation = impactValueEntry.getKey();
56 long[] impact = impactValueEntry.getValue();
57 var cursor = interpretation.getAll();
58 while (cursor.move()) {
59 Tuple tuple = cursor.getKey();
60 Object value = cursor.getValue();
61 long tupleHash = getTupleHash(tuple, value, previous);
62 addHash(next, tuple, impact, tupleHash);
63 }
64 }
65 28
66 previous = next; 29 int rounds = 0;
67 next = null; 30 do {
68 lastSum = 0; 31 final ObjectCodeImpl nextObjectCode = rounds == 0 ? new ObjectCodeImpl() :
69 MutableLongSet codes = new LongHashSet(); 32 new ObjectCodeImpl(previousObjectCode.getSize());
70 for (int i = 0; i < previous.getSize(); i++) {
71 long objectHash = previous.get(i);
72 codes.add(objectHash);
73
74 final long shifted1 = objectHash>>> 32;
75 final long shifted2 = objectHash << 32;
76 lastSum += shifted1 + shifted2;
77 }
78 int nextSize = codes.size();
79 grows = previousSize < nextSize;
80 previousSize = nextSize;
81 33
82 if(grows) { 34 constructNextObjectCodes(previousObjectCode, nextObjectCode);
83 next = new ObjectCodeImpl(previous); 35 previousObjectCode = nextObjectCode;
84 } 36 rounds++;
85 } while (grows); 37 } while (rounds <= 7 && rounds <= previousObjectCode.getEffectiveSize());
86 38
87 long result = 1; 39 long result = calculateLastSum(previousObjectCode);
40 return new StateCoderResult((int) result, previousObjectCode);
41 }
42
43 private long calculateLastSum(ObjectCode codes) {
44 long result = 0;
88 for (var nullImpactValue : nullImpactValues) { 45 for (var nullImpactValue : nullImpactValues) {
89 result = result * 31 + nullImpactValue.get(Tuple0.INSTANCE).hashCode(); 46 result = result * 31 + Objects.hashCode(nullImpactValue.get(Tuple0.INSTANCE));
90 } 47 }
91 result += lastSum;
92 48
93 return new StateCoderResult((int) result, previous); 49 for (int i = 0; i < codes.getSize(); i++) {
94 } 50 final long hash = codes.get(i);
95 51 result += hash*PRIME;
96 protected long getTupleHash(Tuple tuple, Object value, ObjectCodeImpl objectCodeImpl) {
97 long result = value.hashCode();
98 int arity = tuple.getSize();
99 if (arity == 1) {
100 result = result * 31 + objectCodeImpl.get(tuple.get(0));
101 } else if (arity == 2) {
102 result = result * 31 + objectCodeImpl.get(tuple.get(0));
103 result = result * 31 + objectCodeImpl.get(tuple.get(1));
104 if (tuple.get(0) == tuple.get(1)) {
105 result++;
106 }
107 } else if (arity > 2) {
108 for (int i = 0; i < arity; i++) {
109 result = result * 31 + objectCodeImpl.get(tuple.get(i));
110 }
111 } 52 }
53
112 return result; 54 return result;
113 } 55 }
114 56
115 protected void addHash(ObjectCodeImpl objectCodeImpl, Tuple tuple, long[] impact, long tupleHashCode) { 57 private void constructNextObjectCodes(ObjectCodeImpl previous, ObjectCodeImpl next) {
116 if (tuple.getSize() == 1) { 58 for (var impactValueEntry : this.impactValues.entrySet()) {
117 addHash(objectCodeImpl, tuple.get(0), impact[0], tupleHashCode); 59 Interpretation<?> interpretation = impactValueEntry.getKey();
118 } else if (tuple.getSize() == 2) { 60 var cursor = interpretation.getAll();
119 addHash(objectCodeImpl, tuple.get(0), impact[0], tupleHashCode); 61 int arity = interpretation.getSymbol().arity();
120 addHash(objectCodeImpl, tuple.get(1), impact[1], tupleHashCode); 62 long[] impactValue = impactValueEntry.getValue();
121 } else if (tuple.getSize() > 2) { 63
122 for (int i = 0; i < tuple.getSize(); i++) { 64 if (arity == 1) {
123 addHash(objectCodeImpl, tuple.get(i), impact[i], tupleHashCode); 65 while (cursor.move()) {
66 impactCalculation1(previous, next, impactValue, cursor);
67 }
68 } else if (arity == 2) {
69 while (cursor.move()) {
70 impactCalculation2(previous, next, impactValue, cursor);
71 }
72 } else {
73 while (cursor.move()) {
74 impactCalculationN(previous, next, impactValue, cursor);
75 }
124 } 76 }
125 } 77 }
126 } 78 }
127 79
128 protected void addHash(ObjectCodeImpl objectCodeImpl, int o, long impact, long tupleHash) { 80
129 objectCodeImpl.set(o, objectCodeImpl.get(o) + tupleHash * impact); 81 private void impactCalculation1(ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) {
82
83 Tuple tuple = cursor.getKey();
84 int o = tuple.get(0);
85 Object value = cursor.getValue();
86 long tupleHash = getTupleHash1(tuple, value, previous);
87 addHash(next, o, impactValues[0], tupleHash);
88 }
89
90 private void impactCalculation2(ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) {
91 final Tuple tuple = cursor.getKey();
92 final int o1 = tuple.get(0);
93 final int o2 = tuple.get(1);
94
95 Object value = cursor.getValue();
96 long tupleHash = getTupleHash2(tuple, value, previous);
97
98 addHash(next, o1, impactValues[0], tupleHash);
99 addHash(next, o2, impactValues[1], tupleHash);
130 } 100 }
131 101
102 private void impactCalculationN(ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) {
103 final Tuple tuple = cursor.getKey();
104
105 Object value = cursor.getValue();
106 long tupleHash = getTupleHashN(tuple, value, previous);
107
108 for (int i = 0; i < tuple.getSize(); i++) {
109 addHash(next, tuple.get(i), impactValues[i], tupleHash);
110 }
111 }
132} 112}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/ObjectCodeImpl.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/ObjectCodeImpl.java
index 08e3a90b..0cd7ff58 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/ObjectCodeImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/ObjectCodeImpl.java
@@ -12,26 +12,35 @@ import java.util.Arrays;
12public class ObjectCodeImpl implements ObjectCode { 12public class ObjectCodeImpl implements ObjectCode {
13 private long[] vector; 13 private long[] vector;
14 private int size; 14 private int size;
15 private int effectiveSize;
15 16
16 public ObjectCodeImpl() { 17 public ObjectCodeImpl() {
17 vector = new long[10]; 18 vector = new long[10];
18 size = 0; 19 size = 0;
20 effectiveSize = 0;
19 } 21 }
20 22
21 public ObjectCodeImpl(ObjectCodeImpl sameSize) { 23 public ObjectCodeImpl(int size) {
22 this.vector = new long[sameSize.size]; 24 this.vector = new long[size];
23 this.size = sameSize.size; 25 this.size = size;
26 effectiveSize = 0;
27 }
28
29 public ObjectCodeImpl(ObjectCodeImpl copy) {
30 this.vector = Arrays.copyOf(copy.vector, copy.size);
31 this.size = copy.size;
32 effectiveSize = copy.effectiveSize;
24 } 33 }
25 34
26 public void ensureSize(int object) { 35 public void ensureSize(int object) {
27 if(object >= size) { 36 if (object >= size) {
28 size = object+1; 37 size = object + 1;
29 } 38 }
30 39
31 if(object >= vector.length) { 40 if (object >= vector.length) {
32 int newLength = vector.length*2; 41 int newLength = vector.length * 2;
33 while(object >= newLength) { 42 while (object >= newLength) {
34 newLength*=2; 43 newLength *= 2;
35 } 44 }
36 45
37 long[] newVector = new long[newLength]; 46 long[] newVector = new long[newLength];
@@ -41,7 +50,7 @@ public class ObjectCodeImpl implements ObjectCode {
41 } 50 }
42 51
43 public long get(int object) { 52 public long get(int object) {
44 if(object < vector.length) { 53 if (object < vector.length) {
45 return vector[object]; 54 return vector[object];
46 } else { 55 } else {
47 return 0; 56 return 0;
@@ -50,17 +59,23 @@ public class ObjectCodeImpl implements ObjectCode {
50 59
51 public void set(int object, long value) { 60 public void set(int object, long value) {
52 ensureSize(object); 61 ensureSize(object);
53 vector[object]=value; 62 final long valueToPut = value == 0 ? 1 : value;
63 if (vector[object] == 0) effectiveSize++;
64 vector[object] = valueToPut;
54 } 65 }
55 66
56 public int getSize() { 67 public int getSize() {
57 return this.size; 68 return this.size;
58 } 69 }
59 70
71 public int getEffectiveSize() {
72 return this.effectiveSize;
73 }
74
60 @Override 75 @Override
61 public String toString() { 76 public String toString() {
62 return "ObjectCodeImpl{" + 77 return "ObjectCodeImpl{" +
63 "vector=" + Arrays.toString(Arrays.copyOf(vector,this.size)) + 78 "vector=" + Arrays.toString(Arrays.copyOf(vector, this.size)) +
64 '}'; 79 '}';
65 } 80 }
66} 81}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/stateequivalence/StateEquivalenceCheckerImpl.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/stateequivalence/StateEquivalenceCheckerImpl.java
index fd704086..34dba34e 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/stateequivalence/StateEquivalenceCheckerImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/stateequivalence/StateEquivalenceCheckerImpl.java
@@ -5,7 +5,9 @@
5 */ 5 */
6package tools.refinery.store.statecoding.stateequivalence; 6package tools.refinery.store.statecoding.stateequivalence;
7 7
8import org.eclipse.collections.api.factory.primitive.IntIntMaps;
8import org.eclipse.collections.api.map.primitive.IntIntMap; 9import org.eclipse.collections.api.map.primitive.IntIntMap;
10import org.eclipse.collections.api.set.primitive.IntSet;
9import org.eclipse.collections.impl.map.mutable.primitive.IntIntHashMap; 11import org.eclipse.collections.impl.map.mutable.primitive.IntIntHashMap;
10import org.eclipse.collections.impl.map.mutable.primitive.LongObjectHashMap; 12import org.eclipse.collections.impl.map.mutable.primitive.LongObjectHashMap;
11import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet; 13import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet;
@@ -23,18 +25,17 @@ public class StateEquivalenceCheckerImpl implements StateEquivalenceChecker {
23 public static final int LIMIT = 1000; 25 public static final int LIMIT = 1000;
24 26
25 @Override 27 @Override
26 public EquivalenceResult constructMorphism(List<? extends Interpretation<?>> interpretations1, 28 public EquivalenceResult constructMorphism(IntSet individuals,
29 List<? extends Interpretation<?>> interpretations1,
27 ObjectCode code1, 30 ObjectCode code1,
28 List<? extends Interpretation<?>> interpretations2, 31 List<? extends Interpretation<?>> interpretations2,
29 ObjectCode code2) { 32 ObjectCode code2)
30 if (code1.getSize() != code2.getSize()) { 33 {
31 return EquivalenceResult.DIFFERENT;
32 }
33
34 IntIntHashMap object2PermutationGroup = new IntIntHashMap(); 34 IntIntHashMap object2PermutationGroup = new IntIntHashMap();
35 List<List<IntIntMap>> permutationsGroups = new ArrayList<>(); 35 List<List<IntIntMap>> permutationsGroups = new ArrayList<>();
36 36
37 final EquivalenceResult permutations = constructPermutationNavigation(indexByHash(code1), indexByHash(code2), 37 final EquivalenceResult permutations = constructPermutationNavigation(individuals,
38 indexByHash(code1, individuals), indexByHash(code2, individuals),
38 object2PermutationGroup, permutationsGroups); 39 object2PermutationGroup, permutationsGroups);
39 40
40 if (permutations == EquivalenceResult.DIFFERENT) { 41 if (permutations == EquivalenceResult.DIFFERENT) {
@@ -60,24 +61,29 @@ public class StateEquivalenceCheckerImpl implements StateEquivalenceChecker {
60 return EquivalenceResult.DIFFERENT; 61 return EquivalenceResult.DIFFERENT;
61 } 62 }
62 63
63 private LongObjectHashMap<IntHashSet> indexByHash(ObjectCode code) { 64 private LongObjectHashMap<IntHashSet> indexByHash(ObjectCode code, IntSet individuals) {
64 LongObjectHashMap<IntHashSet> result = new LongObjectHashMap<>(); 65 LongObjectHashMap<IntHashSet> result = new LongObjectHashMap<>();
65 for (int o = 0; o < code.getSize(); o++) { 66 for (int o = 0; o < code.getSize(); o++) {
66 long hash = code.get(o); 67 if(! individuals.contains(o)){
67 var equivalenceClass = result.get(hash); 68 long hash = code.get(o);
68 if (equivalenceClass == null) { 69 if(hash != 0) {
69 equivalenceClass = new IntHashSet(); 70 var equivalenceClass = result.get(hash);
70 result.put(hash, equivalenceClass); 71 if (equivalenceClass == null) {
72 equivalenceClass = new IntHashSet();
73 result.put(hash, equivalenceClass);
74 }
75 equivalenceClass.add(o);
76 }
71 } 77 }
72 equivalenceClass.add(o);
73 } 78 }
74 return result; 79 return result;
75 } 80 }
76 81
77 private EquivalenceResult constructPermutationNavigation(LongObjectHashMap<IntHashSet> map1, 82 private EquivalenceResult constructPermutationNavigation(IntSet individuals,
78 LongObjectHashMap<IntHashSet> map2, 83 LongObjectHashMap<IntHashSet> map1,
79 IntIntHashMap emptyMapToListOfOptions, 84 LongObjectHashMap<IntHashSet> map2,
80 List<List<IntIntMap>> emptyListOfOptions) { 85 IntIntHashMap object2OptionIndex,
86 List<List<IntIntMap>> listOfOptions) {
81 if (map1.size() != map2.size()) { 87 if (map1.size() != map2.size()) {
82 return EquivalenceResult.DIFFERENT; 88 return EquivalenceResult.DIFFERENT;
83 } 89 }
@@ -101,10 +107,13 @@ public class StateEquivalenceCheckerImpl implements StateEquivalenceChecker {
101 107
102 allComplete &= pairing.isComplete(); 108 allComplete &= pairing.isComplete();
103 109
104 final int optionIndex = emptyListOfOptions.size(); 110 final int optionIndex = listOfOptions.size();
105 set1.forEach(key -> emptyMapToListOfOptions.put(key, optionIndex)); 111 set1.forEach(key -> object2OptionIndex.put(key, optionIndex));
106 emptyListOfOptions.add(pairing.permutations()); 112 listOfOptions.add(pairing.permutations());
107 } 113 }
114
115 individuals.forEach(o -> listOfOptions.add(o,List.of(IntIntMaps.immutable.of(o,o))));
116
108 if(allComplete) { 117 if(allComplete) {
109 return EquivalenceResult.ISOMORPHIC; 118 return EquivalenceResult.ISOMORPHIC;
110 } else { 119 } else {
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java
new file mode 100644
index 00000000..8a9c0e9b
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java
@@ -0,0 +1,178 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.statecoding;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.map.Version;
10import tools.refinery.store.model.Model;
11import tools.refinery.store.model.ModelStore;
12import tools.refinery.store.representation.Symbol;
13import tools.refinery.store.tuple.Tuple;
14
15import static org.junit.jupiter.api.Assertions.assertEquals;
16
17class EquivalenceTest {
18 Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false);
19 Symbol<Integer> age = new Symbol<>("age", 1, Integer.class, null);
20 Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false);
21 Symbol<Boolean> parents = new Symbol<>("parents", 3, Boolean.class, false);
22 Symbol<Integer> population = new Symbol<>("population", 0, Integer.class, 0);
23
24 private ModelStore createStore() {
25 return ModelStore.builder()
26 .symbols(person, age, friend, parents, population)
27 .with(StateCoderAdapter.builder())
28 .build();
29 }
30
31 @Test
32 void emptyModelCode0() {
33 ModelStore store = createStore();
34 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
35 Model model = createStore().createEmptyModel();
36 Version v1 = model.commit();
37 Version v2 = model.commit();
38
39 assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v1, v2));
40
41 var personI = model.getInterpretation(person);
42 var friendI = model.getInterpretation(friend);
43
44 personI.put(Tuple.of(1), true);
45 personI.put(Tuple.of(2), true);
46 friendI.put(Tuple.of(1, 2), true);
47
48 Version v3 = model.commit();
49
50 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v3));
51 }
52
53 @Test
54 void nullRelationTest() {
55 ModelStore store = createStore();
56 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
57 Model model = createStore().createEmptyModel();
58
59 var populationI = model.getInterpretation(population);
60
61 Version v1 = model.commit();
62
63 populationI.put(Tuple.of(), 1);
64 Version v2 = model.commit();
65
66 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2));
67
68 populationI.put(Tuple.of(), 2);
69 Version v3 = model.commit();
70
71 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3));
72 }
73
74 @Test
75 void unaryBooleanTest() {
76 ModelStore store = createStore();
77 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
78 Model model = createStore().createEmptyModel();
79
80 var personI = model.getInterpretation(person);
81
82 Version v1 = model.commit();
83
84 personI.put(Tuple.of(1), true);
85 Version v2 = model.commit();
86
87 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2));
88
89 personI.put(Tuple.of(2), true);
90 Version v3 = model.commit();
91
92 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3));
93
94 personI.put(Tuple.of(1), false);
95 Version v4 = model.commit();
96
97 assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4));
98 }
99
100 @Test
101 void unaryIntTest() {
102 ModelStore store = createStore();
103 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
104 Model model = createStore().createEmptyModel();
105
106 var ageI = model.getInterpretation(age);
107
108 ageI.put(Tuple.of(1), 3);
109 Version v1 = model.commit();
110
111 ageI.put(Tuple.of(1), 4);
112 Version v2 = model.commit();
113
114 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2));
115
116 ageI.put(Tuple.of(2), 4);
117 Version v3 = model.commit();
118
119 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3));
120
121 ageI.put(Tuple.of(1), null);
122 Version v4 = model.commit();
123
124 assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4));
125 }
126
127 @Test
128 void binaryTest() {
129 ModelStore store = createStore();
130 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
131 Model model = createStore().createEmptyModel();
132
133 var friendI = model.getInterpretation(friend);
134
135 Version v1 = model.commit();
136
137 friendI.put(Tuple.of(1, 2), true);
138 Version v2 = model.commit();
139
140 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2));
141
142 friendI.put(Tuple.of(2, 1), true);
143 Version v3 = model.commit();
144
145 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3));
146
147 friendI.put(Tuple.of(1, 2), false);
148 Version v4 = model.commit();
149
150 assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4));
151 }
152
153 @Test
154 void NaryTest() {
155 ModelStore store = createStore();
156 var stateCoder = store.getAdapter(StateCoderStoreAdapter.class);
157 Model model = createStore().createEmptyModel();
158
159 var parentsI = model.getInterpretation(parents);
160
161 Version v1 = model.commit();
162
163 parentsI.put(Tuple.of(3, 1, 2), true);
164 Version v2 = model.commit();
165
166 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2));
167
168 parentsI.put(Tuple.of(4, 1, 2), true);
169 Version v3 = model.commit();
170
171 assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3));
172
173 parentsI.put(Tuple.of(3, 1, 2), false);
174 Version v4 = model.commit();
175
176 assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4));
177 }
178}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java
index 87b1623c..25b5dca1 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java
@@ -5,16 +5,52 @@
5 */ 5 */
6package tools.refinery.store.statecoding; 6package tools.refinery.store.statecoding;
7 7
8import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap;
9import org.junit.jupiter.api.Tag;
8import org.junit.jupiter.api.Test; 10import org.junit.jupiter.api.Test;
11import org.junit.jupiter.params.ParameterizedTest;
12import org.junit.jupiter.params.provider.ValueSource;
9import tools.refinery.store.map.Version; 13import tools.refinery.store.map.Version;
14import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelStore; 15import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.representation.Symbol; 16import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.tuple.Tuple; 17import tools.refinery.store.tuple.Tuple;
13 18
14import java.util.*; 19import java.util.ArrayList;
20import java.util.HashSet;
21import java.util.List;
22import java.util.Set;
23
24import static org.junit.jupiter.api.Assertions.assertEquals;
25import static org.junit.jupiter.api.Assertions.assertTrue;
26
15 27
16class ExperimentalSetupTest { 28class ExperimentalSetupTest {
17 public static void generate(int size) { 29 static class ExperimentalSetupResult {
30 int versions = 0;
31 int different = 0;
32 int isomorphic = 0;
33 int unknown = 0;
34
35 double failureRatio() {
36 return (different + 0.0) / versions;
37 }
38
39 @Override
40 public String toString() {
41 return "ExperimentalSetupResult{" +
42 "versions=" + versions +
43 ", different=" + different +
44 ", isomorphic=" + isomorphic +
45 ", unknown=" + unknown +
46 ", ratio= " + failureRatio() +
47 '}';
48 }
49 }
50
51 static int MAX = 100000;
52
53 public static ExperimentalSetupResult generate(int size, boolean permuteTypes) {
18 Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false); 54 Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false);
19 Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false); 55 Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false);
20 56
@@ -25,13 +61,13 @@ class ExperimentalSetupTest {
25 .build(); 61 .build();
26 62
27 Set<Version> versions = new HashSet<>(); 63 Set<Version> versions = new HashSet<>();
28 Map<Integer, List<Version>> codes = new HashMap<>(); 64 IntObjectHashMap<List<Version>> codes = new IntObjectHashMap<>();
29 65
30 var empty = store.createEmptyModel(); 66 var empty = store.createEmptyModel();
31 var pI = empty.getInterpretation(person); 67 if (!permuteTypes) {
32 68 for (int i = 0; i < size; i++) {
33 for (int i = 0; i < size; i++) { 69 empty.getInterpretation(person).put(Tuple.of(i), true);
34 pI.put(Tuple.of(i), true); 70 }
35 } 71 }
36 72
37 var emptyVersion = empty.commit(); 73 var emptyVersion = empty.commit();
@@ -42,12 +78,27 @@ class ExperimentalSetupTest {
42 codes.put(emptyCode, emptyList); 78 codes.put(emptyCode, emptyList);
43 79
44 var storeAdapter = store.getAdapter(StateCoderStoreAdapter.class); 80 var storeAdapter = store.getAdapter(StateCoderStoreAdapter.class);
81 var result = new ExperimentalSetupResult();
45 82
46 int dif = 0; 83 int steps = 0;
47 int iso = 0;
48 int unk = 0;
49 84
50 //int step = 0 85 if (permuteTypes) {
86 for (int i = 0; i < size; i++) {
87 var previousVersions = new HashSet<>(versions);
88 for (var version : previousVersions) {
89 var model = store.createModelForState(version);
90 model.getInterpretation(person).put(Tuple.of(i), true);
91
92 saveAsNewVersion(versions, codes, storeAdapter, result, model);
93
94 logProgress(steps++);
95 if (steps > MAX) {
96 result.versions = versions.size();
97 return result;
98 }
99 }
100 }
101 }
51 102
52 for (int i = 0; i < size; i++) { 103 for (int i = 0; i < size; i++) {
53 for (int j = 0; j < size; j++) { 104 for (int j = 0; j < size; j++) {
@@ -57,51 +108,91 @@ class ExperimentalSetupTest {
57 var model = store.createModelForState(version); 108 var model = store.createModelForState(version);
58 model.getInterpretation(friend).put(Tuple.of(i, j), true); 109 model.getInterpretation(friend).put(Tuple.of(i, j), true);
59 110
60 Version version1 = model.commit(); 111 saveAsNewVersion(versions, codes, storeAdapter, result, model);
61 var stateCode = model.getAdapter(StateCoderAdapter.class).calculateStateCode(); 112
62 int code = stateCode.modelCode(); 113 logProgress(steps++);
63 //System.out.println(step+++" ->" +code); 114 if (steps > MAX) {
64 if (codes.containsKey(code)) { 115 result.versions = versions.size();
65 Version similar = codes.get(code).get(0); 116 return result;
66
67 var outcome = storeAdapter.checkEquivalence(version1, similar);
68 if (outcome == StateEquivalenceChecker.EquivalenceResult.DIFFERENT) {
69 System.out.println();
70 var c = model.getInterpretation(friend).getAll();
71 while (c.move()) {
72 System.out.println(c.getKey().toString());
73 }
74 System.out.println("vs");
75 var c2 = store.createModelForState(similar).getInterpretation(friend).getAll();
76 while (c2.move()) {
77 System.out.println(c2.getKey().toString());
78 }
79
80 dif++;
81 } else if (outcome == StateEquivalenceChecker.EquivalenceResult.UNKNOWN) {
82 unk++;
83 } else {
84 iso++;
85 }
86 } else {
87 versions.add(version1);
88
89 List<Version> newList = new ArrayList<>();
90 newList.add(version1);
91 codes.put(code, newList);
92 } 117 }
93 } 118 }
94 } 119 }
95 } 120 }
96 121
97 System.out.printf("v=%d i=%d d=%d u=%d\n", versions.size(), iso, dif, unk); 122 result.versions = versions.size();
123 return result;
98 } 124 }
99 125
100 @Test 126 private static void saveAsNewVersion(Set<Version> versions, IntObjectHashMap<List<Version>> codes,
101 void runTests() { 127 StateCoderStoreAdapter storeAdapter, ExperimentalSetupResult result, Model model) {
102 for (int i = 0; i < 5; i++) { 128 Version version1 = model.commit();
103 System.out.println("size = " + i); 129
104 generate(i); 130 var stateCode = model.getAdapter(StateCoderAdapter.class).calculateStateCode();
131 int code = stateCode.modelCode();
132 if (codes.containsKey(code)) {
133 Version similar = codes.get(code).get(0);
134
135 var outcome = storeAdapter.checkEquivalence(version1, similar);
136 if (outcome == StateEquivalenceChecker.EquivalenceResult.DIFFERENT) {
137 result.different++;
138 } else if (outcome == StateEquivalenceChecker.EquivalenceResult.UNKNOWN) {
139 result.unknown++;
140 } else {
141 result.isomorphic++;
142 }
143 } else {
144 versions.add(version1);
145
146 List<Version> newList = new ArrayList<>();
147 newList.add(version1);
148 codes.put(code, newList);
149 }
150 }
151
152 private static void logProgress(int steps) {
153 if (steps % 10000 == 0) {
154 System.out.println("Steps: " + steps + " / " + MAX);
105 } 155 }
106 } 156 }
157
158 static final double limit = 0.01;
159
160 @Test
161 void test0() {
162 assertEquals(1, generate(0, true).versions);
163 }
164
165 @ParameterizedTest
166 @ValueSource(ints = {1, 2, 3, 4})
167 void testForSmallUntypedModels(int size) {
168 var res = generate(size, false);
169 System.out.println(res);
170 assertTrue(res.failureRatio() < limit);
171 }
172
173 @ParameterizedTest
174 @ValueSource(ints = {1, 2, 3})
175 void testForSmallTypedModels(int size) {
176 var res = generate(size, true);
177 System.out.println(res);
178 assertTrue(res.failureRatio() < limit);
179 }
180
181 @Test
182 @Tag("fuzz")
183 @Tag("slow")
184 void testForLargeTypedModels() {
185 var res = generate(10, true);
186 System.out.println(res);
187 assertTrue(res.failureRatio() < limit);
188 }
189
190 @Test
191 @Tag("fuzz")
192 @Tag("slow")
193 void testForLargeUntypedModels() {
194 var res = generate(10, false);
195 System.out.println(res);
196 assertTrue(res.failureRatio() < limit);
197 }
107} 198}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java
index b0b80af7..0b738005 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java
@@ -19,11 +19,10 @@ class StateCoderBuildTest {
19 Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false); 19 Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false);
20 20
21 @Test 21 @Test
22 void simpleStateCoderTest() { 22 void simpleStateCoderBuildTest() {
23 var store = ModelStore.builder() 23 var store = ModelStore.builder()
24 .symbols(person, age, friend) 24 .symbols(person, age, friend)
25 .with(StateCoderAdapter 25 .with(StateCoderAdapter.builder())
26 .builder())
27 .build(); 26 .build();
28 27
29 var model = store.createEmptyModel(); 28 var model = store.createEmptyModel();
@@ -33,6 +32,7 @@ class StateCoderBuildTest {
33 var personI = model.getInterpretation(person); 32 var personI = model.getInterpretation(person);
34 var friendI = model.getInterpretation(friend); 33 var friendI = model.getInterpretation(friend);
35 var ageI = model.getInterpretation(age); 34 var ageI = model.getInterpretation(age);
35
36 fill(personI, friendI, ageI); 36 fill(personI, friendI, ageI);
37 37
38 stateCoder.calculateStateCode(); 38 stateCoder.calculateStateCode();
@@ -58,16 +58,107 @@ class StateCoderBuildTest {
58 58
59 int code = stateCoder.calculateStateCode().modelCode(); 59 int code = stateCoder.calculateStateCode().modelCode();
60 60
61 ageI.put(Tuple.of(1),3); 61 ageI.put(Tuple.of(1), 3);
62 assertEquals(code,stateCoder.calculateStateCode().modelCode()); 62 assertEquals(code, stateCoder.calculateStateCode().modelCode());
63
64 ageI.put(Tuple.of(1), null);
65 assertEquals(code, stateCoder.calculateStateCode().modelCode());
66
67 personI.put(Tuple.of(2), false);
68 assertEquals(code, stateCoder.calculateStateCode().modelCode());
69 }
70
71 @Test
72 void notIndividualTest() {
73 var store = ModelStore.builder()
74 .symbols(friend)
75 .with(StateCoderAdapter.builder())
76 .build();
77
78 var model = store.createEmptyModel();
79 var stateCoder = model.getAdapter(StateCoderAdapter.class);
80
81 var friendI = model.getInterpretation(friend);
82
83 friendI.put(Tuple.of(1, 2), true);
84 int code1 = stateCoder.calculateModelCode();
63 85
64 ageI.put(Tuple.of(1),null); 86 friendI.put(Tuple.of(1, 2), false);
65 assertEquals(code,stateCoder.calculateStateCode().modelCode()); 87 friendI.put(Tuple.of(2, 1), true);
88 int code2 = stateCoder.calculateModelCode();
66 89
67 personI.put(Tuple.of(2),false); 90 assertEquals(code1, code2);
68 assertEquals(code,stateCoder.calculateStateCode().modelCode());
69 } 91 }
70 92
93 @Test
94 void individualTest() {
95 var store = ModelStore.builder()
96 .symbols(friend)
97 .with(StateCoderAdapter.builder()
98 .individual(Tuple.of(1)))
99 .build();
100
101 var model = store.createEmptyModel();
102 var stateCoder = model.getAdapter(StateCoderAdapter.class);
103
104 var friendI = model.getInterpretation(friend);
105
106 friendI.put(Tuple.of(1, 2), true);
107 int code1 = stateCoder.calculateModelCode();
108
109 friendI.put(Tuple.of(1, 2), false);
110 friendI.put(Tuple.of(2, 1), true);
111 int code2 = stateCoder.calculateModelCode();
112
113 assertNotEquals(code1, code2);
114 }
115
116 @Test
117 void customStateCoderTest() {
118 final boolean[] called = new boolean[]{false};
119 StateCodeCalculator mock = () -> {
120 called[0] = true;
121 return null;
122 };
123
124 var store = ModelStore.builder()
125 .symbols(friend)
126 .with(StateCoderAdapter.builder()
127 .stateCodeCalculatorFactory((interpretations, individuals) -> mock))
128 .build();
129
130 var model = store.createEmptyModel();
131 var stateCoder = model.getAdapter(StateCoderAdapter.class);
132
133 stateCoder.calculateStateCode();
134
135 assertTrue(called[0]);
136 }
137
138 @Test
139 void customEquivalenceCheckerTest() {
140 final boolean[] called = new boolean[]{false};
141 StateEquivalenceChecker mock = (p1, p2, p3, p4, p5) -> {
142 called[0] = true;
143 return StateEquivalenceChecker.EquivalenceResult.UNKNOWN;
144 };
145
146 var store = ModelStore.builder()
147 .symbols(friend)
148 .with(StateCoderAdapter.builder()
149 .stateEquivalenceChecker(mock))
150 .build();
151
152 var model = store.createEmptyModel();
153 var v1 = model.commit();
154 var v2 = model.commit();
155
156 store.getAdapter(StateCoderStoreAdapter.class).checkEquivalence(v1, v2);
157
158 assertTrue(called[0]);
159 }
160
161
71 private static void fill(Interpretation<Boolean> personI, Interpretation<Boolean> friendI, Interpretation<Integer> ageI) { 162 private static void fill(Interpretation<Boolean> personI, Interpretation<Boolean> friendI, Interpretation<Integer> ageI) {
72 personI.put(Tuple.of(1), true); 163 personI.put(Tuple.of(1), true);
73 personI.put(Tuple.of(2), true); 164 personI.put(Tuple.of(2), true);
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java
new file mode 100644
index 00000000..d94df841
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java
@@ -0,0 +1,195 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.statecoding;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.tuple.Tuple;
13
14import java.util.Objects;
15
16import static org.junit.jupiter.api.Assertions.*;
17
18class StateCoderUnitTest {
19 Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false);
20 Symbol<Integer> age = new Symbol<>("age", 1, Integer.class, null);
21 Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false);
22 Symbol<Boolean> parents = new Symbol<>("parents", 3, Boolean.class, false);
23 Symbol<Integer> population = new Symbol<>("population", 0, Integer.class, 0);
24
25 private Model createEmptyModel() {
26 var store = ModelStore.builder()
27 .symbols(person, age, friend, parents, population)
28 .with(StateCoderAdapter.builder())
29 .build();
30
31 return store.createEmptyModel();
32 }
33
34 @Test
35 void emptyModelCode0() {
36 Model model = createEmptyModel();
37 var stateCoder = model.getAdapter(StateCoderAdapter.class);
38
39 assertEquals(0, stateCoder.calculateModelCode());
40
41 var personI = model.getInterpretation(person);
42 var friendI = model.getInterpretation(friend);
43
44 personI.put(Tuple.of(1), true);
45 personI.put(Tuple.of(2), true);
46 friendI.put(Tuple.of(1, 2), true);
47
48 assertNotEquals(0, stateCoder.calculateModelCode());
49 }
50
51 @Test
52 void emptyObjectCode0() {
53 Model model = createEmptyModel();
54 var stateCoder = model.getAdapter(StateCoderAdapter.class);
55
56 var personI = model.getInterpretation(person);
57 var friendI = model.getInterpretation(friend);
58
59 assertEquals(0, stateCoder.calculateObjectCode().get(1));
60 assertEquals(0, stateCoder.calculateObjectCode().get(17));
61
62 personI.put(Tuple.of(1), true);
63 personI.put(Tuple.of(2), true);
64 friendI.put(Tuple.of(1, 2), true);
65
66 assertNotEquals(0, stateCoder.calculateObjectCode().get(1));
67 assertEquals(0, stateCoder.calculateObjectCode().get(17));
68 }
69
70 @Test
71 void nullRelationTest() {
72 Model model = createEmptyModel();
73 var stateCoder = model.getAdapter(StateCoderAdapter.class);
74
75 var populationI = model.getInterpretation(population);
76
77 final int hashOf0 = Objects.hashCode(0);
78
79 assertEquals(hashOf0, stateCoder.calculateModelCode());
80
81 populationI.put(Tuple.of(), 1);
82 int code1 = stateCoder.calculateModelCode();
83
84 assertNotEquals(hashOf0, stateCoder.calculateModelCode());
85
86 populationI.put(Tuple.of(), 2);
87 int code2 = stateCoder.calculateModelCode();
88
89 assertNotEquals(code1, code2);
90
91 populationI.put(Tuple.of(), 1);
92 assertEquals(code1, stateCoder.calculateModelCode());
93 }
94
95 @Test
96 void unaryBooleanTest() {
97 Model model = createEmptyModel();
98 var stateCoder = model.getAdapter(StateCoderAdapter.class);
99
100 var personI = model.getInterpretation(person);
101
102 assertEquals(0, stateCoder.calculateModelCode());
103
104 personI.put(Tuple.of(1), true);
105 int code1 = stateCoder.calculateModelCode();
106
107 assertNotEquals(0, stateCoder.calculateModelCode());
108
109 personI.put(Tuple.of(2), true);
110 int code2 = stateCoder.calculateModelCode();
111
112 assertNotEquals(code1, code2);
113
114 personI.put(Tuple.of(1), false);
115 assertEquals(code1, stateCoder.calculateModelCode());
116 }
117
118 @Test
119 void unaryIntTest() {
120 Model model = createEmptyModel();
121 var stateCoder = model.getAdapter(StateCoderAdapter.class);
122
123 var ageI = model.getInterpretation(age);
124
125 assertEquals(0, stateCoder.calculateModelCode());
126
127 ageI.put(Tuple.of(1), 4);
128 int code0 = stateCoder.calculateModelCode();
129
130 assertNotEquals(0, code0);
131
132 ageI.put(Tuple.of(1), 5);
133 int code1 = stateCoder.calculateModelCode();
134
135 assertNotEquals(code0, code1);
136
137 ageI.put(Tuple.of(2), 5);
138 int code2 = stateCoder.calculateModelCode();
139
140 assertNotEquals(code1, code2);
141
142 ageI.put(Tuple.of(1), null);
143 assertEquals(code1, stateCoder.calculateModelCode());
144 }
145
146 @Test
147 void binaryTest() {
148 Model model = createEmptyModel();
149 var stateCoder = model.getAdapter(StateCoderAdapter.class);
150
151 var friendI = model.getInterpretation(friend);
152
153 assertEquals(0, stateCoder.calculateModelCode());
154
155 friendI.put(Tuple.of(1, 2), true);
156 int code1 = stateCoder.calculateModelCode();
157
158 assertNotEquals(0, code1);
159
160 friendI.put(Tuple.of(2, 1), true);
161 int code2 = stateCoder.calculateModelCode();
162
163 assertNotEquals(code1, code2);
164
165 friendI.put(Tuple.of(1, 2), false);
166 int code3 = stateCoder.calculateModelCode();
167
168 assertEquals(code1, code3);
169 }
170
171 @Test
172 void NaryTest() {
173 Model model = createEmptyModel();
174 var stateCoder = model.getAdapter(StateCoderAdapter.class);
175
176 var parentsI = model.getInterpretation(parents);
177
178 assertEquals(0, stateCoder.calculateModelCode());
179
180 parentsI.put(Tuple.of(3, 1, 2), true);
181 int code1 = stateCoder.calculateModelCode();
182
183 assertNotEquals(0, code1);
184
185 parentsI.put(Tuple.of(4, 1, 2), true);
186 int code2 = stateCoder.calculateModelCode();
187
188 assertNotEquals(code1, code2);
189
190 parentsI.put(Tuple.of(3, 1, 2), false);
191 int code3 = stateCoder.calculateModelCode();
192
193 assertEquals(code1, code3);
194 }
195}