diff options
Diffstat (limited to 'store/src/main/java/org/eclipse/viatra/solver/data/query')
20 files changed, 1308 insertions, 0 deletions
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/RelationalScope.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/RelationalScope.java new file mode 100644 index 00000000..97b33935 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/RelationalScope.java | |||
@@ -0,0 +1,34 @@ | |||
1 | package org.eclipse.viatra.solver.data.query; | ||
2 | |||
3 | import java.util.Set; | ||
4 | |||
5 | import org.apache.log4j.Logger; | ||
6 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
7 | import org.eclipse.viatra.query.runtime.api.scope.IEngineContext; | ||
8 | import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener; | ||
9 | import org.eclipse.viatra.query.runtime.api.scope.QueryScope; | ||
10 | import org.eclipse.viatra.solver.data.model.Model; | ||
11 | import org.eclipse.viatra.solver.data.model.Tuple; | ||
12 | import org.eclipse.viatra.solver.data.query.internal.RelationUpdateListener; | ||
13 | import org.eclipse.viatra.solver.data.query.internal.RelationalEngineContext; | ||
14 | import org.eclipse.viatra.solver.data.query.view.RelationView; | ||
15 | |||
16 | public class RelationalScope extends QueryScope{ | ||
17 | private final Model model; | ||
18 | private final RelationUpdateListener updateListener; | ||
19 | |||
20 | public RelationalScope(Model model, Set<RelationView<?>> relationViews) { | ||
21 | this.model = model; | ||
22 | updateListener = new RelationUpdateListener(relationViews); | ||
23 | } | ||
24 | |||
25 | public <D> void processUpdate(RelationView<D> relationView, Tuple key, D oldValue, D newValue) { | ||
26 | updateListener.processChange(relationView, key, oldValue, newValue); | ||
27 | } | ||
28 | |||
29 | @Override | ||
30 | protected IEngineContext createEngineContext(ViatraQueryEngine engine, IIndexingErrorListener errorListener, | ||
31 | Logger logger) { | ||
32 | return new RelationalEngineContext(model, updateListener); | ||
33 | } | ||
34 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/building/DNFAnd.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/DNFAnd.java new file mode 100644 index 00000000..ff5a7848 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/DNFAnd.java | |||
@@ -0,0 +1,37 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.building; | ||
2 | |||
3 | import java.util.HashMap; | ||
4 | import java.util.HashSet; | ||
5 | import java.util.List; | ||
6 | import java.util.Map; | ||
7 | import java.util.Set; | ||
8 | |||
9 | public class DNFAnd { | ||
10 | private Set<Variable> existentiallyQuantified; | ||
11 | private List<DNFAtom> constraints; | ||
12 | public DNFAnd(Set<Variable> quantifiedVariables, List<DNFAtom> constraints) { | ||
13 | super(); | ||
14 | this.existentiallyQuantified = quantifiedVariables; | ||
15 | this.constraints = constraints; | ||
16 | } | ||
17 | public Set<Variable> getExistentiallyQuantified() { | ||
18 | return existentiallyQuantified; | ||
19 | } | ||
20 | public List<DNFAtom> getConstraints() { | ||
21 | return constraints; | ||
22 | } | ||
23 | void unifyVariables(Map<String,Variable> uniqueVariableMap) { | ||
24 | Map<String,Variable> uniqueVariableMapForClause = new HashMap<>(uniqueVariableMap); | ||
25 | for(DNFAtom atom : constraints) { | ||
26 | atom.unifyVariables(uniqueVariableMapForClause); | ||
27 | } | ||
28 | } | ||
29 | void collectQuantifiedVariables(Set<Variable> parameters) { | ||
30 | Set<Variable> result = new HashSet<>(); | ||
31 | for(DNFAtom constraint : constraints) { | ||
32 | constraint.collectAllVariables(result); | ||
33 | } | ||
34 | result.removeAll(parameters); | ||
35 | existentiallyQuantified = result; | ||
36 | } | ||
37 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/building/DNFAtom.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/DNFAtom.java new file mode 100644 index 00000000..05a3e3f8 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/DNFAtom.java | |||
@@ -0,0 +1,33 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.building; | ||
2 | |||
3 | import java.util.Collection; | ||
4 | import java.util.Iterator; | ||
5 | import java.util.Map; | ||
6 | import java.util.Set; | ||
7 | |||
8 | public interface DNFAtom { | ||
9 | void unifyVariables(Map<String,Variable> variables); | ||
10 | static Variable unifyVariables(Map<String,Variable> unifiedVariables, Variable variable) { | ||
11 | if(variable != null) { | ||
12 | if(variable.isNamed() && unifiedVariables.containsKey(variable.getName())) { | ||
13 | return unifiedVariables.get(variable.getName()); | ||
14 | } | ||
15 | return variable; | ||
16 | } else { | ||
17 | return null; | ||
18 | } | ||
19 | } | ||
20 | void collectAllVariables(Set<Variable> variables); | ||
21 | static void addToCollection(Set<Variable> variables, Variable variable) { | ||
22 | if(variable != null) { | ||
23 | variables.add(variable); | ||
24 | } | ||
25 | } | ||
26 | static void addToCollection(Set<Variable> variables, Collection<Variable> variableCollection) { | ||
27 | Iterator<Variable> iterator = variableCollection.iterator(); | ||
28 | while(iterator.hasNext()) { | ||
29 | Variable variable = iterator.next(); | ||
30 | addToCollection(variables, variable); | ||
31 | } | ||
32 | } | ||
33 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/building/DNFPredicate.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/DNFPredicate.java new file mode 100644 index 00000000..8ee540ae --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/DNFPredicate.java | |||
@@ -0,0 +1,72 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.building; | ||
2 | |||
3 | import java.util.HashMap; | ||
4 | import java.util.HashSet; | ||
5 | import java.util.List; | ||
6 | import java.util.Map; | ||
7 | import java.util.UUID; | ||
8 | |||
9 | public class DNFPredicate { | ||
10 | private final String name; | ||
11 | private final String uniqueName; | ||
12 | private final List<Variable> parameters; | ||
13 | private final List<DNFAnd> clauses; | ||
14 | |||
15 | public DNFPredicate(String name, List<Variable> parameters, List<DNFAnd> clauses) { | ||
16 | this.name = name; | ||
17 | this.uniqueName = generateUniqueName(name,"predicate"); | ||
18 | this.parameters = parameters; | ||
19 | this.clauses = clauses; | ||
20 | |||
21 | postProcess(); | ||
22 | } | ||
23 | |||
24 | public static String generateUniqueName(String originalName, String defaultPrefix) { | ||
25 | UUID uuid = UUID.randomUUID(); | ||
26 | String uniqueString = uuid.toString().replace('-', '_'); | ||
27 | if(originalName == null) { | ||
28 | return defaultPrefix+uniqueString; | ||
29 | } else { | ||
30 | return originalName+uniqueString; | ||
31 | } | ||
32 | } | ||
33 | |||
34 | public String getName() { | ||
35 | return name; | ||
36 | } | ||
37 | public String getUniqueName() { | ||
38 | return uniqueName; | ||
39 | } | ||
40 | public List<Variable> getVariables() { | ||
41 | return parameters; | ||
42 | } | ||
43 | public List<DNFAnd> getClauses() { | ||
44 | return clauses; | ||
45 | } | ||
46 | |||
47 | public void unifyVariables() { | ||
48 | Map<String,Variable> uniqueVariableMap = new HashMap<>(); | ||
49 | for(Variable parameter : this.parameters) { | ||
50 | if(parameter.isNamed()) { | ||
51 | String parameterName = parameter.getName(); | ||
52 | if(uniqueVariableMap.containsKey(parameterName)) { | ||
53 | throw new IllegalArgumentException("Multiple parameters has the name "+parameterName); | ||
54 | } else { | ||
55 | uniqueVariableMap.put(parameterName, parameter); | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | for(DNFAnd clause : this.clauses) { | ||
60 | clause.unifyVariables(uniqueVariableMap); | ||
61 | } | ||
62 | } | ||
63 | public void collectQuantifiedVariables() { | ||
64 | for(DNFAnd clause : this.clauses) { | ||
65 | clause.collectQuantifiedVariables(new HashSet<>(parameters)); | ||
66 | } | ||
67 | } | ||
68 | public void postProcess() { | ||
69 | unifyVariables(); | ||
70 | collectQuantifiedVariables(); | ||
71 | } | ||
72 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/building/EquivalenceAtom.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/EquivalenceAtom.java new file mode 100644 index 00000000..b47fe2a8 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/EquivalenceAtom.java | |||
@@ -0,0 +1,44 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.building; | ||
2 | |||
3 | import java.util.Map; | ||
4 | import java.util.Set; | ||
5 | |||
6 | public class EquivalenceAtom implements DNFAtom{ | ||
7 | private boolean positive; | ||
8 | private Variable left; | ||
9 | private Variable right; | ||
10 | public EquivalenceAtom(boolean positive, Variable left, Variable right) { | ||
11 | this.positive = positive; | ||
12 | this.left = left; | ||
13 | this.right = right; | ||
14 | } | ||
15 | public boolean isPositive() { | ||
16 | return positive; | ||
17 | } | ||
18 | public void setPositive(boolean positive) { | ||
19 | this.positive = positive; | ||
20 | } | ||
21 | public Variable getLeft() { | ||
22 | return left; | ||
23 | } | ||
24 | public void setLeft(Variable left) { | ||
25 | this.left = left; | ||
26 | } | ||
27 | public Variable getRight() { | ||
28 | return right; | ||
29 | } | ||
30 | public void setRight(Variable right) { | ||
31 | this.right = right; | ||
32 | } | ||
33 | |||
34 | @Override | ||
35 | public void unifyVariables(Map<String, Variable> variables) { | ||
36 | this.left = DNFAtom.unifyVariables(variables,left); | ||
37 | this.right = DNFAtom.unifyVariables(variables,right); | ||
38 | } | ||
39 | @Override | ||
40 | public void collectAllVariables(Set<Variable> variables) { | ||
41 | DNFAtom.addToCollection(variables, left); | ||
42 | DNFAtom.addToCollection(variables, right); | ||
43 | } | ||
44 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/building/PredicateAtom.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/PredicateAtom.java new file mode 100644 index 00000000..3e5ef88e --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/PredicateAtom.java | |||
@@ -0,0 +1,57 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.building; | ||
2 | |||
3 | import java.util.List; | ||
4 | import java.util.Map; | ||
5 | import java.util.Set; | ||
6 | |||
7 | public class PredicateAtom implements DNFAtom{ | ||
8 | private DNFPredicate referred; | ||
9 | private List<Variable> substitution; | ||
10 | private boolean positive; | ||
11 | private boolean transitive; | ||
12 | |||
13 | public PredicateAtom(boolean positive, boolean transitive, DNFPredicate referred, List<Variable> substitution) { | ||
14 | this.positive = positive; | ||
15 | this.referred = referred; | ||
16 | this.substitution = substitution; | ||
17 | this.transitive = transitive; | ||
18 | } | ||
19 | public DNFPredicate getReferred() { | ||
20 | return referred; | ||
21 | } | ||
22 | public void setReferred(DNFPredicate referred) { | ||
23 | this.referred = referred; | ||
24 | } | ||
25 | public List<Variable> getSubstitution() { | ||
26 | return substitution; | ||
27 | } | ||
28 | public void setSubstitution(List<Variable> substitution) { | ||
29 | this.substitution = substitution; | ||
30 | } | ||
31 | public boolean isPositive() { | ||
32 | return positive; | ||
33 | } | ||
34 | public void setPositive(boolean positive) { | ||
35 | this.positive = positive; | ||
36 | } | ||
37 | public boolean isTransitive() { | ||
38 | return transitive; | ||
39 | } | ||
40 | public void setTransitive(boolean transitive) { | ||
41 | this.transitive = transitive; | ||
42 | } | ||
43 | @Override | ||
44 | public void unifyVariables(Map<String, Variable> variables) { | ||
45 | for(int i = 0; i<this.substitution.size(); i++) { | ||
46 | final Object term = this.substitution.get(i); | ||
47 | if(term instanceof Variable) { | ||
48 | Variable variableReference = (Variable) term; | ||
49 | this.substitution.set(i, DNFAtom.unifyVariables(variables, variableReference)); | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | @Override | ||
54 | public void collectAllVariables(Set<Variable> variables) { | ||
55 | DNFAtom.addToCollection(variables, substitution); | ||
56 | } | ||
57 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/building/PredicateBuilder_string.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/PredicateBuilder_string.java new file mode 100644 index 00000000..41f85d39 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/PredicateBuilder_string.java | |||
@@ -0,0 +1,107 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.building; | ||
2 | |||
3 | import java.util.ArrayList; | ||
4 | import java.util.Collections; | ||
5 | import java.util.HashSet; | ||
6 | import java.util.List; | ||
7 | |||
8 | import org.eclipse.viatra.solver.data.query.view.RelationView; | ||
9 | |||
10 | public class PredicateBuilder_string { | ||
11 | private PredicateBuilder_string() {} | ||
12 | |||
13 | public static PredicateBuild1 predicate(String name) { | ||
14 | return new PredicateBuild1(name); | ||
15 | } | ||
16 | public static class PredicateBuild1 { | ||
17 | private String name; | ||
18 | public PredicateBuild1(String name) { | ||
19 | this.name = name; | ||
20 | } | ||
21 | public PredicateBuild2 parameters(String... parameters) { | ||
22 | return new PredicateBuild2(name, parameters); | ||
23 | } | ||
24 | } | ||
25 | public static class PredicateBuild2 { | ||
26 | private String name; | ||
27 | private String[] parameters; | ||
28 | public PredicateBuild2(String name, String[] parameters) { | ||
29 | this.name = name; | ||
30 | this.parameters = parameters; | ||
31 | } | ||
32 | |||
33 | public PredicateBuild3 clause(DNFAtom...constraints) { | ||
34 | return new PredicateBuild3(name,parameters,List.<DNFAtom[]>of(constraints)); | ||
35 | } | ||
36 | } | ||
37 | public static class PredicateBuild3 { | ||
38 | String name; | ||
39 | String[] parameters; | ||
40 | List<DNFAtom[]> clauses; | ||
41 | public PredicateBuild3(String name, String[] parameters, List<DNFAtom[]> clauses) { | ||
42 | super(); | ||
43 | this.name = name; | ||
44 | this.parameters = parameters; | ||
45 | this.clauses = clauses; | ||
46 | } | ||
47 | |||
48 | public PredicateBuild3 clause(DNFAtom...constraints) { | ||
49 | List<DNFAtom[]> newClauses = new ArrayList<>(); | ||
50 | newClauses.addAll(clauses); | ||
51 | newClauses.add(constraints); | ||
52 | return new PredicateBuild3(name, parameters, newClauses); | ||
53 | } | ||
54 | public DNFPredicate build() { | ||
55 | List<Variable> newParameters = new ArrayList<>(this.parameters.length); | ||
56 | for(int i = 0; i<this.parameters.length; i++) { | ||
57 | newParameters.add(new Variable(parameters[i])); | ||
58 | } | ||
59 | |||
60 | List<DNFAnd> newClauses = new ArrayList<>(this.clauses.size()); | ||
61 | for(DNFAtom[] clause : this.clauses) { | ||
62 | List<DNFAtom> constraints = new ArrayList<>(clause.length); | ||
63 | Collections.addAll(constraints, clause); | ||
64 | newClauses.add(new DNFAnd(new HashSet<>(), constraints)); | ||
65 | } | ||
66 | |||
67 | return new DNFPredicate(name,newParameters,newClauses); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | private static Variable stringToVariable(String name) { | ||
72 | if(name != null) { | ||
73 | return new Variable(name); | ||
74 | } else { | ||
75 | return null; | ||
76 | } | ||
77 | } | ||
78 | private static List<Variable> stringToVariable(String[] names) { | ||
79 | List<Variable> variables = new ArrayList<>(); | ||
80 | for(int i = 0; i<names.length; i++) { | ||
81 | variables.add(stringToVariable(names[i])); | ||
82 | } | ||
83 | return variables; | ||
84 | } | ||
85 | |||
86 | public static EquivalenceAtom cEquals(String v1, String v2) { | ||
87 | return new EquivalenceAtom(true,stringToVariable(v1),stringToVariable(v2)); | ||
88 | } | ||
89 | public static EquivalenceAtom cNotEquals(String v1, String v2) { | ||
90 | return new EquivalenceAtom(false,stringToVariable(v1),stringToVariable(v2)); | ||
91 | } | ||
92 | |||
93 | public static RelationAtom cInRelation(RelationView<?> view, String... variables) { | ||
94 | |||
95 | return new RelationAtom(view, stringToVariable(variables)); | ||
96 | } | ||
97 | |||
98 | public static PredicateAtom cInPredicate(DNFPredicate referred, String... variables) { | ||
99 | return new PredicateAtom(true, false, referred, stringToVariable(variables)); | ||
100 | } | ||
101 | public static PredicateAtom cInTransitivePredicate(DNFPredicate referred, String... variables) { | ||
102 | return new PredicateAtom(true, true, referred, stringToVariable(variables)); | ||
103 | } | ||
104 | public static PredicateAtom cNotInPredicate(DNFPredicate referred, String... variables) { | ||
105 | return new PredicateAtom(false, false, referred, stringToVariable(variables)); | ||
106 | } | ||
107 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/building/RelationAtom.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/RelationAtom.java new file mode 100644 index 00000000..f7152bba --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/RelationAtom.java | |||
@@ -0,0 +1,45 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.building; | ||
2 | |||
3 | import java.util.List; | ||
4 | import java.util.Map; | ||
5 | import java.util.Set; | ||
6 | |||
7 | import org.eclipse.viatra.solver.data.query.view.FilteredRelationView; | ||
8 | import org.eclipse.viatra.solver.data.query.view.RelationView; | ||
9 | |||
10 | public class RelationAtom implements DNFAtom{ | ||
11 | RelationView<?> view; | ||
12 | List<Variable> substitution; | ||
13 | |||
14 | public RelationAtom(RelationView<?> view, List<Variable> substitution) { | ||
15 | this.view = view; | ||
16 | this.substitution = substitution; | ||
17 | } | ||
18 | public RelationView<?> getView() { | ||
19 | return view; | ||
20 | } | ||
21 | public void setView(FilteredRelationView<?> view) { | ||
22 | this.view = view; | ||
23 | } | ||
24 | public List<Variable> getSubstitution() { | ||
25 | return substitution; | ||
26 | } | ||
27 | public void setSubstitution(List<Variable> substitution) { | ||
28 | this.substitution = substitution; | ||
29 | } | ||
30 | |||
31 | @Override | ||
32 | public void unifyVariables(Map<String, Variable> variables) { | ||
33 | for(int i = 0; i<this.substitution.size(); i++) { | ||
34 | final Object term = this.substitution.get(i); | ||
35 | if(term instanceof Variable) { | ||
36 | Variable variableReference = (Variable) term; | ||
37 | this.substitution.set(i, DNFAtom.unifyVariables(variables, variableReference)); | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | @Override | ||
42 | public void collectAllVariables(Set<Variable> variables) { | ||
43 | DNFAtom.addToCollection(variables, substitution); | ||
44 | } | ||
45 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/building/Variable.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/Variable.java new file mode 100644 index 00000000..29f9fc8b --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/building/Variable.java | |||
@@ -0,0 +1,22 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.building; | ||
2 | |||
3 | public class Variable { | ||
4 | private final String name; | ||
5 | private final String uniqueName; | ||
6 | |||
7 | public Variable(String name) { | ||
8 | super(); | ||
9 | this.name = name; | ||
10 | this.uniqueName = DNFPredicate.generateUniqueName(name, "variable"); | ||
11 | |||
12 | } | ||
13 | public String getName() { | ||
14 | return name; | ||
15 | } | ||
16 | public String getUniqueName() { | ||
17 | return uniqueName; | ||
18 | } | ||
19 | public boolean isNamed() { | ||
20 | return name != null; | ||
21 | } | ||
22 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/DummyBaseIndexer.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/DummyBaseIndexer.java new file mode 100644 index 00000000..042ec3dc --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/DummyBaseIndexer.java | |||
@@ -0,0 +1,59 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.internal; | ||
2 | |||
3 | import java.lang.reflect.InvocationTargetException; | ||
4 | import java.util.concurrent.Callable; | ||
5 | |||
6 | import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex; | ||
7 | import org.eclipse.viatra.query.runtime.api.scope.IIndexingErrorListener; | ||
8 | import org.eclipse.viatra.query.runtime.api.scope.IInstanceObserver; | ||
9 | import org.eclipse.viatra.query.runtime.api.scope.ViatraBaseIndexChangeListener; | ||
10 | |||
11 | /** | ||
12 | * copied from org.eclipse.viatra.query.runtime.tabular.TabularEngineContext; | ||
13 | */ | ||
14 | public class DummyBaseIndexer implements IBaseIndex{ | ||
15 | |||
16 | @Override | ||
17 | public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException { | ||
18 | try { | ||
19 | return callable.call(); | ||
20 | } catch (Exception e) { | ||
21 | throw new InvocationTargetException(e); | ||
22 | } | ||
23 | } | ||
24 | |||
25 | @Override | ||
26 | public void addBaseIndexChangeListener(ViatraBaseIndexChangeListener listener) { | ||
27 | // no notification support | ||
28 | } | ||
29 | |||
30 | @Override | ||
31 | public void removeBaseIndexChangeListener(ViatraBaseIndexChangeListener listener) { | ||
32 | // no notification support | ||
33 | } | ||
34 | |||
35 | @Override | ||
36 | public void resampleDerivedFeatures() { | ||
37 | throw new UnsupportedOperationException(); | ||
38 | } | ||
39 | |||
40 | @Override | ||
41 | public boolean addIndexingErrorListener(IIndexingErrorListener listener) { | ||
42 | return true; | ||
43 | } | ||
44 | |||
45 | @Override | ||
46 | public boolean removeIndexingErrorListener(IIndexingErrorListener listener) { | ||
47 | return true; | ||
48 | } | ||
49 | |||
50 | @Override | ||
51 | public boolean addInstanceObserver(IInstanceObserver observer, Object observedObject) { | ||
52 | return true; | ||
53 | } | ||
54 | |||
55 | @Override | ||
56 | public boolean removeInstanceObserver(IInstanceObserver observer, Object observedObject) { | ||
57 | return true; | ||
58 | } | ||
59 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/PredicateTranslator.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/PredicateTranslator.java new file mode 100644 index 00000000..54cb4bab --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/PredicateTranslator.java | |||
@@ -0,0 +1,209 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.internal; | ||
2 | |||
3 | import java.util.ArrayList; | ||
4 | import java.util.HashMap; | ||
5 | import java.util.LinkedHashSet; | ||
6 | import java.util.LinkedList; | ||
7 | import java.util.List; | ||
8 | import java.util.Map; | ||
9 | import java.util.Set; | ||
10 | |||
11 | import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; | ||
12 | import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; | ||
13 | import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; | ||
14 | import org.eclipse.viatra.query.runtime.api.scope.QueryScope; | ||
15 | import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; | ||
16 | import org.eclipse.viatra.query.runtime.matchers.psystem.PBody; | ||
17 | import org.eclipse.viatra.query.runtime.matchers.psystem.PVariable; | ||
18 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Equality; | ||
19 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.ExportedParameter; | ||
20 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.Inequality; | ||
21 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicdeferred.NegativePatternCall; | ||
22 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.BinaryReflexiveTransitiveClosure; | ||
23 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.BinaryTransitiveClosure; | ||
24 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; | ||
25 | import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; | ||
26 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.BasePQuery; | ||
27 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; | ||
28 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; | ||
29 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; | ||
30 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | ||
31 | import org.eclipse.viatra.solver.data.query.RelationalScope; | ||
32 | import org.eclipse.viatra.solver.data.query.view.RelationView; | ||
33 | |||
34 | public class PredicateTranslator extends BasePQuery { | ||
35 | |||
36 | private final Map<String, PParameter> parameters = new HashMap<String, PParameter>(); | ||
37 | private String fullyQualifiedName; | ||
38 | private LinkedList<PBody> bodies = new LinkedList<PBody>(); | ||
39 | private List<ExportedParameter> symbolicParameters; | ||
40 | |||
41 | public PredicateTranslator(String fullyQualifiedName) { | ||
42 | super(PVisibility.PUBLIC); | ||
43 | this.fullyQualifiedName = fullyQualifiedName; | ||
44 | PBody body = new PBody(this); | ||
45 | bodies.add(body); | ||
46 | } | ||
47 | |||
48 | @Override | ||
49 | public String getFullyQualifiedName() { | ||
50 | return fullyQualifiedName; | ||
51 | } | ||
52 | |||
53 | public PredicateTranslator addParameter(String name, RelationView<?> type) { | ||
54 | PParameter parameter = new PParameter(name); | ||
55 | parameters.put(name, parameter); | ||
56 | |||
57 | PBody body = bodies.peekLast(); | ||
58 | List<ExportedParameter> symbolicParameters = new ArrayList<>(); | ||
59 | parameters.forEach((pName, pParameter) -> { | ||
60 | PVariable var = body.getOrCreateVariableByName(pName); | ||
61 | symbolicParameters.add(new ExportedParameter(body, var, pParameter)); | ||
62 | }); | ||
63 | body.setSymbolicParameters(symbolicParameters); | ||
64 | |||
65 | return this; | ||
66 | } | ||
67 | |||
68 | @Override | ||
69 | public List<PParameter> getParameters() { | ||
70 | return new ArrayList<PParameter>(parameters.values()); | ||
71 | } | ||
72 | public <D> PredicateTranslator addConstraint(RelationView<D> view, String... name) { | ||
73 | if(name.length != view.getArity()) { | ||
74 | throw new IllegalArgumentException("Arity ("+view.getArity()+") does not match parameter numbers ("+name.length+")"); | ||
75 | } | ||
76 | PBody body = bodies.peekLast(); | ||
77 | Object[] variables = new Object[name.length]; | ||
78 | for(int i = 0; i<name.length; i++) { | ||
79 | variables[i] = body.getOrCreateVariableByName(name[i]); | ||
80 | } | ||
81 | new TypeConstraint(body, Tuples.flatTupleOf(variables), view); | ||
82 | return this; | ||
83 | } | ||
84 | |||
85 | // // Type constraint | ||
86 | // public RelationQuery addConstraint(String type, String name) { | ||
87 | // PBody body = bodies.peekLast(); | ||
88 | // PVariable var = body.getOrCreateVariableByName(name); | ||
89 | // new TypeConstraint(body, Tuples.flatTupleOf(var), new StringExactInstancesKey(type)); | ||
90 | // return this; | ||
91 | // } | ||
92 | // | ||
93 | // // Relation constraint | ||
94 | // public RelationQuery addConstraint(String type, String sourceName, String targetName) { | ||
95 | // PBody body = bodies.peekLast(); | ||
96 | // PVariable var_source = body.getOrCreateVariableByName(sourceName); | ||
97 | // PVariable var_target = body.getOrCreateVariableByName(targetName); | ||
98 | // new TypeConstraint(body, Tuples.flatTupleOf(var_source, var_target), | ||
99 | // new StringStructuralFeatureInstancesKey(type)); | ||
100 | // return this; | ||
101 | // } | ||
102 | |||
103 | // Create new Body | ||
104 | public PredicateTranslator or() { | ||
105 | PBody body = new PBody(this); | ||
106 | List<ExportedParameter> symbolicParameters = new ArrayList<>(); | ||
107 | parameters.forEach((name, parameter) -> { | ||
108 | PVariable var = body.getOrCreateVariableByName(name); | ||
109 | symbolicParameters.add(new ExportedParameter(body, var, parameter)); | ||
110 | }); | ||
111 | body.setSymbolicParameters(symbolicParameters); | ||
112 | bodies.add(body); | ||
113 | return this; | ||
114 | } | ||
115 | |||
116 | // Equality constraint | ||
117 | public PredicateTranslator addEquality(String sourceName, String targetName) { | ||
118 | PBody body = bodies.peekLast(); | ||
119 | PVariable var_source = body.getOrCreateVariableByName(sourceName); | ||
120 | PVariable var_target = body.getOrCreateVariableByName(targetName); | ||
121 | new Equality(body, var_source, var_target); | ||
122 | return this; | ||
123 | } | ||
124 | |||
125 | // Inequality constraint | ||
126 | public PredicateTranslator addInequality(String sourceName, String targetName) { | ||
127 | PBody body = bodies.peekLast(); | ||
128 | PVariable var_source = body.getOrCreateVariableByName(sourceName); | ||
129 | PVariable var_target = body.getOrCreateVariableByName(targetName); | ||
130 | new Inequality(body, var_source, var_target); | ||
131 | return this; | ||
132 | } | ||
133 | |||
134 | // Positive pattern call | ||
135 | public PredicateTranslator addPatternCall(PQuery query, String... names) { | ||
136 | PBody body = bodies.peekLast(); | ||
137 | PVariable[] vars = new PVariable[names.length]; | ||
138 | for (int i = 0; i < names.length; i++) { | ||
139 | vars[i] = body.getOrCreateVariableByName(names[i]); | ||
140 | } | ||
141 | new PositivePatternCall(body, Tuples.flatTupleOf(vars), query); | ||
142 | return this; | ||
143 | } | ||
144 | |||
145 | // Negative pattern call | ||
146 | public PredicateTranslator addNegativePatternCall(PQuery query, String... names) { | ||
147 | PBody body = bodies.peekLast(); | ||
148 | PVariable[] vars = new PVariable[names.length]; | ||
149 | for (int i = 0; i < names.length; i++) { | ||
150 | vars[i] = body.getOrCreateVariableByName(names[i]); | ||
151 | } | ||
152 | new NegativePatternCall(body, Tuples.flatTupleOf(vars), query); | ||
153 | return this; | ||
154 | } | ||
155 | |||
156 | // Binary transitive closure pattern call | ||
157 | public PredicateTranslator addBinaryTransitiveClosure(PQuery query, String sourceName, String targetName) { | ||
158 | PBody body = bodies.peekLast(); | ||
159 | PVariable var_source = body.getOrCreateVariableByName(sourceName); | ||
160 | PVariable var_target = body.getOrCreateVariableByName(targetName); | ||
161 | new BinaryTransitiveClosure(body, Tuples.flatTupleOf(var_source, var_target), query); | ||
162 | return this; | ||
163 | } | ||
164 | |||
165 | // Binary reflexive transitive closure pattern call | ||
166 | public PredicateTranslator addBinaryReflexiveTransitiveClosure(PQuery query, String sourceName, String targetName) { | ||
167 | PBody body = bodies.peekLast(); | ||
168 | PVariable var_source = body.getOrCreateVariableByName(sourceName); | ||
169 | PVariable var_target = body.getOrCreateVariableByName(targetName); | ||
170 | new BinaryReflexiveTransitiveClosure(body, Tuples.flatTupleOf(var_source, var_target), query, | ||
171 | query.getParameters().get(0).getDeclaredUnaryType()); | ||
172 | return this; | ||
173 | } | ||
174 | |||
175 | @Override | ||
176 | public Set<PBody> doGetContainedBodies() { | ||
177 | setEvaluationHints(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.UNSPECIFIED)); | ||
178 | return new LinkedHashSet<PBody>(bodies); | ||
179 | } | ||
180 | |||
181 | public void addSymbolicParameters(ExportedParameter symbolicParameter) { | ||
182 | checkMutability(); | ||
183 | if (symbolicParameters == null) { | ||
184 | symbolicParameters = new ArrayList<>(); | ||
185 | } | ||
186 | symbolicParameters.add(symbolicParameter); | ||
187 | } | ||
188 | |||
189 | public GenericQuerySpecification<GenericPatternMatcher> build() { | ||
190 | return new GenericQuerySpecification<GenericPatternMatcher>(this) { | ||
191 | |||
192 | @Override | ||
193 | public Class<? extends QueryScope> getPreferredScopeClass() { | ||
194 | return RelationalScope.class; | ||
195 | } | ||
196 | |||
197 | @Override | ||
198 | protected GenericPatternMatcher instantiate(ViatraQueryEngine engine) { | ||
199 | return defaultInstantiate(engine); | ||
200 | } | ||
201 | |||
202 | @Override | ||
203 | public GenericPatternMatcher instantiate() { | ||
204 | return new GenericPatternMatcher(this); | ||
205 | } | ||
206 | |||
207 | }; | ||
208 | } | ||
209 | } \ No newline at end of file | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationUpdateListener.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationUpdateListener.java new file mode 100644 index 00000000..c6d12614 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationUpdateListener.java | |||
@@ -0,0 +1,51 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.internal; | ||
2 | |||
3 | import java.util.HashMap; | ||
4 | import java.util.HashSet; | ||
5 | import java.util.Map; | ||
6 | import java.util.Set; | ||
7 | |||
8 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
9 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
10 | import org.eclipse.viatra.solver.data.model.Tuple; | ||
11 | import org.eclipse.viatra.solver.data.query.view.RelationView; | ||
12 | |||
13 | public class RelationUpdateListener { | ||
14 | private final Map<RelationView<?>,Set<RelationUpdateListenerEntry<?>>> view2Listeners; | ||
15 | |||
16 | public RelationUpdateListener(Set<RelationView<?>> relationViews) { | ||
17 | view2Listeners = new HashMap<>(); | ||
18 | for(RelationView<?> relationView : relationViews) { | ||
19 | view2Listeners.put(relationView, new HashSet<>()); | ||
20 | } | ||
21 | } | ||
22 | public boolean containsRelationalView(RelationView<?> relationalKey) { | ||
23 | RelationView<?> relationView = relationalKey.getWrappedKey(); | ||
24 | return view2Listeners.containsKey(relationView); | ||
25 | } | ||
26 | public void addListener(RelationView<?> relationalKey, ITuple seed, IQueryRuntimeContextListener listener) { | ||
27 | RelationView<?> relationView = relationalKey.getWrappedKey(); | ||
28 | if(view2Listeners.containsKey(relationView)) { | ||
29 | RelationUpdateListenerEntry<?> entry = new RelationUpdateListenerEntry<>(relationalKey, seed, listener); | ||
30 | view2Listeners.get(relationView).add(entry); | ||
31 | } else throw new IllegalArgumentException(); | ||
32 | } | ||
33 | public void removeListener(RelationView<?> relationalKey, ITuple seed, IQueryRuntimeContextListener listener) { | ||
34 | RelationView<?> relationView = relationalKey.getWrappedKey(); | ||
35 | if(view2Listeners.containsKey(relationView)) { | ||
36 | RelationUpdateListenerEntry<?> entry = new RelationUpdateListenerEntry<>(relationalKey, seed, listener); | ||
37 | view2Listeners.get(relationView).remove(entry); | ||
38 | } else throw new IllegalArgumentException(); | ||
39 | } | ||
40 | |||
41 | public <D> void processChange(RelationView<D> relationView, Tuple tuple, D oldValue, D newValue) { | ||
42 | Set<RelationUpdateListenerEntry<?>> listeners = view2Listeners.get(relationView); | ||
43 | if(listeners != null) { | ||
44 | for(RelationUpdateListenerEntry<?> listener : listeners) { | ||
45 | @SuppressWarnings("unchecked") | ||
46 | RelationUpdateListenerEntry<D> typeCorrectListener = (RelationUpdateListenerEntry<D>) listener; | ||
47 | typeCorrectListener.processChange(tuple, oldValue, newValue); | ||
48 | } | ||
49 | } else throw new IllegalArgumentException("View was not indexed in constructor "+relationView); | ||
50 | } | ||
51 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationUpdateListenerEntry.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationUpdateListenerEntry.java new file mode 100644 index 00000000..55aed7c8 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationUpdateListenerEntry.java | |||
@@ -0,0 +1,63 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.internal; | ||
2 | |||
3 | import java.util.Arrays; | ||
4 | import java.util.Objects; | ||
5 | |||
6 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
7 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
8 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | ||
9 | import org.eclipse.viatra.solver.data.model.Tuple; | ||
10 | import org.eclipse.viatra.solver.data.query.view.RelationView; | ||
11 | |||
12 | public class RelationUpdateListenerEntry<D> { | ||
13 | final RelationView<D> key; | ||
14 | final ITuple filter; | ||
15 | final IQueryRuntimeContextListener listener; | ||
16 | |||
17 | public RelationUpdateListenerEntry(RelationView<D> key, ITuple filter, IQueryRuntimeContextListener listener) { | ||
18 | super(); | ||
19 | this.key = key; | ||
20 | this.filter = filter; | ||
21 | this.listener = listener; | ||
22 | } | ||
23 | |||
24 | public void processChange(Tuple tuple, D oldValue, D newValue) { | ||
25 | Object[] oldTuple = isMatching(key.getWrappedKey().transform(tuple, oldValue), filter); | ||
26 | Object[] newTuple = isMatching(key.getWrappedKey().transform(tuple, newValue), filter); | ||
27 | |||
28 | if(!Arrays.equals(oldTuple, newTuple)) { | ||
29 | if(oldTuple != null) { | ||
30 | listener.update(key, Tuples.flatTupleOf(oldTuple), false); | ||
31 | } | ||
32 | if(newTuple != null) { | ||
33 | listener.update(key, Tuples.flatTupleOf(newTuple), true); | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | |||
38 | private Object[] isMatching(Object[] tuple, ITuple filter) { | ||
39 | for(int i = 0; i<filter.getSize(); i++) { | ||
40 | final Object filterObject = filter.get(i); | ||
41 | if(filterObject != null && !filterObject.equals(tuple[i])) { | ||
42 | return null; | ||
43 | } | ||
44 | } | ||
45 | return tuple; | ||
46 | } | ||
47 | |||
48 | @Override | ||
49 | public int hashCode() { | ||
50 | return Objects.hash(filter, key, listener); | ||
51 | } | ||
52 | |||
53 | @Override | ||
54 | public boolean equals(Object obj) { | ||
55 | if (this == obj) | ||
56 | return true; | ||
57 | if (!(obj instanceof RelationUpdateListenerEntry)) | ||
58 | return false; | ||
59 | RelationUpdateListenerEntry<?> other = (RelationUpdateListenerEntry<?>) obj; | ||
60 | return Objects.equals(filter, other.filter) && Objects.equals(key, other.key) | ||
61 | && Objects.equals(listener, other.listener); | ||
62 | } | ||
63 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationalEngineContext.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationalEngineContext.java new file mode 100644 index 00000000..01948828 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationalEngineContext.java | |||
@@ -0,0 +1,32 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.internal; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex; | ||
4 | import org.eclipse.viatra.query.runtime.api.scope.IEngineContext; | ||
5 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; | ||
6 | import org.eclipse.viatra.solver.data.model.Model; | ||
7 | |||
8 | public class RelationalEngineContext implements IEngineContext{ | ||
9 | private final IBaseIndex baseIndex = new DummyBaseIndexer(); | ||
10 | private final RelationalRuntimeContext runtimeContext; | ||
11 | |||
12 | |||
13 | public RelationalEngineContext(Model model, RelationUpdateListener updateListener) { | ||
14 | runtimeContext = new RelationalRuntimeContext(model, updateListener); | ||
15 | } | ||
16 | |||
17 | @Override | ||
18 | public IBaseIndex getBaseIndex() { | ||
19 | return this.baseIndex; | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public void dispose() { | ||
24 | //lifecycle not controlled by engine | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public IQueryRuntimeContext getQueryRuntimeContext() { | ||
29 | return runtimeContext; | ||
30 | } | ||
31 | |||
32 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationalQueryMetaContext.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationalQueryMetaContext.java new file mode 100644 index 00000000..de500fc9 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationalQueryMetaContext.java | |||
@@ -0,0 +1,57 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.internal; | ||
2 | |||
3 | import java.util.Collection; | ||
4 | import java.util.Collections; | ||
5 | import java.util.HashMap; | ||
6 | import java.util.HashSet; | ||
7 | import java.util.Map; | ||
8 | import java.util.Set; | ||
9 | |||
10 | import org.eclipse.viatra.query.runtime.matchers.context.AbstractQueryMetaContext; | ||
11 | import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; | ||
12 | import org.eclipse.viatra.query.runtime.matchers.context.InputKeyImplication; | ||
13 | import org.eclipse.viatra.solver.data.query.view.RelationView; | ||
14 | |||
15 | /** | ||
16 | * The meta context information for String scopes. | ||
17 | */ | ||
18 | public final class RelationalQueryMetaContext extends AbstractQueryMetaContext { | ||
19 | |||
20 | @Override | ||
21 | public boolean isEnumerable(IInputKey key) { | ||
22 | ensureValidKey(key); | ||
23 | return key.isEnumerable(); | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public boolean isStateless(IInputKey key) { | ||
28 | ensureValidKey(key); | ||
29 | return key instanceof RelationView<?>; | ||
30 | } | ||
31 | |||
32 | @Override | ||
33 | public Collection<InputKeyImplication> getImplications(IInputKey implyingKey) { | ||
34 | ensureValidKey(implyingKey); | ||
35 | return new HashSet<InputKeyImplication>(); | ||
36 | } | ||
37 | |||
38 | @Override | ||
39 | public Map<Set<Integer>, Set<Integer>> getFunctionalDependencies(IInputKey key) { | ||
40 | ensureValidKey(key); | ||
41 | if (key instanceof RelationView) { | ||
42 | return new HashMap<Set<Integer>, Set<Integer>>(); | ||
43 | } else { | ||
44 | return Collections.emptyMap(); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | public void ensureValidKey(IInputKey key) { | ||
49 | if (! (key instanceof RelationView<?>)) | ||
50 | illegalInputKey(key); | ||
51 | } | ||
52 | |||
53 | public void illegalInputKey(IInputKey key) { | ||
54 | throw new IllegalArgumentException("The input key " + key + " is not a valid input key."); | ||
55 | } | ||
56 | |||
57 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationalRuntimeContext.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationalRuntimeContext.java new file mode 100644 index 00000000..7d1682b2 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/internal/RelationalRuntimeContext.java | |||
@@ -0,0 +1,187 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.internal; | ||
2 | |||
3 | import static org.eclipse.viatra.solver.data.util.CollectionsUtil.filter; | ||
4 | import static org.eclipse.viatra.solver.data.util.CollectionsUtil.map; | ||
5 | |||
6 | import java.lang.reflect.InvocationTargetException; | ||
7 | import java.util.Iterator; | ||
8 | import java.util.Optional; | ||
9 | import java.util.concurrent.Callable; | ||
10 | |||
11 | import org.eclipse.viatra.query.runtime.base.core.NavigationHelperImpl; | ||
12 | import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; | ||
13 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryMetaContext; | ||
14 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContext; | ||
15 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; | ||
16 | import org.eclipse.viatra.query.runtime.matchers.context.IndexingService; | ||
17 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
18 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; | ||
19 | import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; | ||
20 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | ||
21 | import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; | ||
22 | import org.eclipse.viatra.solver.data.model.Model; | ||
23 | import org.eclipse.viatra.solver.data.query.view.RelationView; | ||
24 | |||
25 | public class RelationalRuntimeContext implements IQueryRuntimeContext { | ||
26 | private final RelationalQueryMetaContext metaContext = new RelationalQueryMetaContext(); | ||
27 | private final RelationUpdateListener relationUpdateListener; | ||
28 | private final Model model; | ||
29 | |||
30 | public RelationalRuntimeContext(Model model, RelationUpdateListener relationUpdateListener) { | ||
31 | this.model = model; | ||
32 | this.relationUpdateListener = relationUpdateListener; | ||
33 | } | ||
34 | |||
35 | @Override | ||
36 | public IQueryMetaContext getMetaContext() { | ||
37 | return metaContext; | ||
38 | } | ||
39 | |||
40 | // | ||
41 | /** | ||
42 | * TODO: check {@link NavigationHelperImpl#coalesceTraversals(Callable)} | ||
43 | */ | ||
44 | @Override | ||
45 | public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException { | ||
46 | try { | ||
47 | return callable.call(); | ||
48 | } catch (Exception e) { | ||
49 | throw new InvocationTargetException(e); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | @Override | ||
54 | public boolean isCoalescing() { | ||
55 | return true; | ||
56 | } | ||
57 | |||
58 | @Override | ||
59 | public boolean isIndexed(IInputKey key, IndexingService service) { | ||
60 | if(key instanceof RelationView<?>) { | ||
61 | RelationView<?> relationalKey = (RelationView<?>) key; | ||
62 | return this.relationUpdateListener.containsRelationalView(relationalKey); | ||
63 | } else { | ||
64 | return false; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | @Override | ||
69 | public void ensureIndexed(IInputKey key, IndexingService service) { | ||
70 | if(!isIndexed(key, service)) { | ||
71 | throw new IllegalStateException("Engine tries to index a new key " +key); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | RelationView<?> checkKey(IInputKey key) { | ||
76 | if(key instanceof RelationView) { | ||
77 | RelationView<?> relationViewKey = (RelationView<?>) key; | ||
78 | if(relationUpdateListener.containsRelationalView(relationViewKey)) { | ||
79 | return relationViewKey; | ||
80 | } else { | ||
81 | throw new IllegalStateException("Query is asking for non-indexed key"); | ||
82 | } | ||
83 | } else { | ||
84 | throw new IllegalStateException("Query is asking for non-relational key"); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | @Override | ||
89 | public int countTuples(IInputKey key, TupleMask seedMask, ITuple seed) { | ||
90 | RelationView<?> relationalViewKey = checkKey(key); | ||
91 | Iterable<Object[]> allObjects = relationalViewKey.getAll(model); | ||
92 | Iterable<Object[]> filteredBySeed = filter(allObjects,objectArray -> isMatching(objectArray,seedMask,seed)); | ||
93 | Iterator<Object[]> iterator = filteredBySeed.iterator(); | ||
94 | int result = 0; | ||
95 | while(iterator.hasNext()) { | ||
96 | iterator.next(); | ||
97 | result++; | ||
98 | } | ||
99 | return result; | ||
100 | } | ||
101 | |||
102 | @Override | ||
103 | public Optional<Long> estimateCardinality(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy) { | ||
104 | return Optional.empty(); | ||
105 | } | ||
106 | |||
107 | @Override | ||
108 | public Iterable<Tuple> enumerateTuples(IInputKey key, TupleMask seedMask, ITuple seed) { | ||
109 | RelationView<?> relationalViewKey = checkKey(key); | ||
110 | Iterable<Object[]> allObjects = relationalViewKey.getAll(model); | ||
111 | Iterable<Object[]> filteredBySeed = filter(allObjects,objectArray -> isMatching(objectArray,seedMask,seed)); | ||
112 | return map(filteredBySeed,Tuples::flatTupleOf); | ||
113 | } | ||
114 | |||
115 | private boolean isMatching(Object[] tuple, TupleMask seedMask, ITuple seed) { | ||
116 | for(int i=0; i<seedMask.indices.length; i++) { | ||
117 | final Object seedElement = seed.get(i); | ||
118 | final Object tupleElement = tuple[seedMask.indices[i]]; | ||
119 | if(!tupleElement.equals(seedElement)) { | ||
120 | return false; | ||
121 | } | ||
122 | } | ||
123 | return true; | ||
124 | } | ||
125 | // private Object[] toObjectMask(RelationViewKey<?> relationalViewKey, TupleMask seedMask, ITuple seed) { | ||
126 | // final int arity = relationalViewKey.getArity(); | ||
127 | // Object[] result = new Object[arity]; | ||
128 | // for(int i = 0; i<seedMask.indices.length; i++) { | ||
129 | // result[seedMask.indices[i]] = seed.get(i); | ||
130 | // } | ||
131 | // return result; | ||
132 | // } | ||
133 | |||
134 | @Override | ||
135 | public Iterable<? extends Object> enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed) { | ||
136 | return enumerateTuples(key, seedMask, seed); | ||
137 | } | ||
138 | |||
139 | @Override | ||
140 | public boolean containsTuple(IInputKey key, ITuple seed) { | ||
141 | RelationView<?> relationalViewKey = checkKey(key); | ||
142 | return relationalViewKey.get(model,seed.getElements()); | ||
143 | } | ||
144 | |||
145 | @Override | ||
146 | public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { | ||
147 | RelationView<?> relationalKey = checkKey(key); | ||
148 | this.relationUpdateListener.addListener(relationalKey, seed, listener); | ||
149 | |||
150 | } | ||
151 | |||
152 | @Override | ||
153 | public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) { | ||
154 | RelationView<?> relationalKey = checkKey(key); | ||
155 | this.relationUpdateListener.removeListener(relationalKey, seed, listener); | ||
156 | } | ||
157 | |||
158 | @Override | ||
159 | public Object wrapElement(Object externalElement) { | ||
160 | return externalElement; | ||
161 | } | ||
162 | |||
163 | @Override | ||
164 | public Object unwrapElement(Object internalElement) { | ||
165 | return internalElement; | ||
166 | } | ||
167 | |||
168 | @Override | ||
169 | public Tuple wrapTuple(Tuple externalElements) { | ||
170 | return externalElements; | ||
171 | } | ||
172 | |||
173 | @Override | ||
174 | public Tuple unwrapTuple(Tuple internalElements) { | ||
175 | return internalElements; | ||
176 | } | ||
177 | |||
178 | @Override | ||
179 | public void ensureWildcardIndexing(IndexingService service) { | ||
180 | throw new UnsupportedOperationException(); | ||
181 | } | ||
182 | |||
183 | @Override | ||
184 | public void executeAfterTraversal(Runnable runnable) throws InvocationTargetException { | ||
185 | runnable.run(); | ||
186 | } | ||
187 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/view/FilteredRelationView.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/view/FilteredRelationView.java new file mode 100644 index 00000000..edc534b7 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/view/FilteredRelationView.java | |||
@@ -0,0 +1,48 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.view; | ||
2 | |||
3 | import java.util.function.BiPredicate; | ||
4 | |||
5 | import org.eclipse.viatra.solver.data.model.Model; | ||
6 | import org.eclipse.viatra.solver.data.model.Tuple; | ||
7 | import org.eclipse.viatra.solver.data.model.Tuple.Tuple1; | ||
8 | import org.eclipse.viatra.solver.data.model.representation.Relation; | ||
9 | |||
10 | public class FilteredRelationView<D> extends RelationView<D>{ | ||
11 | private final BiPredicate<Tuple,D> predicate; | ||
12 | |||
13 | public FilteredRelationView(Relation<D> representation, BiPredicate<Tuple,D> predicate) { | ||
14 | super(representation); | ||
15 | this.predicate = predicate; | ||
16 | } | ||
17 | @Override | ||
18 | protected Object[] forwardMap(Tuple key, D value) { | ||
19 | return toTuple1Array(key); | ||
20 | } | ||
21 | @Override | ||
22 | public boolean get(Model model, Object[] tuple) { | ||
23 | int[] content = new int[tuple.length]; | ||
24 | for(int i = 0; i<tuple.length; i++) { | ||
25 | content[i] =((Tuple1)tuple[i]).get(0); | ||
26 | } | ||
27 | Tuple key = Tuple.of(content); | ||
28 | D value = model.get(representation, key); | ||
29 | return filter(key, value); | ||
30 | } | ||
31 | |||
32 | public static Object[] toTuple1Array(Tuple t) { | ||
33 | Object[] result = new Object[t.getSize()]; | ||
34 | for(int i = 0; i<t.getSize(); i++) { | ||
35 | result[i] = t.get(i); | ||
36 | } | ||
37 | return result; | ||
38 | } | ||
39 | |||
40 | @Override | ||
41 | public int getArity() { | ||
42 | return this.representation.getArity(); | ||
43 | } | ||
44 | @Override | ||
45 | protected boolean filter(Tuple key, D value) { | ||
46 | return this.predicate.test(key, value); | ||
47 | } | ||
48 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/view/FunctionalRelationView.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/view/FunctionalRelationView.java new file mode 100644 index 00000000..4aa7cfd0 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/view/FunctionalRelationView.java | |||
@@ -0,0 +1,50 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.view; | ||
2 | |||
3 | import org.eclipse.viatra.solver.data.model.Model; | ||
4 | import org.eclipse.viatra.solver.data.model.Tuple; | ||
5 | import org.eclipse.viatra.solver.data.model.Tuple.Tuple1; | ||
6 | import org.eclipse.viatra.solver.data.model.representation.Relation; | ||
7 | |||
8 | public class FunctionalRelationView<D> extends RelationView<D> { | ||
9 | |||
10 | public FunctionalRelationView(Relation<D> representation) { | ||
11 | super(representation); | ||
12 | } | ||
13 | |||
14 | @Override | ||
15 | protected boolean filter(Tuple key, D value) { | ||
16 | return true; | ||
17 | } | ||
18 | |||
19 | @Override | ||
20 | protected Object[] forwardMap(Tuple key, D value) { | ||
21 | return toTuple1ArrayPlusValue(key, value); | ||
22 | } | ||
23 | |||
24 | @Override | ||
25 | public boolean get(Model model, Object[] tuple) { | ||
26 | int[] content = new int[tuple.length-1]; | ||
27 | for(int i = 0; i<tuple.length-1; i++) { | ||
28 | content[i] =((Tuple1)tuple[i]).get(0); | ||
29 | } | ||
30 | Tuple key = Tuple.of(content); | ||
31 | @SuppressWarnings("unchecked") | ||
32 | D valueInTuple = (D) tuple[tuple.length-1]; | ||
33 | D valueInMap = model.get(representation, key); | ||
34 | return valueInTuple.equals(valueInMap); | ||
35 | } | ||
36 | |||
37 | public static <D> Object[] toTuple1ArrayPlusValue(Tuple t, D value) { | ||
38 | Object[] result = new Object[t.getSize()+1]; | ||
39 | for(int i = 0; i<t.getSize(); i++) { | ||
40 | result[i] = t.get(i); | ||
41 | } | ||
42 | result[t.getSize()] = value; | ||
43 | return result; | ||
44 | } | ||
45 | |||
46 | @Override | ||
47 | public int getArity() { | ||
48 | return this.representation.getArity()+1; | ||
49 | } | ||
50 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/view/KeyOnlyRelationView.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/view/KeyOnlyRelationView.java new file mode 100644 index 00000000..11a24fc8 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/view/KeyOnlyRelationView.java | |||
@@ -0,0 +1,16 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.view; | ||
2 | |||
3 | import org.eclipse.viatra.solver.data.model.Tuple; | ||
4 | import org.eclipse.viatra.solver.data.model.representation.Relation; | ||
5 | |||
6 | public class KeyOnlyRelationView extends FilteredRelationView<Boolean>{ | ||
7 | |||
8 | public KeyOnlyRelationView(Relation<Boolean> representation) { | ||
9 | super(representation, (k,v)->true); | ||
10 | } | ||
11 | @Override | ||
12 | protected boolean filter(Tuple key, Boolean value) { | ||
13 | return true; | ||
14 | } | ||
15 | |||
16 | } | ||
diff --git a/store/src/main/java/org/eclipse/viatra/solver/data/query/view/RelationView.java b/store/src/main/java/org/eclipse/viatra/solver/data/query/view/RelationView.java new file mode 100644 index 00000000..c5bc5228 --- /dev/null +++ b/store/src/main/java/org/eclipse/viatra/solver/data/query/view/RelationView.java | |||
@@ -0,0 +1,85 @@ | |||
1 | package org.eclipse.viatra.solver.data.query.view; | ||
2 | |||
3 | import java.util.Objects; | ||
4 | |||
5 | import org.eclipse.viatra.query.runtime.matchers.context.common.BaseInputKeyWrapper; | ||
6 | import org.eclipse.viatra.solver.data.map.CursorAsIterator; | ||
7 | import org.eclipse.viatra.solver.data.model.Model; | ||
8 | import org.eclipse.viatra.solver.data.model.Tuple; | ||
9 | import org.eclipse.viatra.solver.data.model.representation.Relation; | ||
10 | |||
11 | /** | ||
12 | * Represents a view of a {@link Relation} that can be queried. | ||
13 | * | ||
14 | * @author Oszkar Semerath | ||
15 | * | ||
16 | * @param <D> | ||
17 | */ | ||
18 | public abstract class RelationView<D> extends BaseInputKeyWrapper<RelationView<D>> { | ||
19 | protected final Relation<D> representation; | ||
20 | |||
21 | protected RelationView(Relation<D> representation) { | ||
22 | super(null); | ||
23 | this.wrappedKey = this; | ||
24 | this.representation = representation; | ||
25 | } | ||
26 | |||
27 | @Override | ||
28 | public String getPrettyPrintableName() { | ||
29 | return representation.getName(); | ||
30 | } | ||
31 | |||
32 | @Override | ||
33 | public String getStringID() { | ||
34 | return representation.getName() + this.getClass().getName(); | ||
35 | } | ||
36 | |||
37 | public Relation<D> getRepresentation() { | ||
38 | return representation; | ||
39 | } | ||
40 | |||
41 | @Override | ||
42 | public boolean isEnumerable() { | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | protected abstract boolean filter(Tuple key, D value); | ||
47 | |||
48 | protected abstract Object[] forwardMap(Tuple key, D value); | ||
49 | |||
50 | public abstract boolean get(Model model, Object[] tuple); | ||
51 | |||
52 | public Object[] transform(Tuple tuple, D value) { | ||
53 | if (filter(tuple, value)) { | ||
54 | return forwardMap(tuple, value); | ||
55 | } else | ||
56 | return null; | ||
57 | } | ||
58 | |||
59 | public Iterable<Object[]> getAll(Model model) { | ||
60 | return (() -> new CursorAsIterator<>(model.getAll(representation), (k, v) -> forwardMap(k, v), | ||
61 | (k, v) -> filter(k, v))); | ||
62 | } | ||
63 | |||
64 | @Override | ||
65 | public int hashCode() { | ||
66 | final int prime = 31; | ||
67 | int result = 1; | ||
68 | result = prime * result + Objects.hash(representation); | ||
69 | return result; | ||
70 | } | ||
71 | |||
72 | @Override | ||
73 | public boolean equals(Object obj) { | ||
74 | if (this == obj) | ||
75 | return true; | ||
76 | if (!super.equals(obj)) | ||
77 | return false; | ||
78 | if (!(obj instanceof RelationView)) | ||
79 | return false; | ||
80 | @SuppressWarnings("unchecked") | ||
81 | RelationView<D> other = ((RelationView<D>) obj); | ||
82 | return Objects.equals(representation, other.representation); | ||
83 | } | ||
84 | |||
85 | } | ||