aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraQueryableModelStore.java
blob: 94d2db4f2125a3721dc572aa9a15d90ac65aa91e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package tools.refinery.store.query.viatra;

import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
import tools.refinery.store.model.ModelDiffCursor;
import tools.refinery.store.model.ModelStore;
import tools.refinery.store.model.ModelStoreImpl;
import tools.refinery.store.model.RelationLike;
import tools.refinery.store.model.representation.AnyDataRepresentation;
import tools.refinery.store.model.representation.DataRepresentation;
import tools.refinery.store.query.DNF;
import tools.refinery.store.query.DNFAnd;
import tools.refinery.store.query.QueryableModel;
import tools.refinery.store.query.QueryableModelStore;
import tools.refinery.store.query.atom.*;
import tools.refinery.store.query.viatra.internal.RawPatternMatcher;
import tools.refinery.store.query.viatra.internal.ViatraQueryableModel;
import tools.refinery.store.query.viatra.internal.pquery.DNF2PQuery;
import tools.refinery.store.query.view.AnyRelationView;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class ViatraQueryableModelStore implements QueryableModelStore {
	protected final ModelStore store;

	protected final Set<AnyRelationView> relationViews;

	protected final Map<DNF, GenericQuerySpecification<RawPatternMatcher>> predicates;

	public ViatraQueryableModelStore(ModelStore store, Set<AnyRelationView> relationViews,
									 Set<DNF> predicates) {
		this.store = store;
		validateViews(store.getDataRepresentations(), relationViews);
		this.relationViews = Collections.unmodifiableSet(relationViews);
		validatePredicates(relationViews, predicates);
		this.predicates = initPredicates(predicates);
	}

	public ViatraQueryableModelStore(Set<AnyDataRepresentation> dataRepresentations,
									 Set<AnyRelationView> relationViews, Set<DNF> predicates) {
		this(new ModelStoreImpl(dataRepresentations), relationViews, predicates);
	}

	private void validateViews(Set<AnyDataRepresentation> dataRepresentations, Set<AnyRelationView> relationViews) {
		for (var relationView : relationViews) {
			if (!dataRepresentations.contains(relationView.getRepresentation())) {
				throw new IllegalArgumentException("%s %s added to %s without a referred representation.".formatted(
						DataRepresentation.class.getSimpleName(), relationView.getName(),
						QueryableModelStore.class.getSimpleName()));
			}
		}
	}

	private void validatePredicates(Set<AnyRelationView> relationViews, Set<DNF> predicates) {
		for (DNF dnfPredicate : predicates) {
			for (DNFAnd clause : dnfPredicate.getClauses()) {
				for (DNFAtom atom : clause.constraints()) {
					if (atom instanceof RelationViewAtom relationViewAtom) {
						validateRelationAtom(relationViews, dnfPredicate, relationViewAtom);
					} else if (atom instanceof CallAtom<?> queryCallAtom) {
						validatePredicateAtom(predicates, dnfPredicate, queryCallAtom);
					} else if (!(atom instanceof EquivalenceAtom || atom instanceof ConstantAtom)) {
						throw new IllegalArgumentException("Unknown constraint: " + atom.toString());
					}
				}
			}
		}
	}

	private void validateRelationAtom(Set<AnyRelationView> relationViews, DNF dnfPredicate,
									  RelationViewAtom relationViewAtom) {
		if (!relationViews.contains(relationViewAtom.getTarget())) {
			throw new IllegalArgumentException(
					"%s %s contains reference to a view %s that is not in the model.".formatted(
							DNF.class.getSimpleName(), dnfPredicate.getUniqueName(),
							relationViewAtom.getTarget().getName()));
		}
	}

	private void validatePredicateReference(Set<DNF> predicates, DNF dnfPredicate, RelationLike target) {
		if (!(target instanceof DNF dnfTarget) || !predicates.contains(dnfTarget)) {
			throw new IllegalArgumentException(
					"%s %s contains reference to a predicate %s that is not in the model.".formatted(
							DNF.class.getSimpleName(), dnfPredicate.getUniqueName(), target.getName()));
		}
	}

	private void validatePredicateAtom(Set<DNF> predicates, DNF dnfPredicate, CallAtom<?> queryCallAtom) {
		validatePredicateReference(predicates, dnfPredicate, queryCallAtom.getTarget());
	}


	private Map<DNF, GenericQuerySpecification<RawPatternMatcher>> initPredicates(Set<DNF> predicates) {
		Map<DNF, GenericQuerySpecification<RawPatternMatcher>> result = new HashMap<>();
		var dnf2PQuery = new DNF2PQuery();
		for (DNF dnfPredicate : predicates) {
			GenericQuerySpecification<RawPatternMatcher> query = dnf2PQuery.translate(dnfPredicate).build();
			result.put(dnfPredicate, query);
		}

		return result;
	}

	@Override
	public Set<AnyDataRepresentation> getDataRepresentations() {
		return store.getDataRepresentations();
	}

	@Override
	public Set<AnyRelationView> getViews() {
		return this.relationViews;
	}

	@Override
	public Set<DNF> getPredicates() {
		return predicates.keySet();
	}

	@Override
	public QueryableModel createModel() {
		return new ViatraQueryableModel(this, this.store.createModel(), predicates);
	}

	@Override
	public QueryableModel createModel(long state) {
		return new ViatraQueryableModel(this, this.store.createModel(state), predicates);
	}

	@Override
	public synchronized Set<Long> getStates() {
		return this.store.getStates();
	}

	@Override
	public synchronized ModelDiffCursor getDiffCursor(long from, long to) {
		return this.store.getDiffCursor(from, to);
	}
}