diff options
12 files changed, 297 insertions, 251 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 | */ | ||
6 | package tools.refinery.store.statecoding; | ||
7 | |||
8 | import org.eclipse.collections.api.set.primitive.IntSet; | ||
9 | import tools.refinery.store.model.Interpretation; | ||
10 | |||
11 | import java.util.List; | ||
12 | |||
13 | public 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; | |||
8 | import tools.refinery.store.adapter.ModelAdapterBuilder; | 8 | import tools.refinery.store.adapter.ModelAdapterBuilder; |
9 | import tools.refinery.store.model.ModelStore; | 9 | import tools.refinery.store.model.ModelStore; |
10 | import tools.refinery.store.representation.AnySymbol; | 10 | import tools.refinery.store.representation.AnySymbol; |
11 | import tools.refinery.store.tuple.Tuple1; | ||
11 | 12 | ||
13 | import java.util.Arrays; | ||
12 | import java.util.Collection; | 14 | import java.util.Collection; |
13 | import java.util.List; | 15 | import 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 | */ |
6 | package tools.refinery.store.statecoding; | 6 | package tools.refinery.store.statecoding; |
7 | 7 | ||
8 | import org.eclipse.collections.api.set.primitive.IntSet; | ||
8 | import tools.refinery.store.model.Interpretation; | 9 | import tools.refinery.store.model.Interpretation; |
9 | 10 | ||
10 | import java.util.List; | 11 | import 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 @@ | |||
6 | package tools.refinery.store.statecoding.internal; | 6 | package tools.refinery.store.statecoding.internal; |
7 | 7 | ||
8 | import tools.refinery.store.adapter.ModelStoreAdapter; | 8 | import tools.refinery.store.adapter.ModelStoreAdapter; |
9 | import tools.refinery.store.model.Interpretation; | ||
10 | import tools.refinery.store.model.Model; | 9 | import tools.refinery.store.model.Model; |
11 | import tools.refinery.store.representation.Symbol; | ||
12 | import tools.refinery.store.statecoding.StateCodeCalculator; | 10 | import tools.refinery.store.statecoding.StateCodeCalculator; |
13 | import tools.refinery.store.statecoding.StateCoderAdapter; | 11 | import tools.refinery.store.statecoding.StateCoderAdapter; |
14 | import tools.refinery.store.statecoding.StateCoderResult; | 12 | import tools.refinery.store.statecoding.StateCoderResult; |
15 | import tools.refinery.store.statecoding.neighbourhood.LazyNeighbourhoodCalculator; | ||
16 | |||
17 | import java.util.Collection; | ||
18 | import java.util.List; | ||
19 | 13 | ||
20 | public class StateCoderAdapterImpl implements StateCoderAdapter { | 14 | public 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..8268a826 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,27 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.statecoding.internal; | 6 | package tools.refinery.store.statecoding.internal; |
7 | 7 | ||
8 | import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet; | ||
8 | import tools.refinery.store.model.ModelStore; | 9 | import tools.refinery.store.model.ModelStore; |
9 | import tools.refinery.store.model.ModelStoreBuilder; | 10 | import tools.refinery.store.model.ModelStoreBuilder; |
10 | import tools.refinery.store.representation.AnySymbol; | 11 | import tools.refinery.store.representation.AnySymbol; |
11 | import tools.refinery.store.representation.Symbol; | 12 | import tools.refinery.store.representation.Symbol; |
13 | import tools.refinery.store.statecoding.StateCodeCalculatorFactory; | ||
12 | import tools.refinery.store.statecoding.StateCoderBuilder; | 14 | import tools.refinery.store.statecoding.StateCoderBuilder; |
13 | import tools.refinery.store.statecoding.StateCoderStoreAdapter; | 15 | import tools.refinery.store.statecoding.StateCoderStoreAdapter; |
16 | import tools.refinery.store.statecoding.StateEquivalenceChecker; | ||
17 | import tools.refinery.store.statecoding.neighbourhood.LazyNeighbourhoodCalculatorFactory; | ||
18 | import tools.refinery.store.statecoding.stateequivalence.StateEquivalenceCheckerImpl; | ||
19 | import tools.refinery.store.tuple.Tuple1; | ||
14 | 20 | ||
15 | import java.util.HashSet; | 21 | import java.util.*; |
16 | import java.util.LinkedHashSet; | ||
17 | import java.util.Set; | ||
18 | 22 | ||
19 | public class StateCoderBuilderImpl implements StateCoderBuilder { | 23 | public class StateCoderBuilderImpl implements StateCoderBuilder { |
20 | Set<AnySymbol> excluded = new HashSet<>(); | 24 | Set<AnySymbol> excluded = new HashSet<>(); |
25 | IntHashSet individuals = new IntHashSet(); | ||
26 | |||
27 | StateCodeCalculatorFactory calculator = new LazyNeighbourhoodCalculatorFactory(); | ||
28 | StateEquivalenceChecker checker = new StateEquivalenceCheckerImpl(); | ||
21 | 29 | ||
22 | @Override | 30 | @Override |
23 | public StateCoderBuilder exclude(AnySymbol symbol) { | 31 | public StateCoderBuilder exclude(AnySymbol symbol) { |
@@ -26,6 +34,24 @@ public class StateCoderBuilderImpl implements StateCoderBuilder { | |||
26 | } | 34 | } |
27 | 35 | ||
28 | @Override | 36 | @Override |
37 | public StateCoderBuilder individual(Tuple1 tuple) { | ||
38 | individuals.add(tuple.get(0)); | ||
39 | return this; | ||
40 | } | ||
41 | |||
42 | @Override | ||
43 | public StateCoderBuilder stateEquivalenceChecker(StateEquivalenceChecker stateEquivalenceChecker) { | ||
44 | this.checker = stateEquivalenceChecker; | ||
45 | return this; | ||
46 | } | ||
47 | |||
48 | @Override | ||
49 | public StateCoderBuilder stateCodeCalculatorFactory(StateCodeCalculatorFactory codeCalculatorFactory) { | ||
50 | this.calculator = codeCalculatorFactory; | ||
51 | return this; | ||
52 | } | ||
53 | |||
54 | @Override | ||
29 | public boolean isConfigured() { | 55 | public boolean isConfigured() { |
30 | return true; | 56 | return true; |
31 | } | 57 | } |
@@ -43,6 +69,6 @@ public class StateCoderBuilderImpl implements StateCoderBuilder { | |||
43 | symbols.add(typed); | 69 | symbols.add(typed); |
44 | } | 70 | } |
45 | } | 71 | } |
46 | return new StateCoderStoreAdapterImpl(store, symbols); | 72 | return new StateCoderStoreAdapterImpl(store, calculator, checker, symbols, individuals); |
47 | } | 73 | } |
48 | } | 74 | } |
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 | */ |
6 | package tools.refinery.store.statecoding.internal; | 6 | package tools.refinery.store.statecoding.internal; |
7 | 7 | ||
8 | import org.eclipse.collections.api.set.primitive.IntSet; | ||
8 | import tools.refinery.store.map.Version; | 9 | import tools.refinery.store.map.Version; |
9 | import tools.refinery.store.model.Model; | 10 | import tools.refinery.store.model.Model; |
10 | import tools.refinery.store.model.ModelStore; | 11 | import tools.refinery.store.model.ModelStore; |
11 | import tools.refinery.store.representation.Symbol; | 12 | import tools.refinery.store.representation.Symbol; |
13 | import tools.refinery.store.statecoding.StateCodeCalculatorFactory; | ||
12 | import tools.refinery.store.statecoding.StateCoderAdapter; | 14 | import tools.refinery.store.statecoding.StateCoderAdapter; |
13 | import tools.refinery.store.statecoding.StateCoderStoreAdapter; | 15 | import tools.refinery.store.statecoding.StateCoderStoreAdapter; |
14 | import tools.refinery.store.statecoding.StateEquivalenceChecker; | 16 | import tools.refinery.store.statecoding.StateEquivalenceChecker; |
15 | import tools.refinery.store.statecoding.stateequivalence.StateEquivalenceCheckerImpl; | ||
16 | 17 | ||
17 | import java.util.Collection; | 18 | import java.util.Collection; |
18 | import java.util.Objects; | 19 | import java.util.Objects; |
@@ -20,12 +21,22 @@ import java.util.Objects; | |||
20 | public class StateCoderStoreAdapterImpl implements StateCoderStoreAdapter { | 21 | public 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..0de76519 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/AbstractNeighbourhoodCalculator.java | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.statecoding.neighbourhood; | ||
7 | |||
8 | import org.eclipse.collections.api.set.primitive.IntSet; | ||
9 | import org.eclipse.collections.impl.map.mutable.primitive.IntLongHashMap; | ||
10 | import org.eclipse.collections.impl.map.mutable.primitive.LongIntHashMap; | ||
11 | import tools.refinery.store.model.Interpretation; | ||
12 | import tools.refinery.store.statecoding.ObjectCode; | ||
13 | import tools.refinery.store.tuple.Tuple; | ||
14 | import tools.refinery.store.tuple.Tuple0; | ||
15 | |||
16 | import java.util.ArrayList; | ||
17 | import java.util.LinkedHashMap; | ||
18 | import java.util.List; | ||
19 | import java.util.Random; | ||
20 | |||
21 | public abstract class AbstractNeighbourhoodCalculator { | ||
22 | protected final List<Interpretation<?>> nullImpactValues; | ||
23 | protected final LinkedHashMap<Interpretation<?>, long[]> impactValues; | ||
24 | protected final IntLongHashMap individualHashValues; | ||
25 | |||
26 | protected AbstractNeighbourhoodCalculator(List<? extends Interpretation<?>> interpretations, IntSet individuals) { | ||
27 | this.nullImpactValues = new ArrayList<>(); | ||
28 | this.impactValues = new LinkedHashMap<>(); | ||
29 | Random random = new Random(1); | ||
30 | |||
31 | individualHashValues = new IntLongHashMap(); | ||
32 | var individualsInOrder = individuals.toSortedList(Integer::compare); | ||
33 | for(int i = 0; i<individualsInOrder.size(); i++) { | ||
34 | individualHashValues.put(individualsInOrder.get(i), random.nextLong()); | ||
35 | } | ||
36 | |||
37 | for (Interpretation<?> interpretation : interpretations) { | ||
38 | int arity = interpretation.getSymbol().arity(); | ||
39 | if (arity == 0) { | ||
40 | nullImpactValues.add(interpretation); | ||
41 | } else { | ||
42 | long[] impact = new long[arity]; | ||
43 | for (int i = 0; i < arity; i++) { | ||
44 | impact[i] = random.nextInt(); | ||
45 | } | ||
46 | impactValues.put(interpretation, impact); | ||
47 | } | ||
48 | } | ||
49 | } | ||
50 | |||
51 | protected void initializeWithIndividuals(ObjectCodeImpl previous, LongIntHashMap hash2Amount) { | ||
52 | for (var entry : individualHashValues.keyValuesView()) { | ||
53 | previous.set(entry.getOne(), entry.getTwo()); | ||
54 | hash2Amount.put(entry.getTwo(), 1); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | protected long getTupleHash1(Tuple tuple, Object value, ObjectCode objectCodeImpl) { | ||
59 | long result = value.hashCode(); | ||
60 | result = result * 31 + objectCodeImpl.get(tuple.get(0)); | ||
61 | return result; | ||
62 | } | ||
63 | |||
64 | protected long getTupleHash2(Tuple tuple, Object value, ObjectCode objectCodeImpl) { | ||
65 | long result = value.hashCode(); | ||
66 | result = result * 31 + objectCodeImpl.get(tuple.get(0)); | ||
67 | result = result * 31 + objectCodeImpl.get(tuple.get(1)); | ||
68 | if (tuple.get(0) == tuple.get(1)) { | ||
69 | result *= 31; | ||
70 | } | ||
71 | return result; | ||
72 | } | ||
73 | |||
74 | protected long getTupleHashN(Tuple tuple, Object value, ObjectCode objectCodeImpl) { | ||
75 | long result = value.hashCode(); | ||
76 | for (int i = 0; i < tuple.getSize(); i++) { | ||
77 | result = result * 31 + objectCodeImpl.get(tuple.get(i)); | ||
78 | } | ||
79 | return result; | ||
80 | } | ||
81 | |||
82 | protected void addHash(ObjectCodeImpl objectCodeImpl, int o, long impact, long tupleHash) { | ||
83 | long x = tupleHash * impact; | ||
84 | objectCodeImpl.set(o, objectCodeImpl.get(o) + x); | ||
85 | } | ||
86 | |||
87 | protected long calculateModelCode(long lastSum) { | ||
88 | long result = 1; | ||
89 | for (var nullImpactValue : nullImpactValues) { | ||
90 | result = result * 31 + nullImpactValue.get(Tuple0.INSTANCE).hashCode(); | ||
91 | } | ||
92 | result += lastSum; | ||
93 | return result; | ||
94 | } | ||
95 | } | ||
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..98a75e08 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,74 +6,48 @@ | |||
6 | package tools.refinery.store.statecoding.neighbourhood; | 6 | package tools.refinery.store.statecoding.neighbourhood; |
7 | 7 | ||
8 | import org.eclipse.collections.api.map.primitive.LongIntMap; | 8 | import org.eclipse.collections.api.map.primitive.LongIntMap; |
9 | import org.eclipse.collections.api.set.primitive.IntSet; | ||
9 | import org.eclipse.collections.impl.map.mutable.primitive.LongIntHashMap; | 10 | import org.eclipse.collections.impl.map.mutable.primitive.LongIntHashMap; |
10 | import tools.refinery.store.map.Cursor; | 11 | import tools.refinery.store.map.Cursor; |
11 | import tools.refinery.store.model.Interpretation; | 12 | import tools.refinery.store.model.Interpretation; |
12 | import tools.refinery.store.statecoding.StateCodeCalculator; | 13 | import tools.refinery.store.statecoding.StateCodeCalculator; |
13 | import tools.refinery.store.statecoding.StateCoderResult; | 14 | import tools.refinery.store.statecoding.StateCoderResult; |
14 | import tools.refinery.store.tuple.Tuple; | 15 | import tools.refinery.store.tuple.Tuple; |
15 | import tools.refinery.store.tuple.Tuple0; | ||
16 | 16 | ||
17 | import java.util.ArrayList; | ||
18 | import java.util.LinkedHashMap; | ||
19 | import java.util.List; | 17 | import java.util.List; |
20 | import java.util.Random; | ||
21 | 18 | ||
22 | public class LazyNeighbourhoodCalculator implements StateCodeCalculator { | 19 | public 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 previous = new ObjectCodeImpl(); |
47 | ObjectCodeImpl next = new ObjectCodeImpl(); | 26 | LongIntHashMap hash2Amount = new LongIntHashMap(); |
48 | LongIntMap hash2Amount = new LongIntHashMap(); | 27 | |
28 | initializeWithIndividuals(previous, hash2Amount); | ||
49 | 29 | ||
50 | long lastSum; | 30 | long lastSum; |
51 | int lastSize = 1; | 31 | // All hash code is 0, except to the individuals. |
52 | boolean grows; | 32 | int lastSize = hash2Amount.size() + 1; |
53 | 33 | ||
34 | boolean grows; | ||
54 | do { | 35 | do { |
36 | ObjectCodeImpl next = new ObjectCodeImpl(); | ||
55 | constructNextObjectCodes(previous, next, hash2Amount); | 37 | constructNextObjectCodes(previous, next, hash2Amount); |
56 | 38 | ||
57 | LongIntHashMap nextHash2Amount = new LongIntHashMap(); | 39 | LongIntHashMap nextHash2Amount = new LongIntHashMap(); |
58 | lastSum = calculateLastSum(previous, next, hash2Amount, nextHash2Amount); | 40 | lastSum = calculateLastSum(previous, next, hash2Amount, nextHash2Amount); |
59 | 41 | ||
60 | previous = next; | ||
61 | next = null; | ||
62 | |||
63 | int nextSize = nextHash2Amount.size(); | 42 | int nextSize = nextHash2Amount.size(); |
64 | grows = nextSize > lastSize; | 43 | grows = nextSize > lastSize; |
65 | lastSize = nextSize; | 44 | lastSize = nextSize; |
66 | 45 | ||
67 | if (grows) { | 46 | previous = next; |
68 | next = new ObjectCodeImpl(previous); | 47 | hash2Amount = nextHash2Amount; |
69 | } | ||
70 | } while (grows); | 48 | } while (grows); |
71 | 49 | ||
72 | long result = 1; | 50 | long result = calculateModelCode(lastSum); |
73 | for (var nullImpactValue : nullImpactValues) { | ||
74 | result = result * 31 + nullImpactValue.get(Tuple0.INSTANCE).hashCode(); | ||
75 | } | ||
76 | result += lastSum; | ||
77 | 51 | ||
78 | return new StateCoderResult((int) result, previous); | 52 | return new StateCoderResult((int) result, previous); |
79 | } | 53 | } |
@@ -96,7 +70,7 @@ public class LazyNeighbourhoodCalculator implements StateCodeCalculator { | |||
96 | final long shifted1 = hash >>> 8; | 70 | final long shifted1 = hash >>> 8; |
97 | final long shifted2 = hash << 8; | 71 | final long shifted2 = hash << 8; |
98 | final long shifted3 = hash >> 2; | 72 | final long shifted3 = hash >> 2; |
99 | lastSum += shifted1*shifted3 + shifted2; | 73 | lastSum += shifted1 * shifted3 + shifted2; |
100 | } | 74 | } |
101 | return lastSum; | 75 | return lastSum; |
102 | } | 76 | } |
@@ -126,7 +100,7 @@ public class LazyNeighbourhoodCalculator implements StateCodeCalculator { | |||
126 | 100 | ||
127 | private boolean isUnique(LongIntMap hash2Amount, ObjectCodeImpl objectCodeImpl, int object) { | 101 | private boolean isUnique(LongIntMap hash2Amount, ObjectCodeImpl objectCodeImpl, int object) { |
128 | final long hash = objectCodeImpl.get(object); | 102 | final long hash = objectCodeImpl.get(object); |
129 | if(hash == 0) { | 103 | if (hash == 0) { |
130 | return false; | 104 | return false; |
131 | } | 105 | } |
132 | final int amount = hash2Amount.get(hash); | 106 | final int amount = hash2Amount.get(hash); |
@@ -149,12 +123,12 @@ public class LazyNeighbourhoodCalculator implements StateCodeCalculator { | |||
149 | } | 123 | } |
150 | 124 | ||
151 | private void lazyImpactCalculation2(LongIntMap hash2Amount, ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) { | 125 | private void lazyImpactCalculation2(LongIntMap hash2Amount, ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) { |
152 | Tuple tuple = cursor.getKey(); | 126 | final Tuple tuple = cursor.getKey(); |
153 | int o1 = tuple.get(0); | 127 | final int o1 = tuple.get(0); |
154 | int o2 = tuple.get(1); | 128 | final int o2 = tuple.get(1); |
155 | 129 | ||
156 | boolean u1 = isUnique(hash2Amount, previous, o1); | 130 | final boolean u1 = isUnique(hash2Amount, previous, o1); |
157 | boolean u2 = isUnique(hash2Amount, previous, o2); | 131 | final boolean u2 = isUnique(hash2Amount, previous, o2); |
158 | 132 | ||
159 | if (u1 && u2) { | 133 | if (u1 && u2) { |
160 | next.ensureSize(o1); | 134 | next.ensureSize(o1); |
@@ -175,9 +149,9 @@ public class LazyNeighbourhoodCalculator implements StateCodeCalculator { | |||
175 | } | 149 | } |
176 | 150 | ||
177 | private void lazyImpactCalculationN(LongIntMap hash2Amount, ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) { | 151 | private void lazyImpactCalculationN(LongIntMap hash2Amount, ObjectCodeImpl previous, ObjectCodeImpl next, long[] impactValues, Cursor<Tuple, ?> cursor) { |
178 | Tuple tuple = cursor.getKey(); | 152 | final Tuple tuple = cursor.getKey(); |
179 | 153 | ||
180 | boolean[] uniques = new boolean[tuple.getSize()]; | 154 | final boolean[] uniques = new boolean[tuple.getSize()]; |
181 | boolean allUnique = true; | 155 | boolean allUnique = true; |
182 | for (int i = 0; i < tuple.getSize(); i++) { | 156 | for (int i = 0; i < tuple.getSize(); i++) { |
183 | final boolean isUnique = isUnique(hash2Amount, previous, tuple.get(i)); | 157 | final boolean isUnique = isUnique(hash2Amount, previous, tuple.get(i)); |
@@ -204,32 +178,4 @@ public class LazyNeighbourhoodCalculator implements StateCodeCalculator { | |||
204 | } | 178 | } |
205 | } | 179 | } |
206 | 180 | ||
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 | } | 181 | } |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculatorFactory.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculatorFactory.java new file mode 100644 index 00000000..2e499f95 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/LazyNeighbourhoodCalculatorFactory.java | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.statecoding.neighbourhood; | ||
7 | |||
8 | import org.eclipse.collections.api.set.primitive.IntSet; | ||
9 | import tools.refinery.store.model.Interpretation; | ||
10 | import tools.refinery.store.statecoding.StateCodeCalculator; | ||
11 | import tools.refinery.store.statecoding.StateCodeCalculatorFactory; | ||
12 | |||
13 | import java.util.List; | ||
14 | |||
15 | public class LazyNeighbourhoodCalculatorFactory implements StateCodeCalculatorFactory { | ||
16 | @Override | ||
17 | public StateCodeCalculator create(List<? extends Interpretation<?>> interpretations, IntSet individuals) { | ||
18 | return new LazyNeighbourhoodCalculator(interpretations,individuals); | ||
19 | } | ||
20 | } | ||
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 deleted file mode 100644 index 212291c3..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java +++ /dev/null | |||
@@ -1,132 +0,0 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.statecoding.neighbourhood; | ||
7 | |||
8 | import org.eclipse.collections.api.set.primitive.MutableLongSet; | ||
9 | import org.eclipse.collections.impl.set.mutable.primitive.LongHashSet; | ||
10 | import tools.refinery.store.model.Interpretation; | ||
11 | import tools.refinery.store.statecoding.StateCodeCalculator; | ||
12 | import tools.refinery.store.statecoding.StateCoderResult; | ||
13 | import tools.refinery.store.tuple.Tuple; | ||
14 | import tools.refinery.store.tuple.Tuple0; | ||
15 | |||
16 | import java.util.ArrayList; | ||
17 | import java.util.LinkedHashMap; | ||
18 | import java.util.List; | ||
19 | import java.util.Random; | ||
20 | |||
21 | public class NeighbourhoodCalculator implements StateCodeCalculator { | ||
22 | protected final List<Interpretation<?>> nullImpactValues; | ||
23 | protected final LinkedHashMap<Interpretation<?>, long[]> impactValues; | ||
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 | } | ||
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 | |||
132 | } | ||
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..e58a2502 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 | */ |
6 | package tools.refinery.store.statecoding.stateequivalence; | 6 | package tools.refinery.store.statecoding.stateequivalence; |
7 | 7 | ||
8 | import org.eclipse.collections.api.factory.primitive.IntIntMaps; | ||
8 | import org.eclipse.collections.api.map.primitive.IntIntMap; | 9 | import org.eclipse.collections.api.map.primitive.IntIntMap; |
10 | import org.eclipse.collections.api.set.primitive.IntSet; | ||
9 | import org.eclipse.collections.impl.map.mutable.primitive.IntIntHashMap; | 11 | import org.eclipse.collections.impl.map.mutable.primitive.IntIntHashMap; |
10 | import org.eclipse.collections.impl.map.mutable.primitive.LongObjectHashMap; | 12 | import org.eclipse.collections.impl.map.mutable.primitive.LongObjectHashMap; |
11 | import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet; | 13 | import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet; |
@@ -23,7 +25,8 @@ 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) { |
@@ -34,7 +37,8 @@ public class StateEquivalenceCheckerImpl implements StateEquivalenceChecker { | |||
34 | IntIntHashMap object2PermutationGroup = new IntIntHashMap(); | 37 | IntIntHashMap object2PermutationGroup = new IntIntHashMap(); |
35 | List<List<IntIntMap>> permutationsGroups = new ArrayList<>(); | 38 | List<List<IntIntMap>> permutationsGroups = new ArrayList<>(); |
36 | 39 | ||
37 | final EquivalenceResult permutations = constructPermutationNavigation(indexByHash(code1), indexByHash(code2), | 40 | final EquivalenceResult permutations = constructPermutationNavigation(individuals, |
41 | indexByHash(code1, individuals), indexByHash(code2, individuals), | ||
38 | object2PermutationGroup, permutationsGroups); | 42 | object2PermutationGroup, permutationsGroups); |
39 | 43 | ||
40 | if (permutations == EquivalenceResult.DIFFERENT) { | 44 | if (permutations == EquivalenceResult.DIFFERENT) { |
@@ -60,24 +64,27 @@ public class StateEquivalenceCheckerImpl implements StateEquivalenceChecker { | |||
60 | return EquivalenceResult.DIFFERENT; | 64 | return EquivalenceResult.DIFFERENT; |
61 | } | 65 | } |
62 | 66 | ||
63 | private LongObjectHashMap<IntHashSet> indexByHash(ObjectCode code) { | 67 | private LongObjectHashMap<IntHashSet> indexByHash(ObjectCode code, IntSet individuals) { |
64 | LongObjectHashMap<IntHashSet> result = new LongObjectHashMap<>(); | 68 | LongObjectHashMap<IntHashSet> result = new LongObjectHashMap<>(); |
65 | for (int o = 0; o < code.getSize(); o++) { | 69 | for (int o = 0; o < code.getSize(); o++) { |
66 | long hash = code.get(o); | 70 | if(! individuals.contains(o)){ |
67 | var equivalenceClass = result.get(hash); | 71 | long hash = code.get(o); |
68 | if (equivalenceClass == null) { | 72 | var equivalenceClass = result.get(hash); |
69 | equivalenceClass = new IntHashSet(); | 73 | if (equivalenceClass == null) { |
70 | result.put(hash, equivalenceClass); | 74 | equivalenceClass = new IntHashSet(); |
75 | result.put(hash, equivalenceClass); | ||
76 | } | ||
77 | equivalenceClass.add(o); | ||
71 | } | 78 | } |
72 | equivalenceClass.add(o); | ||
73 | } | 79 | } |
74 | return result; | 80 | return result; |
75 | } | 81 | } |
76 | 82 | ||
77 | private EquivalenceResult constructPermutationNavigation(LongObjectHashMap<IntHashSet> map1, | 83 | private EquivalenceResult constructPermutationNavigation(IntSet individuals, |
78 | LongObjectHashMap<IntHashSet> map2, | 84 | LongObjectHashMap<IntHashSet> map1, |
79 | IntIntHashMap emptyMapToListOfOptions, | 85 | LongObjectHashMap<IntHashSet> map2, |
80 | List<List<IntIntMap>> emptyListOfOptions) { | 86 | IntIntHashMap object2OptionIndex, |
87 | List<List<IntIntMap>> listOfOptions) { | ||
81 | if (map1.size() != map2.size()) { | 88 | if (map1.size() != map2.size()) { |
82 | return EquivalenceResult.DIFFERENT; | 89 | return EquivalenceResult.DIFFERENT; |
83 | } | 90 | } |
@@ -101,10 +108,13 @@ public class StateEquivalenceCheckerImpl implements StateEquivalenceChecker { | |||
101 | 108 | ||
102 | allComplete &= pairing.isComplete(); | 109 | allComplete &= pairing.isComplete(); |
103 | 110 | ||
104 | final int optionIndex = emptyListOfOptions.size(); | 111 | final int optionIndex = listOfOptions.size(); |
105 | set1.forEach(key -> emptyMapToListOfOptions.put(key, optionIndex)); | 112 | set1.forEach(key -> object2OptionIndex.put(key, optionIndex)); |
106 | emptyListOfOptions.add(pairing.permutations()); | 113 | listOfOptions.add(pairing.permutations()); |
107 | } | 114 | } |
115 | |||
116 | individuals.forEach(o -> listOfOptions.add(o,List.of(IntIntMaps.immutable.of(o,o)))); | ||
117 | |||
108 | if(allComplete) { | 118 | if(allComplete) { |
109 | return EquivalenceResult.ISOMORPHIC; | 119 | return EquivalenceResult.ISOMORPHIC; |
110 | } else { | 120 | } else { |
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..a4e953ea 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(); |
@@ -68,6 +68,51 @@ class StateCoderBuildTest { | |||
68 | assertEquals(code,stateCoder.calculateStateCode().modelCode()); | 68 | assertEquals(code,stateCoder.calculateStateCode().modelCode()); |
69 | } | 69 | } |
70 | 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(); | ||
85 | |||
86 | friendI.put(Tuple.of(1,2),false); | ||
87 | friendI.put(Tuple.of(2,1),true); | ||
88 | int code2 = stateCoder.calculateModelCode(); | ||
89 | |||
90 | assertEquals(code1,code2); | ||
91 | } | ||
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 | |||
71 | private static void fill(Interpretation<Boolean> personI, Interpretation<Boolean> friendI, Interpretation<Integer> ageI) { | 116 | private static void fill(Interpretation<Boolean> personI, Interpretation<Boolean> friendI, Interpretation<Integer> ageI) { |
72 | personI.put(Tuple.of(1), true); | 117 | personI.put(Tuple.of(1), true); |
73 | personI.put(Tuple.of(2), true); | 118 | personI.put(Tuple.of(2), true); |