diff options
author | 2023-07-29 16:16:02 +0200 | |
---|---|---|
committer | 2023-07-29 16:16:02 +0200 | |
commit | 64f8706af45647b3015abc1bb1378c6be22a515c (patch) | |
tree | a4b776a846634d69f6a256eb4755f62abd1bb248 /subprojects/store/src/main/java/tools | |
parent | Merge pull request #31 from OszkarSemerath/datastructure (diff) | |
download | refinery-64f8706af45647b3015abc1bb1378c6be22a515c.tar.gz refinery-64f8706af45647b3015abc1bb1378c6be22a515c.tar.zst refinery-64f8706af45647b3015abc1bb1378c6be22a515c.zip |
Initial prototype of the StateCoderAdapter based on NeighbourhoodCalculator.
No tests yet.
Diffstat (limited to 'subprojects/store/src/main/java/tools')
9 files changed, 378 insertions, 0 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculator.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculator.java new file mode 100644 index 00000000..479b61ed --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCodeCalculator.java | |||
@@ -0,0 +1,10 @@ | |||
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 | public interface StateCodeCalculator { | ||
9 | |||
10 | } | ||
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderAdapter.java new file mode 100644 index 00000000..8795fb68 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderAdapter.java | |||
@@ -0,0 +1,12 @@ | |||
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 tools.refinery.store.adapter.ModelAdapter; | ||
9 | |||
10 | public interface StateCoderAdapter extends ModelAdapter { | ||
11 | int calculateHashCode(); | ||
12 | } | ||
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 new file mode 100644 index 00000000..2f37584f --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderBuilder.java | |||
@@ -0,0 +1,29 @@ | |||
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 tools.refinery.store.adapter.ModelAdapterBuilder; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.representation.AnySymbol; | ||
11 | |||
12 | import java.util.Collection; | ||
13 | import java.util.List; | ||
14 | |||
15 | public interface StateCoderBuilder extends ModelAdapterBuilder { | ||
16 | StateCoderBuilder exclude(AnySymbol symbol); | ||
17 | default StateCoderBuilder excludeAll(Collection<? extends AnySymbol> symbols) { | ||
18 | for(var symbol : symbols) { | ||
19 | exclude(symbol); | ||
20 | } | ||
21 | return this; | ||
22 | } | ||
23 | default StateCoderBuilder excludeAll(AnySymbol... symbols) { | ||
24 | return excludeAll(List.of(symbols)); | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | StateCoderStoreAdapter build(ModelStore store); | ||
29 | } | ||
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderStoreAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderStoreAdapter.java new file mode 100644 index 00000000..5946a162 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/StateCoderStoreAdapter.java | |||
@@ -0,0 +1,14 @@ | |||
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 tools.refinery.store.adapter.ModelStoreAdapter; | ||
9 | import tools.refinery.store.model.Model; | ||
10 | |||
11 | public interface StateCoderStoreAdapter extends ModelStoreAdapter { | ||
12 | @Override | ||
13 | StateCoderAdapter createModelAdapter(Model model); | ||
14 | } | ||
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 new file mode 100644 index 00000000..689db2e3 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderAdapterImpl.java | |||
@@ -0,0 +1,47 @@ | |||
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.internal; | ||
7 | |||
8 | import tools.refinery.store.adapter.ModelStoreAdapter; | ||
9 | import tools.refinery.store.model.Interpretation; | ||
10 | import tools.refinery.store.model.Model; | ||
11 | import tools.refinery.store.representation.Symbol; | ||
12 | import tools.refinery.store.statecoding.StateCoderAdapter; | ||
13 | import tools.refinery.store.statecoding.neighbourhood.NeighbourhoodCalculator; | ||
14 | |||
15 | import java.util.Collection; | ||
16 | import java.util.List; | ||
17 | |||
18 | public class StateCoderAdapterImpl implements StateCoderAdapter { | ||
19 | final ModelStoreAdapter storeAdapter; | ||
20 | final Model model; | ||
21 | final NeighbourhoodCalculator calculator; | ||
22 | |||
23 | StateCoderAdapterImpl(ModelStoreAdapter storeAdapter, Model model, Collection<Symbol<?>> symbols) { | ||
24 | this.storeAdapter = storeAdapter; | ||
25 | this.model = model; | ||
26 | |||
27 | List<? extends Interpretation<?>> interpretations = symbols.stream().map(model::getInterpretation).toList(); | ||
28 | calculator = new NeighbourhoodCalculator(interpretations); | ||
29 | } | ||
30 | |||
31 | @Override | ||
32 | public Model getModel() { | ||
33 | return model; | ||
34 | } | ||
35 | |||
36 | @Override | ||
37 | public ModelStoreAdapter getStoreAdapter() { | ||
38 | return storeAdapter; | ||
39 | } | ||
40 | |||
41 | @Override | ||
42 | public int calculateHashCode() { | ||
43 | return calculator.calculate(); | ||
44 | } | ||
45 | |||
46 | |||
47 | } | ||
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 new file mode 100644 index 00000000..700723f4 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderBuilderImpl.java | |||
@@ -0,0 +1,48 @@ | |||
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.internal; | ||
7 | |||
8 | import tools.refinery.store.model.ModelStore; | ||
9 | import tools.refinery.store.model.ModelStoreBuilder; | ||
10 | import tools.refinery.store.representation.AnySymbol; | ||
11 | import tools.refinery.store.representation.Symbol; | ||
12 | import tools.refinery.store.statecoding.StateCoderBuilder; | ||
13 | import tools.refinery.store.statecoding.StateCoderStoreAdapter; | ||
14 | |||
15 | import java.util.HashSet; | ||
16 | import java.util.LinkedHashSet; | ||
17 | import java.util.Set; | ||
18 | |||
19 | public class StateCoderBuilderImpl implements StateCoderBuilder { | ||
20 | Set<AnySymbol> excluded = new HashSet<>(); | ||
21 | |||
22 | @Override | ||
23 | public StateCoderBuilder exclude(AnySymbol symbol) { | ||
24 | excluded.add(symbol); | ||
25 | return this; | ||
26 | } | ||
27 | |||
28 | @Override | ||
29 | public boolean isConfigured() { | ||
30 | return true; | ||
31 | } | ||
32 | |||
33 | @Override | ||
34 | public void configure(ModelStoreBuilder storeBuilder) { | ||
35 | // It does not modify the build process | ||
36 | } | ||
37 | |||
38 | @Override | ||
39 | public StateCoderStoreAdapter build(ModelStore store) { | ||
40 | Set<Symbol<?>> symbols = new LinkedHashSet<>(); | ||
41 | for (AnySymbol symbol : store.getSymbols()) { | ||
42 | if (!excluded.contains(symbol) && (symbol instanceof Symbol<?> typed)) { | ||
43 | symbols.add(typed); | ||
44 | } | ||
45 | } | ||
46 | return new StateCoderStoreAdapterImpl(store, symbols); | ||
47 | } | ||
48 | } | ||
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 new file mode 100644 index 00000000..77d36e96 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/internal/StateCoderStoreAdapterImpl.java | |||
@@ -0,0 +1,34 @@ | |||
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.internal; | ||
7 | |||
8 | import tools.refinery.store.model.Model; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.representation.Symbol; | ||
11 | import tools.refinery.store.statecoding.StateCoderAdapter; | ||
12 | import tools.refinery.store.statecoding.StateCoderStoreAdapter; | ||
13 | |||
14 | import java.util.Collection; | ||
15 | |||
16 | public class StateCoderStoreAdapterImpl implements StateCoderStoreAdapter { | ||
17 | final ModelStore store; | ||
18 | final Collection<Symbol<?>> symbols; | ||
19 | |||
20 | StateCoderStoreAdapterImpl(ModelStore store, Collection<Symbol<?>> symbols) { | ||
21 | this.store = store; | ||
22 | this.symbols = symbols; | ||
23 | } | ||
24 | |||
25 | @Override | ||
26 | public ModelStore getStore() { | ||
27 | return store; | ||
28 | } | ||
29 | |||
30 | @Override | ||
31 | public StateCoderAdapter createModelAdapter(Model model) { | ||
32 | return new StateCoderAdapterImpl(this,model,symbols); | ||
33 | } | ||
34 | } | ||
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 new file mode 100644 index 00000000..24a7122e --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/NeighbourhoodCalculator.java | |||
@@ -0,0 +1,129 @@ | |||
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.tuple.Tuple; | ||
12 | import tools.refinery.store.tuple.Tuple0; | ||
13 | |||
14 | import java.util.ArrayList; | ||
15 | import java.util.LinkedHashMap; | ||
16 | import java.util.List; | ||
17 | import java.util.Random; | ||
18 | |||
19 | public class NeighbourhoodCalculator { | ||
20 | final List<Interpretation<?>> nullImpactValues; | ||
21 | final LinkedHashMap<Interpretation<?>, long[]> impactValues; | ||
22 | |||
23 | public NeighbourhoodCalculator(List<? extends Interpretation<?>> interpretations) { | ||
24 | this.nullImpactValues = new ArrayList<>(); | ||
25 | this.impactValues = new LinkedHashMap<>(); | ||
26 | Random random = new Random(1); | ||
27 | |||
28 | for (Interpretation<?> interpretation : interpretations) { | ||
29 | int arity = interpretation.getSymbol().arity(); | ||
30 | if (arity == 0) { | ||
31 | nullImpactValues.add(interpretation); | ||
32 | } else { | ||
33 | long[] impact = new long[arity]; | ||
34 | for (int i = 0; i < arity; i++) { | ||
35 | impact[i] = random.nextLong(); | ||
36 | } | ||
37 | impactValues.put(interpretation, impact); | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | |||
42 | public int calculate() { | ||
43 | ObjectCode previous = new ObjectCode(); | ||
44 | ObjectCode next = new ObjectCode(); | ||
45 | |||
46 | int previousSize = 1; | ||
47 | long lastSum; | ||
48 | boolean grows; | ||
49 | |||
50 | do{ | ||
51 | for (var impactValueEntry : this.impactValues.entrySet()) { | ||
52 | Interpretation<?> interpretation = impactValueEntry.getKey(); | ||
53 | long[] impact = impactValueEntry.getValue(); | ||
54 | var cursor = interpretation.getAll(); | ||
55 | while (cursor.move()) { | ||
56 | Tuple tuple = cursor.getKey(); | ||
57 | Object value = cursor.getValue(); | ||
58 | long tupleHash = getTupleHash(tuple, value, previous); | ||
59 | addHash(next, tuple, impact, tupleHash); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | previous = next; | ||
64 | next = null; | ||
65 | lastSum = 0; | ||
66 | MutableLongSet codes = new LongHashSet(); | ||
67 | for (int i = 0; i < previous.getSize(); i++) { | ||
68 | long objectHash = previous.get(i); | ||
69 | codes.add(objectHash); | ||
70 | |||
71 | final long shifted1 = objectHash>>> 32; | ||
72 | final long shifted2 = objectHash << 32; | ||
73 | lastSum += shifted1 + shifted2; | ||
74 | } | ||
75 | int nextSize = codes.size(); | ||
76 | grows = previousSize < nextSize; | ||
77 | previousSize = nextSize; | ||
78 | |||
79 | if(grows) { | ||
80 | next = new ObjectCode(previous); | ||
81 | } | ||
82 | } while (grows); | ||
83 | |||
84 | long result = 1; | ||
85 | for (var nullImpactValue : nullImpactValues) { | ||
86 | result = result * 31 + nullImpactValue.get(Tuple0.INSTANCE).hashCode(); | ||
87 | } | ||
88 | result += lastSum; | ||
89 | |||
90 | return (int) result; | ||
91 | } | ||
92 | |||
93 | protected long getTupleHash(Tuple tuple, Object value, ObjectCode objectCode) { | ||
94 | long result = (long) value; | ||
95 | int arity = tuple.getSize(); | ||
96 | if (arity == 1) { | ||
97 | result = result * 31 + objectCode.get(tuple.get(0)); | ||
98 | } else if (arity == 2) { | ||
99 | result = result * 31 + objectCode.get(tuple.get(0)); | ||
100 | result = result * 31 + objectCode.get(tuple.get(1)); | ||
101 | if (tuple.get(0) == tuple.get(1)) { | ||
102 | result++; | ||
103 | } | ||
104 | } else if (arity > 2) { | ||
105 | for (int i = 0; i < arity; i++) { | ||
106 | result = result * 31 + objectCode.get(tuple.get(i)); | ||
107 | } | ||
108 | } | ||
109 | return result; | ||
110 | } | ||
111 | |||
112 | protected void addHash(ObjectCode objectCode, Tuple tuple, long[] impact, long tupleHashCode) { | ||
113 | if (tuple.getSize() == 1) { | ||
114 | addHash(objectCode, tuple.get(0), impact[0], tupleHashCode); | ||
115 | } else if (tuple.getSize() == 2) { | ||
116 | addHash(objectCode, tuple.get(0), impact[0], tupleHashCode); | ||
117 | addHash(objectCode, tuple.get(1), impact[1], tupleHashCode); | ||
118 | } else if (tuple.getSize() > 2) { | ||
119 | for (int i = 0; i < tuple.getSize(); i++) { | ||
120 | addHash(objectCode, tuple.get(i), impact[i], tupleHashCode); | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | |||
125 | protected void addHash(ObjectCode objectCode, int o, long impact, long tupleHash) { | ||
126 | objectCode.set(o, objectCode.get(o) + tupleHash * impact); | ||
127 | } | ||
128 | |||
129 | } | ||
diff --git a/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/ObjectCode.java b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/ObjectCode.java new file mode 100644 index 00000000..594d2b3a --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/statecoding/neighbourhood/ObjectCode.java | |||
@@ -0,0 +1,55 @@ | |||
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 | public class ObjectCode { | ||
9 | private long[] vector; | ||
10 | private int size; | ||
11 | |||
12 | public ObjectCode() { | ||
13 | vector = new long[10]; | ||
14 | size = 0; | ||
15 | } | ||
16 | |||
17 | public ObjectCode(ObjectCode sameSize) { | ||
18 | this.vector = new long[sameSize.size]; | ||
19 | this.size = sameSize.size; | ||
20 | } | ||
21 | |||
22 | private void ensureSize(int object) { | ||
23 | if(object >= size) { | ||
24 | size = object+1; | ||
25 | } | ||
26 | |||
27 | if(object >= vector.length) { | ||
28 | int newLength = vector.length*2; | ||
29 | while(object >= newLength) { | ||
30 | newLength*=2; | ||
31 | } | ||
32 | |||
33 | long[] newVector = new long[newLength]; | ||
34 | System.arraycopy(vector, 0, newVector, 0, vector.length); | ||
35 | this.vector = newVector; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | public long get(int object) { | ||
40 | if(object < vector.length) { | ||
41 | return vector[object]; | ||
42 | } else { | ||
43 | return 0; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | public void set(int object, long value) { | ||
48 | ensureSize(object); | ||
49 | vector[object]=value; | ||
50 | } | ||
51 | |||
52 | public int getSize() { | ||
53 | return this.size; | ||
54 | } | ||
55 | } | ||