aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/TypeScopePropagator.java
blob: d117b0e2fb4382ea8f51a4ef519a9830f472f95d (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
/*
 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package tools.refinery.store.reasoning.scope;

import com.google.ortools.linearsolver.MPConstraint;
import tools.refinery.store.model.ModelStoreBuilder;
import tools.refinery.store.query.ModelQueryBuilder;
import tools.refinery.logic.dnf.AnyQuery;
import tools.refinery.logic.dnf.RelationalQuery;
import tools.refinery.store.query.resultset.ResultSet;
import tools.refinery.store.tuple.Tuple;

import java.util.Collection;

abstract class TypeScopePropagator {
	private final BoundScopePropagator adapter;
	private final ResultSet<Boolean> allNodes;
	private final ResultSet<Boolean> multiNodes;
	protected final MPConstraint constraint;

	protected TypeScopePropagator(BoundScopePropagator adapter, RelationalQuery allQuery,
								  RelationalQuery multiQuery) {
		this.adapter = adapter;
		var queryEngine = adapter.getQueryEngine();
		allNodes = queryEngine.getResultSet(allQuery);
		multiNodes = queryEngine.getResultSet(multiQuery);
		constraint = adapter.makeConstraint();
		constraint.setBounds(0, Double.POSITIVE_INFINITY);
		var cursor = multiNodes.getAll();
		while (cursor.move()) {
			var variable = adapter.getVariable(cursor.getKey().get(0));
			constraint.setCoefficient(variable, 1);
		}
		allNodes.addListener(this::allChanged);
		multiNodes.addListener(this::multiChanged);
	}

	protected abstract void doUpdateBounds();

	public boolean updateBounds() {
		doUpdateBounds();
		return constraint.lb() <= constraint.ub();
	}

	protected int getSingleCount() {
		return allNodes.size() - multiNodes.size();
	}

	private void allChanged(Tuple ignoredKey, Boolean ignoredOldValue, Boolean ignoredNewValue) {
		adapter.markAsChanged();
	}

	private void multiChanged(Tuple key, Boolean ignoredOldValue, Boolean newValue) {
		var variable = adapter.getVariable(key.get(0));
		constraint.setCoefficient(variable, Boolean.TRUE.equals(newValue) ? 1 : 0);
		adapter.markAsChanged();
	}

	abstract static class Factory {
		public abstract TypeScopePropagator createPropagator(BoundScopePropagator adapter);

		protected abstract Collection<AnyQuery> getQueries();

		public void configure(ModelStoreBuilder storeBuilder) {
			storeBuilder.getAdapter(ModelQueryBuilder.class).queries(getQueries());
		}
	}
}