aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed')
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java111
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/ModelSeed.java95
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java59
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/SeedInitializer.java28
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java27
5 files changed, 293 insertions, 27 deletions
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java
new file mode 100644
index 00000000..8b1c3bb3
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/MapBasedSeed.java
@@ -0,0 +1,111 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.seed;
7
8import tools.refinery.store.map.Cursor;
9import tools.refinery.store.map.Cursors;
10import tools.refinery.store.tuple.Tuple;
11
12import java.util.Map;
13import java.util.Objects;
14
15record MapBasedSeed<T>(int arity, Class<T> valueType, T reducedValue, Map<Tuple, T> map) implements Seed<T> {
16 @Override
17 public T get(Tuple key) {
18 var value = map.get(key);
19 return value == null ? reducedValue : value;
20 }
21
22 @Override
23 public Cursor<Tuple, T> getCursor(T defaultValue, int nodeCount) {
24 if (Objects.equals(defaultValue, reducedValue)) {
25 return Cursors.of(map);
26 }
27 return new CartesianProductCursor<>(arity, nodeCount, reducedValue, defaultValue, map);
28 }
29
30 private static class CartesianProductCursor<T> implements Cursor<Tuple, T> {
31 private final int nodeCount;
32 private final T reducedValue;
33 private final T defaultValue;
34 private final Map<Tuple, T> map;
35 private final int[] counter;
36 private State state = State.INITIAL;
37 private Tuple key;
38 private T value;
39
40 private CartesianProductCursor(int arity, int nodeCount, T reducedValue, T defaultValue, Map<Tuple, T> map) {
41 this.nodeCount = nodeCount;
42 this.reducedValue = reducedValue;
43 this.defaultValue = defaultValue;
44 this.map = map;
45 counter = new int[arity];
46 }
47
48 @Override
49 public Tuple getKey() {
50 return key;
51 }
52
53 @Override
54 public T getValue() {
55 return value;
56 }
57
58 @Override
59 public boolean isTerminated() {
60 return state == State.TERMINATED;
61 }
62
63 @Override
64 public boolean move() {
65 return switch (state) {
66 case INITIAL -> {
67 state = State.STARTED;
68 yield checkValue() || moveToNext();
69 }
70 case STARTED -> moveToNext();
71 case TERMINATED -> false;
72 };
73 }
74
75 private boolean moveToNext() {
76 do {
77 increment();
78 } while (state != State.TERMINATED && !checkValue());
79 return state != State.TERMINATED;
80 }
81
82 private void increment() {
83 int i = counter.length - 1;
84 while (i >= 0) {
85 counter[i]++;
86 if (counter[i] < nodeCount) {
87 return;
88 }
89 counter[i] = 0;
90 i--;
91 }
92 state = State.TERMINATED;
93 }
94
95 private boolean checkValue() {
96 key = Tuple.of(counter);
97 var valueInMap = map.get(key);
98 if (Objects.equals(valueInMap, defaultValue)) {
99 return false;
100 }
101 value = valueInMap == null ? reducedValue : valueInMap;
102 return true;
103 }
104
105 private enum State {
106 INITIAL,
107 STARTED,
108 TERMINATED
109 }
110 }
111}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/ModelSeed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/ModelSeed.java
new file mode 100644
index 00000000..e6b3eaf9
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/ModelSeed.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 */
6package tools.refinery.store.reasoning.seed;
7
8import tools.refinery.store.map.Cursor;
9import tools.refinery.store.reasoning.representation.AnyPartialSymbol;
10import tools.refinery.store.reasoning.representation.PartialSymbol;
11import tools.refinery.store.tuple.Tuple;
12
13import java.util.Collections;
14import java.util.LinkedHashMap;
15import java.util.Map;
16import java.util.Set;
17import java.util.function.Consumer;
18
19public class ModelSeed {
20 private final int nodeCount;
21 private final Map<AnyPartialSymbol, Seed<?>> seeds;
22
23 private ModelSeed(int nodeCount, Map<AnyPartialSymbol, Seed<?>> seeds) {
24 this.nodeCount = nodeCount;
25 this.seeds = seeds;
26 }
27
28 public int getNodeCount() {
29 return nodeCount;
30 }
31
32 public <A> Seed<A> getSeed(PartialSymbol<A, ?> partialSymbol) {
33 var seed = seeds.get(partialSymbol);
34 if (seed == null) {
35 throw new IllegalArgumentException("No seed for partial symbol " + partialSymbol);
36 }
37 // The builder makes sure only well-typed seeds can be added.
38 @SuppressWarnings("unchecked")
39 var typedSeed = (Seed<A>) seed;
40 return typedSeed;
41 }
42
43 public boolean containsSeed(AnyPartialSymbol symbol) {
44 return seeds.containsKey(symbol);
45 }
46
47 public Set<AnyPartialSymbol> getSeededSymbols() {
48 return Collections.unmodifiableSet(seeds.keySet());
49 }
50
51 public <A> Cursor<Tuple, A> getCursor(PartialSymbol<A, ?> partialSymbol, A defaultValue) {
52 return getSeed(partialSymbol).getCursor(defaultValue, nodeCount);
53 }
54
55 public static Builder builder(int nodeCount) {
56 return new Builder(nodeCount);
57 }
58
59 public static class Builder {
60 private final int nodeCount;
61 private final Map<AnyPartialSymbol, Seed<?>> seeds = new LinkedHashMap<>();
62
63 private Builder(int nodeCount) {
64 if (nodeCount < 0) {
65 throw new IllegalArgumentException("Node count must not be negative");
66 }
67 this.nodeCount = nodeCount;
68 }
69
70 public <A> Builder seed(PartialSymbol<A, ?> partialSymbol, Seed<A> seed) {
71 if (seed.arity() != partialSymbol.arity()) {
72 throw new IllegalStateException("Expected seed of arity %d for partial symbol %s, but got %d instead"
73 .formatted(partialSymbol.arity(), partialSymbol, seed.arity()));
74 }
75 if (!seed.valueType().equals(partialSymbol.abstractDomain().abstractType())) {
76 throw new IllegalStateException("Expected seed of type %s for partial symbol %s, but got %s instead"
77 .formatted(partialSymbol.abstractDomain().abstractType(), partialSymbol, seed.valueType()));
78 }
79 if (seeds.put(partialSymbol, seed) != null) {
80 throw new IllegalArgumentException("Duplicate seed for partial symbol " + partialSymbol);
81 }
82 return this;
83 }
84
85 public <A> Builder seed(PartialSymbol<A, ?> partialSymbol, Consumer<Seed.Builder<A>> callback) {
86 var builder = Seed.builder(partialSymbol);
87 callback.accept(builder);
88 return seed(partialSymbol, builder.build());
89 }
90
91 public ModelSeed build() {
92 return new ModelSeed(nodeCount, Collections.unmodifiableMap(seeds));
93 }
94 }
95}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java
index 08079f12..732efbcc 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java
@@ -6,14 +6,73 @@
6package tools.refinery.store.reasoning.seed; 6package tools.refinery.store.reasoning.seed;
7 7
8import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
9import tools.refinery.store.reasoning.representation.PartialSymbol;
10import tools.refinery.store.representation.Symbol;
9import tools.refinery.store.tuple.Tuple; 11import tools.refinery.store.tuple.Tuple;
10 12
13import java.util.Collections;
14import java.util.LinkedHashMap;
15import java.util.Map;
16
11public interface Seed<T> { 17public interface Seed<T> {
12 int arity(); 18 int arity();
13 19
20 Class<T> valueType();
21
14 T reducedValue(); 22 T reducedValue();
15 23
16 T get(Tuple key); 24 T get(Tuple key);
17 25
18 Cursor<Tuple, T> getCursor(T defaultValue, int nodeCount); 26 Cursor<Tuple, T> getCursor(T defaultValue, int nodeCount);
27
28 static <T> Builder<T> builder(int arity, Class<T> valueType, T reducedValue) {
29 return new Builder<>(arity, valueType, reducedValue);
30 }
31
32 static <T> Builder<T> builder(Symbol<T> symbol) {
33 return builder(symbol.arity(), symbol.valueType(), symbol.defaultValue());
34 }
35
36 static <T> Builder<T> builder(PartialSymbol<T, ?> partialSymbol) {
37 return builder(partialSymbol.arity(), partialSymbol.abstractDomain().abstractType(),
38 partialSymbol.defaultValue());
39 }
40
41 @SuppressWarnings("UnusedReturnValue")
42 class Builder<T> {
43 private final int arity;
44 private final Class<T> valueType;
45 private T reducedValue;
46 private final Map<Tuple, T> map = new LinkedHashMap<>();
47
48 private Builder(int arity, Class<T> valueType, T reducedValue) {
49 this.arity = arity;
50 this.valueType = valueType;
51 this.reducedValue = reducedValue;
52 }
53
54 public Builder<T> reducedValue(T reducedValue) {
55 this.reducedValue = reducedValue;
56 return this;
57 }
58
59 public Builder<T> put(Tuple key, T value) {
60 if (key.getSize() != arity) {
61 throw new IllegalArgumentException("Expected %s to have %d elements".formatted(key, arity));
62 }
63 map.put(key, value);
64 return this;
65 }
66
67 public Builder<T> putAll(Map<Tuple, T> map) {
68 for (var entry : map.entrySet()) {
69 put(entry.getKey(), entry.getValue());
70 }
71 return this;
72 }
73
74 public Seed<T> build() {
75 return new MapBasedSeed<>(arity, valueType, reducedValue, Collections.unmodifiableMap(map));
76 }
77 }
19} 78}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/SeedInitializer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/SeedInitializer.java
new file mode 100644
index 00000000..9af457d8
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/SeedInitializer.java
@@ -0,0 +1,28 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.seed;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.reasoning.refinement.PartialModelInitializer;
10import tools.refinery.store.reasoning.representation.PartialSymbol;
11import tools.refinery.store.representation.Symbol;
12
13public class SeedInitializer<T> implements PartialModelInitializer {
14 private final Symbol<T> symbol;
15 private final PartialSymbol<T, ?> partialSymbol;
16
17 public SeedInitializer(Symbol<T> symbol, PartialSymbol<T, ?> partialSymbol) {
18 this.symbol = symbol;
19 this.partialSymbol = partialSymbol;
20 }
21
22 @Override
23 public void initialize(Model model, ModelSeed modelSeed) {
24 var interpretation = model.getInterpretation(symbol);
25 var cursor = modelSeed.getCursor(partialSymbol, symbol.defaultValue());
26 interpretation.putAll(cursor);
27 }
28}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java
deleted file mode 100644
index 451d1513..00000000
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java
+++ /dev/null
@@ -1,27 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.seed;
7
8import tools.refinery.store.map.Cursor;
9import tools.refinery.store.tuple.Tuple;
10
11public record UniformSeed<T>(int arity, T reducedValue) implements Seed<T> {
12 public UniformSeed {
13 if (arity < 0) {
14 throw new IllegalArgumentException("Arity must not be negative");
15 }
16 }
17
18 @Override
19 public T get(Tuple key) {
20 return reducedValue;
21 }
22
23 @Override
24 public Cursor<Tuple, T> getCursor(T defaultValue, int nodeCount) {
25 return null;
26 }
27}