aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-matchers
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-08-19 03:00:23 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-08-19 03:00:23 +0200
commitfc7e3dc61a2ac8de32914af331c1144e4fa843e6 (patch)
treef17f58c9a14700e76c4b54b242c0bca061199e1f /subprojects/viatra-runtime-matchers
parentchore: import VIATRA source (diff)
downloadrefinery-fc7e3dc61a2ac8de32914af331c1144e4fa843e6.tar.gz
refinery-fc7e3dc61a2ac8de32914af331c1144e4fa843e6.tar.zst
refinery-fc7e3dc61a2ac8de32914af331c1144e4fa843e6.zip
refactor: remove unused VIATRA code
We don't need Eclipse platform support, table-based scopes, and EMF support.
Diffstat (limited to 'subprojects/viatra-runtime-matchers')
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java53
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java51
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java132
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java119
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java266
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java143
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java192
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java212
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java29
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java53
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java52
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java52
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java320
-rw-r--r--subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java140
14 files changed, 0 insertions, 1814 deletions
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java
deleted file mode 100644
index 16f40358..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/IStorageBackend.java
+++ /dev/null
@@ -1,53 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.scopes;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableContext;
13import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableWriterBinary;
14import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableWriterUnary;
15
16/**
17 * An abstract storage backend that instantiates tables and coordinates transactions.
18 *
19 * <p><strong>EXPERIMENTAL</strong>. This class or interface has been added as
20 * part of a work in progress. There is no guarantee that this API will
21 * work or that it will remain the same.
22 *
23 * @author Gabor Bergmann
24 *
25 * @since 2.1
26 */
27public interface IStorageBackend {
28
29
30 /**
31 * Marks the beginning of a transaction.
32 * In transaction mode, table updates may be temporarily delayed ({@link tools.refinery.viatra.runtime.matchers.scopes.tables.IIndexTable} methods may return stale answers) for better performance.
33 */
34 void startTransaction();
35 /**
36 * Marks the end of a transaction.
37 * Any updates delayed during the transaction must now be flushed.
38 */
39 void finishTransaction();
40
41 /**
42 * Creates an index table for a simple value set.
43 * @param unique client promises to only insert a given tuple with multiplicity one
44 */
45 ITableWriterUnary.Table<Object> createUnaryTable(IInputKey key, ITableContext tableContext, boolean unique);
46 /**
47 * Creates an index table for a simple source-target bidirectional mapping.
48 * @param unique client promises to only insert a given tuple with multiplicity one
49 */
50 ITableWriterBinary.Table<Object,Object> createBinaryTable(IInputKey key, ITableContext tableContext, boolean unique);
51
52
53}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java
deleted file mode 100644
index fd1f7b7e..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleLocalStorageBackend.java
+++ /dev/null
@@ -1,51 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.scopes;
10
11import tools.refinery.viatra.runtime.matchers.context.IInputKey;
12import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableContext;
13import tools.refinery.viatra.runtime.matchers.scopes.tables.SimpleBinaryTable;
14import tools.refinery.viatra.runtime.matchers.scopes.tables.SimpleUnaryTable;
15
16/**
17 * Basic storage backend implementation based on local collections.
18 *
19 * <p><strong>EXPERIMENTAL</strong>. This class or interface has been added as
20 * part of a work in progress. There is no guarantee that this API will
21 * work or that it will remain the same.
22 *
23 * @author Gabor Bergmann
24 * @since 2.1
25 */
26public class SimpleLocalStorageBackend implements IStorageBackend {
27
28 @Override
29 public void startTransaction() {
30 // NOP
31 }
32
33 @Override
34 public void finishTransaction() {
35 // NOP
36 }
37
38 @Override
39 public SimpleUnaryTable<Object> createUnaryTable(IInputKey key, ITableContext tableContext, boolean unique) {
40 return new SimpleUnaryTable<>(key, tableContext, unique);
41 }
42
43 @Override
44 public SimpleBinaryTable<Object, Object> createBinaryTable(IInputKey key, ITableContext tableContext,
45 boolean unique) {
46 return new SimpleBinaryTable<>(key, tableContext, unique);
47 }
48
49
50
51}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java
deleted file mode 100644
index a3a827dc..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/SimpleRuntimeContext.java
+++ /dev/null
@@ -1,132 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes;
11
12import java.lang.reflect.InvocationTargetException;
13import java.util.concurrent.Callable;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.context.IndexingService;
18import tools.refinery.viatra.runtime.matchers.context.common.JavaTransitiveInstancesKey;
19import tools.refinery.viatra.runtime.matchers.scopes.tables.IIndexTable;
20import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22
23/**
24 * A simple demo implementation of the IQRC interface using tables.
25 *
26 * <p>
27 * Usage: first, instantiate {@link IIndexTable} tables with this as the 'tableContext' argument, and call
28 * {@link #registerIndexTable(IIndexTable)} manually to register them. Afterwards, they will be visible to the query
29 * backends.
30 * <p>
31 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
32 * part of a work in progress. There is no guarantee that this API will
33 * work or that it will remain the same.
34 *
35 * @author Gabor Bergmann
36 * @since 2.0
37 */
38public class SimpleRuntimeContext extends TabularRuntimeContext {
39
40 private IQueryMetaContext metaContext;
41
42 public SimpleRuntimeContext(IQueryMetaContext metaContext) {
43 this.metaContext = metaContext;
44 }
45
46 @Override
47 public void logError(String message) {
48 System.err.println(message);
49 }
50
51 @Override
52 public IQueryMetaContext getMetaContext() {
53 return metaContext;
54 }
55
56 @Override
57 public <V> V coalesceTraversals(Callable<V> callable) throws InvocationTargetException {
58 try {
59 return callable.call();
60 } catch (Exception e) {
61 throw new InvocationTargetException(e);
62 }
63 }
64
65 @Override
66 public boolean isCoalescing() {
67 return false;
68 }
69
70 @Override
71 public boolean isIndexed(IInputKey key, IndexingService service) {
72 return peekIndexTable(key) != null;
73 }
74
75 @Override
76 public void ensureIndexed(IInputKey key, IndexingService service) {
77 if (peekIndexTable(key) == null)
78 throw new IllegalArgumentException(key.getPrettyPrintableName());
79 }
80
81 @Override
82 public Object wrapElement(Object externalElement) {
83 return externalElement;
84 }
85
86 @Override
87 public Object unwrapElement(Object internalElement) {
88 return internalElement;
89 }
90
91 @Override
92 public Tuple wrapTuple(Tuple externalElements) {
93 return externalElements;
94 }
95
96 @Override
97 public Tuple unwrapTuple(Tuple internalElements) {
98 return internalElements;
99 }
100
101 @Override
102 public void ensureWildcardIndexing(IndexingService service) {
103 throw new UnsupportedOperationException();
104 }
105
106 @Override
107 public void executeAfterTraversal(Runnable runnable) throws InvocationTargetException {
108 runnable.run();
109 }
110
111 @Override
112 protected boolean isContainedInStatelessKey(IInputKey key, ITuple seed) {
113 if (key instanceof JavaTransitiveInstancesKey) {
114 Class<?> instanceClass = forceGetWrapperInstanceClass((JavaTransitiveInstancesKey) key);
115 return instanceClass != null && instanceClass.isInstance(seed.get(0));
116 } else
117 throw new IllegalArgumentException(key.getPrettyPrintableName());
118 }
119
120 private Class<?> forceGetWrapperInstanceClass(JavaTransitiveInstancesKey key) {
121 Class<?> instanceClass;
122 try {
123 instanceClass = key.forceGetWrapperInstanceClass();
124 } catch (ClassNotFoundException e) {
125 logError(
126 "Could not load instance class for type constraint " + key.getWrappedKey() + ": " + e.getMessage());
127 instanceClass = null;
128 }
129 return instanceClass;
130 }
131
132}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java
deleted file mode 100644
index e99e24d3..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/TabularRuntimeContext.java
+++ /dev/null
@@ -1,119 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes;
11
12import java.util.Map;
13import java.util.Optional;
14
15import tools.refinery.viatra.runtime.matchers.context.AbstractQueryRuntimeContext;
16import tools.refinery.viatra.runtime.matchers.context.IInputKey;
17import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
18import tools.refinery.viatra.runtime.matchers.scopes.tables.IIndexTable;
19import tools.refinery.viatra.runtime.matchers.scopes.tables.ITableContext;
20import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
23import tools.refinery.viatra.runtime.matchers.util.Accuracy;
24import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
25
26/**
27 * An abstract runtime context that serves enumerable input key instances from tables.
28 *
29 * <p>
30 * Usage: first, instantiate {@link IIndexTable} tables with this as the 'tableContext' argument. Call
31 * {@link #registerIndexTable(IIndexTable)} to register them; this may happen either during a coalesced indexing, or on
32 * external initiation. Afterwards, they will be visible to the query backends.
33 * <p>
34 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
35 * part of a work in progress. There is no guarantee that this API will
36 * work or that it will remain the same.
37 *
38 * @author Gabor Bergmann
39 * @since 2.0
40 */
41public abstract class TabularRuntimeContext extends AbstractQueryRuntimeContext implements ITableContext {
42
43 private Map<IInputKey, IIndexTable> instanceTables = CollectionsFactory.createMap();
44
45 public void registerIndexTable(IIndexTable table) {
46 IInputKey inputKey = table.getInputKey();
47 instanceTables.put(inputKey, table);
48 }
49
50 /**
51 * @return null if the table is not registered
52 */
53 public IIndexTable peekIndexTable(IInputKey key) {
54 return instanceTables.get(key);
55 }
56
57 /**
58 * If the table is not registered, {@link #handleUnregisteredTableRequest(IInputKey)} is invoked; it may handle it
59 * by raising an error or e.g. on-demand index construction
60 */
61 public IIndexTable getIndexTable(IInputKey key) {
62 IIndexTable table = instanceTables.get(key);
63 if (table != null)
64 return table;
65 else
66 return handleUnregisteredTableRequest(key);
67 }
68
69 /**
70 * Override this to provide on-demand table registration
71 */
72 protected IIndexTable handleUnregisteredTableRequest(IInputKey key) {
73 throw new IllegalArgumentException(key.getPrettyPrintableName());
74 }
75
76 @Override
77 public int countTuples(IInputKey key, TupleMask seedMask, ITuple seed) {
78 return getIndexTable(key).countTuples(seedMask, seed);
79 }
80
81 @Override
82 public Optional<Long> estimateCardinality(IInputKey key, TupleMask groupMask, Accuracy requiredAccuracy) {
83 return getIndexTable(key).estimateProjectionSize(groupMask, requiredAccuracy);
84 }
85
86 @Override
87 public Iterable<Tuple> enumerateTuples(IInputKey key, TupleMask seedMask, ITuple seed) {
88 return getIndexTable(key).enumerateTuples(seedMask, seed);
89 }
90
91 @Override
92 public Iterable<? extends Object> enumerateValues(IInputKey key, TupleMask seedMask, ITuple seed) {
93 return getIndexTable(key).enumerateValues(seedMask, seed);
94 }
95
96 @Override
97 public boolean containsTuple(IInputKey key, ITuple seed) {
98 if (key.isEnumerable()) {
99 return getIndexTable(key).containsTuple(seed);
100 } else {
101 return isContainedInStatelessKey(key, seed);
102 }
103 }
104
105 @Override
106 public void addUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
107 getIndexTable(key).addUpdateListener(seed, listener);
108 }
109 @Override
110 public void removeUpdateListener(IInputKey key, Tuple seed, IQueryRuntimeContextListener listener) {
111 getIndexTable(key).removeUpdateListener(seed, listener);
112 }
113
114 /**
115 * Handles non-enumerable input keys that are not backed by a table
116 */
117 protected abstract boolean isContainedInStatelessKey(IInputKey key, ITuple seed);
118
119}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java
deleted file mode 100644
index 7b557c33..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/AbstractIndexTable.java
+++ /dev/null
@@ -1,266 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.scopes.tables;
10
11import java.util.List;
12
13import tools.refinery.viatra.runtime.matchers.context.IInputKey;
14import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
15import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
16import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
18import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
19import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
20import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
21
22/**
23 * <p>
24 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
25 * part of a work in progress. There is no guarantee that this API will
26 * work or that it will remain the same.
27 *
28 * @since 2.0
29 * @author Gabor Bergmann
30 */
31public abstract class AbstractIndexTable implements IIndexTable {
32
33 private IInputKey inputKey;
34 protected ITableContext tableContext;
35
36 protected final TupleMask emptyMask;
37 protected final Tuple emptyTuple;
38
39
40 public AbstractIndexTable(IInputKey inputKey, ITableContext tableContext) {
41 this.inputKey = inputKey;
42 this.tableContext = tableContext;
43
44 this.emptyMask = TupleMask.empty(getInputKey().getArity());
45 this.emptyTuple = Tuples.flatTupleOf(new Object[inputKey.getArity()]);
46 }
47
48 @Override
49 public String toString() {
50 return this.getClass().getSimpleName() + ":" + inputKey.getPrettyPrintableName();
51 }
52
53 @Override
54 public IInputKey getInputKey() {
55 return inputKey;
56 }
57
58 protected void logError(String message) {
59 tableContext.logError(message);
60 }
61
62
63 /// UPDATE HANDLING SECTION
64
65 // The entire mechanism is designed to accommodate a large number of update listeners,
66 // but maybe there will typically be only a single, universal (unseeded) listener?
67 // TODO Create special handling for that case.
68
69 // Invariant: true iff #listenerGroupsAndSeed is nonempty
70 protected boolean emitNotifications = false;
71 // Subscribed listeners grouped by their seed mask (e.g. all those that seed columns 2 and 5 are together),
72 // groups are stored in a list for quick delivery-time iteration (at the expense of adding / removing);
73 // individual listeners can be looked up based on their seed tuple
74 protected List<IListenersWithSameMask> listenerGroups = CollectionsFactory.createObserverList();
75
76
77 /**
78 * Implementors shall call this to deliver all notifications.
79 * Call may be conditioned to {@link #emitNotifications}
80 */
81 protected void deliverChangeNotifications(Tuple updateTuple, boolean isInsertion) {
82 for (IListenersWithSameMask listenersForSeed : listenerGroups) {
83 listenersForSeed.deliver(updateTuple, isInsertion);
84 }
85 }
86
87 @Override
88 public void addUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
89 TupleMask seedMask;
90 if (seed == null) {
91 seed = emptyTuple;
92 seedMask = emptyMask;
93 } else {
94 seedMask = TupleMask.fromNonNullIndices(seed);
95 }
96 IListenersWithSameMask listenerGroup = getListenerGroup(seedMask);
97 if (listenerGroup == null) { // create new group
98 switch (seedMask.getSize()) {
99 case 0:
100 listenerGroup = new UniversalListeners();
101 break;
102 case 1:
103 listenerGroup = new ColumnBoundListeners(seedMask.indices[0]);
104 break;
105 default:
106 listenerGroup = new GenericBoundListeners(seedMask);
107 }
108 listenerGroups.add(listenerGroup);
109 emitNotifications = true;
110 }
111 listenerGroup.addUpdateListener(seed, listener);
112 }
113
114 @Override
115 public void removeUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
116 TupleMask seedMask;
117 if (seed == null) {
118 seed = emptyTuple;
119 seedMask = emptyMask;
120 } else {
121 seedMask = TupleMask.fromNonNullIndices(seed);
122 }
123 IListenersWithSameMask listenerGroup = getListenerGroup(seedMask);
124 if (listenerGroup == null)
125 throw new IllegalStateException("no listener subscribed with mask" + seedMask);
126
127 if (listenerGroup.removeUpdateListener(seed, listener)) {
128 listenerGroups.remove(listenerGroup);
129 emitNotifications = !listenerGroups.isEmpty();
130 }
131 }
132
133 protected IListenersWithSameMask getListenerGroup(TupleMask seedMask) {
134 for (IListenersWithSameMask candidateGroup : listenerGroups) { // group already exists?
135 if (seedMask.equals(candidateGroup.getSeedMask())) {
136 return candidateGroup;
137 }
138 }
139 return null;
140 }
141
142
143 /**
144 * Represents all listeners subscribed to seeds with the given seed mask.
145 *
146 * @author Bergmann Gabor
147 */
148 protected static interface IListenersWithSameMask {
149
150 public TupleMask getSeedMask();
151
152 public void deliver(Tuple updateTuple, boolean isInsertion);
153
154 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener);
155 /**
156 * @return true if this was the last listener, and the {@link IListenersWithSameMask} can be disposed of.
157 */
158 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener);
159 }
160 /**
161 * Listeners interested in all tuples
162 */
163 protected final class UniversalListeners implements IListenersWithSameMask {
164 private final TupleMask mask = TupleMask.empty(inputKey.getArity());
165 private List<IQueryRuntimeContextListener> listeners = CollectionsFactory.createObserverList();
166
167 @Override
168 public TupleMask getSeedMask() {
169 return mask;
170 }
171 @Override
172 public void deliver(Tuple updateTuple, boolean isInsertion) {
173 IInputKey key = inputKey;
174 for (IQueryRuntimeContextListener listener : listeners) {
175 listener.update(key, updateTuple, isInsertion);
176 }
177 }
178 @Override
179 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
180 listeners.add(listener);
181 }
182 @Override
183 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
184 listeners.remove(listener);
185 return listeners.isEmpty();
186 }
187 }
188 /**
189 * Listeners interested in all tuples seeded by a single columns
190 */
191 protected final class ColumnBoundListeners implements IListenersWithSameMask {
192 private int seedPosition;
193 protected final TupleMask mask;
194 // indexed by projected seed tuple
195 protected IMultiLookup<Object,IQueryRuntimeContextListener> listeners =
196 CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
197
198 public ColumnBoundListeners(int seedPosition) {
199 this.seedPosition = seedPosition;
200 this.mask = TupleMask.selectSingle(seedPosition, inputKey.getArity());
201 }
202
203 @Override
204 public TupleMask getSeedMask() {
205 return mask;
206 }
207 @Override
208 public void deliver(Tuple updateTuple, boolean isInsertion) {
209 IInputKey key = inputKey;
210 Object projectedSeed = updateTuple.get(seedPosition);
211 for (IQueryRuntimeContextListener listener : listeners.lookupOrEmpty(projectedSeed)) {
212 listener.update(key, updateTuple, isInsertion);
213 }
214 }
215 @Override
216 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
217 Object projectedSeed = originalSeed.get(seedPosition);
218 listeners.addPair(projectedSeed, listener);
219 }
220 @Override
221 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
222 Object projectedSeed = originalSeed.get(seedPosition);
223 listeners.removePair(projectedSeed, listener);
224 return listeners.countKeys() == 0;
225 }
226 }
227 /**
228 * Listeners interested in all tuples seeded by a tuple of values
229 */
230 protected final class GenericBoundListeners implements IListenersWithSameMask {
231 protected final TupleMask mask;
232 // indexed by projected seed tuple
233 protected IMultiLookup<Tuple,IQueryRuntimeContextListener> listeners =
234 CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, Object.class);
235
236 public GenericBoundListeners(TupleMask mask) {
237 this.mask = mask;
238 }
239
240 @Override
241 public TupleMask getSeedMask() {
242 return mask;
243 }
244 @Override
245 public void deliver(Tuple updateTuple, boolean isInsertion) {
246 IInputKey key = inputKey;
247 Tuple projectedSeed = mask.transform(updateTuple);
248 for (IQueryRuntimeContextListener listener : listeners.lookupOrEmpty(projectedSeed)) {
249 listener.update(key, updateTuple, isInsertion);
250 }
251 }
252 @Override
253 public void addUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
254 Tuple projectedSeed = mask.transform(originalSeed);
255 listeners.addPair(projectedSeed, listener);
256 }
257 @Override
258 public boolean removeUpdateListener(Tuple originalSeed, IQueryRuntimeContextListener listener) {
259 Tuple projectedSeed = mask.transform(originalSeed);
260 listeners.removePair(projectedSeed, listener);
261 return listeners.countKeys() == 0;
262 }
263 }
264
265
266} \ No newline at end of file
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java
deleted file mode 100644
index 39475d11..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DefaultIndexTable.java
+++ /dev/null
@@ -1,143 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.scopes.tables;
10
11import java.util.Map;
12import java.util.Optional;
13import java.util.stream.Stream;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.memories.MaskedTupleMemory;
17import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.util.Accuracy;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
23import tools.refinery.viatra.runtime.matchers.util.Direction;
24import tools.refinery.viatra.runtime.matchers.util.IMemory;
25
26/**
27 * Demo default implementation.
28 * <p>
29 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
30 * part of a work in progress. There is no guarantee that this API will
31 * work or that it will remain the same.
32 *
33 * @since 2.0
34 * @author Gabor Bergmann
35 */
36public class DefaultIndexTable extends AbstractIndexTable implements ITableWriterGeneric {
37
38 protected IMemory<Tuple> rows = CollectionsFactory.createMultiset(); // TODO use SetMemory if unique
39 protected Map<TupleMask, MaskedTupleMemory<?>> indexMemories = CollectionsFactory.createMap();
40 private boolean unique;
41
42 /**
43 * @param unique
44 * client promises to only insert a given tuple with multiplicity one
45 */
46 public DefaultIndexTable(IInputKey inputKey, ITableContext tableContext, boolean unique) {
47 super(inputKey, tableContext);
48 this.unique = unique;
49 }
50
51 @Override
52 public void write(Direction direction, Tuple row) {
53 if (direction == Direction.INSERT) {
54 boolean changed = rows.addOne(row);
55 if (unique && !changed) {
56 String msg = String.format(
57 "Error: trying to add duplicate row %s to the unique table %s. This indicates some errors in underlying model representation.",
58 row, getInputKey().getPrettyPrintableName());
59 logError(msg);
60 }
61 if (changed) {
62 for (MaskedTupleMemory<?> indexMemory : indexMemories.values()) {
63 indexMemory.add(row);
64 }
65 if (emitNotifications) {
66 deliverChangeNotifications(row, true);
67 }
68 }
69 } else { // DELETE
70 boolean changed = rows.removeOne(row);
71 if (unique && !changed) {
72 String msg = String.format(
73 "Error: trying to remove duplicate value %s from the unique table %s. This indicates some errors in underlying model representation.",
74 row, getInputKey().getPrettyPrintableName());
75 logError(msg);
76 }
77 if (changed) {
78 for (MaskedTupleMemory<?> indexMemory : indexMemories.values()) {
79 indexMemory.remove(row);
80 }
81 if (emitNotifications) {
82 deliverChangeNotifications(row, false);
83 }
84 }
85 }
86 }
87
88 @Override
89 public boolean containsTuple(ITuple seed) {
90 return rows.distinctValues().contains(seed);
91 }
92
93 private MaskedTupleMemory<?> getIndexMemory(TupleMask seedMask) {
94 return indexMemories.computeIfAbsent(seedMask, mask -> {
95 MaskedTupleMemory<?> memory = MaskedTupleMemory.create(seedMask, MemoryType.SETS, DefaultIndexTable.this);
96 for (Tuple tuple : rows.distinctValues()) {
97 memory.add(tuple);
98 }
99 return memory;
100 });
101 }
102
103 @Override
104 public int countTuples(TupleMask seedMask, ITuple seed) {
105 switch (seedMask.getSize()) {
106 case 0: // unseeded
107 return rows.size();
108 default:
109 return getIndexMemory(seedMask).getOrEmpty(seed).size();
110 }
111 }
112
113 @Override
114 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
115 // always exact count
116 if (groupMask.getSize() == 0) {
117 return rows.size() == 0 ? Optional.of(0L) : Optional.of(1L);
118 } else if (groupMask.getSize() == this.emptyTuple.getSize()) {
119 return Optional.of((long) rows.size());
120 } else {
121 return Optional.of((long)getIndexMemory(groupMask).getKeysetSize());
122 }
123 }
124
125 @Override
126 public Iterable<Tuple> enumerateTuples(TupleMask seedMask, ITuple seed) {
127 return getIndexMemory(seedMask).getOrEmpty(seed);
128 }
129
130 @Override
131 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
132 return getIndexMemory(seedMask).getOrEmpty(seed).stream();
133 }
134
135 @Override
136 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
137 // we assume there is a single omitted index in the mask
138 int queriedColumn = seedMask.getFirstOmittedIndex().getAsInt();
139 return getIndexMemory(seedMask).getOrEmpty(seed).stream()
140 .map(row2 -> row2.get(queriedColumn));
141 }
142
143}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java
deleted file mode 100644
index a3a65f14..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/DisjointUnionTable.java
+++ /dev/null
@@ -1,192 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes.tables;
11
12import java.util.Collections;
13import java.util.List;
14import java.util.Objects;
15import java.util.Optional;
16import java.util.stream.Stream;
17
18import tools.refinery.viatra.runtime.matchers.context.IInputKey;
19import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
20import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
21import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
22import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
23import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
24import tools.refinery.viatra.runtime.matchers.util.Accuracy;
25import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
26
27/**
28 * Disjoint union of the provided child tables.
29 *
30 * Used e.g. to present a transitive instance table as a view composed from direct instance tables.
31 * <p>
32 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
33 * part of a work in progress. There is no guarantee that this API will
34 * work or that it will remain the same.
35 *
36 * @since 2.0
37 * @author Gabor Bergmann
38 */
39public class DisjointUnionTable extends AbstractIndexTable {
40
41 protected List<IIndexTable> childTables = CollectionsFactory.createObserverList();
42
43 public DisjointUnionTable(IInputKey inputKey, ITableContext tableContext) {
44 super(inputKey, tableContext);
45 }
46
47 public List<IIndexTable> getChildTables() {
48 return Collections.unmodifiableList(childTables);
49 }
50
51 /**
52 * Precondition: the new child currently is, and will forever stay, disjoint from any other child tables.
53 */
54 public void addChildTable(IIndexTable child) {
55 if (getInputKey().getArity() != child.getInputKey().getArity())
56 throw new IllegalArgumentException(child.toString());
57
58 childTables.add(child);
59
60 if (emitNotifications) {
61 for (Tuple tuple : child.enumerateTuples(emptyMask, Tuples.staticArityFlatTupleOf())) {
62 deliverChangeNotifications(tuple, true);
63 }
64 }
65 }
66
67 @Override
68 public int countTuples(TupleMask seedMask, ITuple seed) {
69 int count = 0;
70 for (IIndexTable child : childTables) {
71 count += child.countTuples(seedMask, seed);
72 }
73 return count;
74 }
75
76
77 @Override
78 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
79 // exact results for trivial projections
80 if (groupMask.getSize() == 0) {
81 for (IIndexTable child : childTables) {
82 if (0 != child.countTuples(this.emptyMask, Tuples.staticArityFlatTupleOf()))
83 return Optional.of(1L);
84 }
85 return Optional.of(0L);
86 } else if (groupMask.getSize() == emptyTuple.getSize()) {
87 return Optional.of((long)countTuples(this.emptyMask, Tuples.staticArityFlatTupleOf()));
88 }
89 // summing child tables is an upper bound
90 if (Accuracy.BEST_UPPER_BOUND.atLeastAsPreciseAs(requiredAccuracy)) {
91 return Optional.of((long)countTuples(this.emptyMask, Tuples.staticArityFlatTupleOf()));
92 } else { // (Accuracy.BEST_LOWER_BOUND == requiredAccuracy)
93 //projections of child tables may coincide, but the largest one is still a lower bound
94 Optional<Long> maxProjection = Optional.empty();
95 for (IIndexTable child : childTables) {
96 Optional<Long> estimateOfChild = child.estimateProjectionSize(groupMask, requiredAccuracy);
97 if (estimateOfChild.isPresent()) {
98 maxProjection = Optional.of(Math.max(estimateOfChild.get(), maxProjection.orElse(0L)));
99 }
100 }
101 return maxProjection;
102 }
103 }
104
105 @Override
106 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
107 Stream<? extends Tuple> stream = Stream.empty();
108 for (IIndexTable child : childTables) {
109 Stream<? extends Tuple> childStream = child.streamTuples(seedMask, seed);
110 stream = Stream.concat(stream, childStream);
111 }
112 return stream;
113 }
114
115 @Override
116 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
117 Stream<? extends Object> stream = Stream.empty();
118 for (IIndexTable child : childTables) {
119 Stream<? extends Object> childStream = child.streamValues(seedMask, seed);
120 stream = Stream.concat(stream, childStream);
121 }
122 return stream;
123 }
124
125 @Override
126 public boolean containsTuple(ITuple seed) {
127 for (IIndexTable child : childTables) {
128 if (child.containsTuple(seed))
129 return true;
130 }
131 return false;
132 }
133
134 @Override
135 public void addUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
136 super.addUpdateListener(seed, listener);
137
138 for (IIndexTable table : childTables) {
139 table.addUpdateListener(seed, new ListenerWrapper(listener));
140 }
141 }
142 @Override
143 public void removeUpdateListener(Tuple seed, IQueryRuntimeContextListener listener) {
144 super.removeUpdateListener(seed, listener);
145
146 for (IIndexTable table : childTables) {
147 table.removeUpdateListener(seed, new ListenerWrapper(listener));
148 }
149 }
150
151
152 // TODO this would not be necessary
153 // if we moved from IQRCL to an interface that does not expose the input key
154 private class ListenerWrapper implements IQueryRuntimeContextListener {
155
156 private IQueryRuntimeContextListener wrappedListener;
157 public ListenerWrapper(IQueryRuntimeContextListener wrappedListener) {
158 this.wrappedListener = wrappedListener;
159 }
160
161 @Override
162 public void update(IInputKey key, Tuple updateTuple, boolean isInsertion) {
163 wrappedListener.update(getInputKey(), updateTuple, isInsertion);
164 }
165
166 @Override
167 public int hashCode() {
168 return Objects.hash(wrappedListener, DisjointUnionTable.this);
169 }
170 @Override
171 public boolean equals(Object obj) {
172 if (this == obj)
173 return true;
174 if (obj == null)
175 return false;
176 if (getClass() != obj.getClass())
177 return false;
178 ListenerWrapper other = (ListenerWrapper) obj;
179 if (!getOuterType().equals(other.getOuterType()))
180 return false;
181 return Objects.equals(wrappedListener, other.wrappedListener);
182 }
183 private DisjointUnionTable getOuterType() {
184 return DisjointUnionTable.this;
185 }
186 @Override
187 public String toString() {
188 return "Wrapper to DisjointUnion("+getInputKey().getPrettyPrintableName()+") for " + wrappedListener;
189 }
190 }
191
192}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java
deleted file mode 100644
index be375393..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/IIndexTable.java
+++ /dev/null
@@ -1,212 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.scopes.tables;
10
11import java.util.Iterator;
12import java.util.Optional;
13import java.util.stream.Stream;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
17import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext;
18import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContextListener;
19import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
21import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
22import tools.refinery.viatra.runtime.matchers.util.Accuracy;
23
24/**
25 * Read-only interface that provides the {@link IInputKey}-specific slice of an instance store to realize a
26 * {@link IQueryRuntimeContext}. Implemented by a customizable data store that is responsible for:
27 * <ul>
28 * <li>storing the instance tuples of the {@link IInputKey},</li>
29 * <li>providing efficient lookup via storage-specific indexing,</li>
30 * <li>delivering notifications. (TODO not designed yet)</li>
31 * </ul>
32 *
33 * <p>
34 * Can be specialized for unary / binary / etc., opposite edges or node subtypes, specific types, distributed storage,
35 * etc.
36 * <p>
37 * Writeable API is specific to the customized implementations (e.g. unary).
38 *
39 * <p>
40 * <b>Precondition:</b> the associated input key is enumerable, see {@link IQueryMetaContext#isEnumerable(IInputKey)}.
41 * <p>
42 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
43 * part of a work in progress. There is no guarantee that this API will
44 * work or that it will remain the same.
45 *
46 * @since 2.0
47 * @author Gabor Bergmann
48 * @noimplement This interface is not intended to be implemented directly. Extend {@link AbstractIndexTable} instead.
49 */
50public interface IIndexTable {
51
52 // TODO add superinterface that represents a statistics-only counter?
53
54 /**
55 * @return the input key indexed by this table
56 */
57 public IInputKey getInputKey();
58
59 /**
60 * Returns the tuples, optionally seeded with the given tuple.
61 *
62 * <p> Consider using the more idiomatic {@link #streamTuples(TupleMask, ITuple)} instead.
63 *
64 * @param seedMask
65 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
66 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
67 * once in seedMask.
68 * @param seed
69 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
70 * parameterSeedMask, so that for each considered row tuple,
71 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
72 * @return the tuples in the table for the given key and seed
73 */
74 @SuppressWarnings("unchecked")
75 public default Iterable<Tuple> enumerateTuples(TupleMask seedMask, ITuple seed) {
76 return () -> (Iterator<Tuple>) (streamTuples(seedMask, seed).iterator());
77 }
78
79 /**
80 * Returns the tuples, optionally seeded with the given tuple.
81 *
82 * @param seedMask
83 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
84 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
85 * once in seedMask.
86 * @param seed
87 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
88 * parameterSeedMask, so that for each considered row tuple,
89 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
90 * @return the tuples in the table for the given key and seed
91 * @since 2.1
92 */
93 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed);
94
95 /**
96 * Simpler form of {@link #enumerateTuples(TupleMask, ITuple)} in the case where all values of the tuples are bound
97 * by the seed except for one.
98 *
99 * <p>
100 * Selects the tuples in the table, optionally seeded with the given tuple, and then returns the single value from
101 * each tuple which is not bound by the seed mask.
102 *
103 * <p> Consider using the more idiomatic {@link #streamValues(TupleMask, ITuple)} instead.
104 *
105 * @param seedMask
106 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
107 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
108 * once in seedMask, and seedMask must include all parameters in any arbitrary order except one.
109 * @param seed
110 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
111 * parameterSeedMask, so that for each considered row tuple,
112 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
113 * @return the objects in the table for the given key and seed
114 *
115 */
116 @SuppressWarnings("unchecked")
117 public default Iterable<? extends Object> enumerateValues(TupleMask seedMask, ITuple seed) {
118 return () -> (Iterator<Object>) (streamValues(seedMask, seed).iterator());
119 }
120
121 /**
122 * Simpler form of {@link #enumerateTuples(TupleMask, ITuple)} in the case where all values of the tuples are bound
123 * by the seed except for one.
124 *
125 * <p>
126 * Selects the tuples in the table, optionally seeded with the given tuple, and then returns the single value from
127 * each tuple which is not bound by the seed mask.
128 *
129 * @param seedMask
130 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
131 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
132 * once in seedMask, and seedMask must include all parameters in any arbitrary order except one.
133 * @param seed
134 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
135 * parameterSeedMask, so that for each considered row tuple,
136 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
137 * @return the objects in the table for the given key and seed
138 *
139 * @since 2.1
140 */
141 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed);
142
143 /**
144 * Simpler form of {@link #enumerateTuples(TupleMask, ITuple)} in the case where all values of the tuples are bound
145 * by the seed.
146 *
147 * <p>
148 * Returns whether the given tuple is in the table identified by the input key.
149 *
150 * @param seed
151 * a row tuple of fixed values whose presence in the table is queried
152 * @return true iff there is a row tuple contained in the table that corresponds to the given seed
153 */
154 public boolean containsTuple(ITuple seed);
155
156 /**
157 * Returns the number of tuples, optionally seeded with the given tuple.
158 *
159 * <p>
160 * Selects the tuples in the table, optionally seeded with the given tuple, and then returns their number.
161 *
162 * @param seedMask
163 * a mask that extracts those parameters of the input key (from the entire parameter list) that should be
164 * bound to a fixed value; must not be null. <strong>Note</strong>: any given index must occur at most
165 * once in seedMask.
166 * @param seed
167 * the tuple of fixed values restricting the row set to be considered, in the same order as given in
168 * parameterSeedMask, so that for each considered row tuple,
169 * projectedParameterSeed.equals(parameterSeedMask.transform(row)) should hold. Must not be null.
170 * @return the number of tuples in the table for the given key and seed
171 *
172 */
173 public int countTuples(TupleMask seedMask, ITuple seed);
174
175 /**
176 * Gives an estimate of the number of different groups the tuples of the table are projected into by the given mask
177 * (e.g. for an identity mask, this means the full relation size). The estimate must meet the required accuracy.
178 *
179 * <p> Derived tables may return {@link Optional#empty()} if it would be costly to provide an answer up to the required precision.
180 * Direct storage tables are expected to always be able to give an exact count.
181 *
182 * <p> PRE: {@link TupleMask#isNonrepeating()} must hold for the group mask.
183 *
184 * @since 2.1
185 */
186 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy);
187
188 /**
189 * Subscribes for updates in the table, optionally seeded with the given tuple.
190 * <p> This should be called after initializing a result cache by an enumeration method.
191 *
192 * @param seed can be null or a tuple with matching arity;
193 * if non-null, notifications will delivered only about those updates of the table
194 * that match the seed at positions where the seed is non-null.
195 * @param listener will be notified of future changes
196 *
197 * @since 2.1
198 */
199 public void addUpdateListener(Tuple seed, IQueryRuntimeContextListener listener);
200
201 /**
202 * Unsubscribes from updates in the table, optionally seeded with the given tuple.
203 *
204 * @param seed can be null or a tuple with matching arity;
205 * see {@link #addUpdateListener(Tuple, IQueryRuntimeContextListener)} for definition.
206 * @param listener will no longer be notified of future changes
207 *
208 * @since 2.1
209 */
210 public void removeUpdateListener(Tuple seed, IQueryRuntimeContextListener listener);
211
212}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java
deleted file mode 100644
index 69e83cd7..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableContext.java
+++ /dev/null
@@ -1,29 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.scopes.tables;
10
11/**
12 * Callbacks that {@link IIndexTable} implementations are expected to invoke on their environment.
13 * <p>
14 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
15 * part of a work in progress. There is no guarantee that this API will
16 * work or that it will remain the same.
17 *
18 * @since 2.0
19 * @author Gabor Bergmann
20 */
21public interface ITableContext {
22
23 // TODO notifications?
24
25 /**
26 * Indicates that an error has occurred in maintaining an index table, e.g. duplicate value.
27 */
28 public void logError(String message);
29}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java
deleted file mode 100644
index fb614014..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterBinary.java
+++ /dev/null
@@ -1,53 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes.tables;
11
12import tools.refinery.viatra.runtime.matchers.util.Direction;
13
14/**
15 * Modifies the contents of a binary {@link IIndexTable}.
16 * <p>
17 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
18 * part of a work in progress. There is no guarantee that this API will
19 * work or that it will remain the same.
20 *
21 * @since 2.0
22 * @author Gabor Bergmann
23 */
24public interface ITableWriterBinary<Source, Target> {
25 /**
26 * Adds/removes a row to/from the table.
27 *
28 * @param direction
29 * tells whether putting a row into the table or deleting
30 *
31 * TODO: store as multiset, return bool?
32 */
33 void write(Direction direction, Source source, Target target);
34
35 /**
36 * Intersection type for writers that are also tables
37 */
38 interface Table<Source, Target> extends ITableWriterBinary<Source, Target>, IIndexTable {
39 }
40
41 /**
42 * /dev/null implementation
43 *
44 * @author Gabor Bergmann
45 */
46 static class Nop<Source, Target> implements ITableWriterBinary<Source, Target> {
47 @Override
48 public void write(Direction direction, Source source, Target target) {
49 // NO-OP
50 }
51
52 }
53}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java
deleted file mode 100644
index fb1ebcc0..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterGeneric.java
+++ /dev/null
@@ -1,52 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.scopes.tables;
10
11import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
12import tools.refinery.viatra.runtime.matchers.util.Direction;
13
14/**
15 * Modifies the contents of an {@link IIndexTable}.
16 * <p>
17 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
18 * part of a work in progress. There is no guarantee that this API will
19 * work or that it will remain the same.
20 *
21 * @since 2.0
22 * @author Gabor Bergmann
23 */
24public interface ITableWriterGeneric {
25
26 /**
27 * Adds/removes a row to/from the table.
28 *
29 * @param direction
30 * tells whether putting a row into the table or deleting TODO: store as multiset, return bool?
31 */
32 void write(Direction direction, Tuple row);
33
34 /**
35 * Intersection type for writers that are also tables
36 */
37 interface Table extends ITableWriterGeneric, IIndexTable {
38 }
39
40 /**
41 * /dev/null implementation
42 *
43 * @author Gabor Bergmann
44 */
45 static class Nop implements ITableWriterGeneric {
46 @Override
47 public void write(Direction direction, Tuple row) {
48 // NO-OP
49 }
50
51 }
52}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java
deleted file mode 100644
index f90d5362..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/ITableWriterUnary.java
+++ /dev/null
@@ -1,52 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes.tables;
11
12import tools.refinery.viatra.runtime.matchers.util.Direction;
13
14/**
15 * Modifies the contents of a unary {@link IIndexTable}.
16 * <p>
17 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
18 * part of a work in progress. There is no guarantee that this API will
19 * work or that it will remain the same.
20 *
21 * @since 2.0
22 * @author Gabor Bergmann
23 *
24 */
25public interface ITableWriterUnary<Value> {
26
27 /**
28 * Adds/removes a row to/from the table.
29 *
30 * @param direction
31 * tells whether putting a row into the table or deleting TODO: store as multiset, return bool?
32 */
33 void write(Direction direction, Value value);
34
35 /**
36 * Intersection type for writers that are also tables
37 */
38 interface Table<Value> extends ITableWriterUnary<Value>, IIndexTable {
39 }
40
41 /**
42 * /dev/null implementation
43 *
44 * @author Gabor Bergmann
45 */
46 static class Nop<Value> implements ITableWriterUnary<Value> {
47 @Override
48 public void write(Direction direction, Value value) {
49 // NO-OP
50 }
51 }
52}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java
deleted file mode 100644
index 588ed9d2..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleBinaryTable.java
+++ /dev/null
@@ -1,320 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.viatra.runtime.matchers.scopes.tables;
10
11import java.util.Collections;
12import java.util.Optional;
13import java.util.Set;
14import java.util.stream.Stream;
15
16import tools.refinery.viatra.runtime.matchers.context.IInputKey;
17import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
18import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
19import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
20import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
21import tools.refinery.viatra.runtime.matchers.util.Accuracy;
22import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
23import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory.MemoryType;
24import tools.refinery.viatra.runtime.matchers.util.Direction;
25import tools.refinery.viatra.runtime.matchers.util.IMemoryView;
26import tools.refinery.viatra.runtime.matchers.util.IMultiLookup;
27import tools.refinery.viatra.runtime.matchers.util.IMultiLookup.ChangeGranularity;
28
29/**
30 * Simple source-target bidirectional mapping.
31 *
32 * <p>
33 * TODO: specialize for to-one features and unique to-many features
34 * <p>
35 * TODO: on-demand construction of valueToHolderMap
36 * <p>
37 * TODO: support for lean indexing, opposites, long surrogate ids, etc.
38 * <p>
39 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
40 * part of a work in progress. There is no guarantee that this API will
41 * work or that it will remain the same.
42 *
43 * @since 2.0
44 * @author Gabor Bergmann
45 */
46public class SimpleBinaryTable<Source, Target> extends AbstractIndexTable
47 implements ITableWriterBinary.Table<Source, Target> {
48
49 /**
50 * value -> holder(s)
51 * <p>
52 * this is currently the primary store, may hold duplicates depending on the unique parameter
53 */
54 private IMultiLookup<Target, Source> valueToHolderMap;
55 /**
56 * holder -> value(s); constructed on-demand, null if unused
57 */
58 private IMultiLookup<Source, Target> holderToValueMap;
59 private int totalRowCount = 0;
60 private boolean unique;
61
62 /**
63 * @param unique
64 * client promises to only insert a given tuple with multiplicity one
65 */
66 public SimpleBinaryTable(IInputKey inputKey, ITableContext tableContext, boolean unique) {
67 super(inputKey, tableContext);
68 this.unique = unique;
69 valueToHolderMap = CollectionsFactory.createMultiLookup(Object.class,
70 unique ? MemoryType.SETS : MemoryType.MULTISETS, Object.class);
71 if (2 != inputKey.getArity())
72 throw new IllegalArgumentException(inputKey.toString());
73 }
74
75 @Override
76 public void write(Direction direction, Source holder, Target value) {
77 if (direction == Direction.INSERT) {
78 try {
79 // TODO we currently assume V2H map exists
80 boolean changed = addToValueToHolderMap(value, holder);
81 if (holderToValueMap != null) {
82 addToHolderToValueMap(value, holder);
83 }
84 if (changed) {
85 totalRowCount++;
86 if (emitNotifications) {
87 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(holder, value), true);
88 }
89 }
90 } catch (IllegalStateException ex) { // if unique table and duplicate tuple
91 String msg = String.format(
92 "Error: trying to add duplicate value %s to the unique feature %s of host object %s. This indicates some errors in underlying model representation.",
93 value, getInputKey().getPrettyPrintableName(), holder);
94 logError(msg);
95 }
96 } else { // DELETE
97 try {
98 // TODO we currently assume V2H map exists
99 boolean changed = removeFromValueToHolderMap(value, holder);
100 if (holderToValueMap != null) {
101 removeFromHolderToValueMap(value, holder);
102 }
103 if (changed) {
104 totalRowCount--;
105 if (emitNotifications) {
106 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(holder, value), false);
107 }
108 }
109 } catch (IllegalStateException ex) { // if unique table and duplicate tuple
110 String msg = String.format(
111 "Error: trying to remove non-existing value %s from the feature %s of host object %s. This indicates some errors in underlying model representation.",
112 value, getInputKey().getPrettyPrintableName(), holder);
113 logError(msg);
114 }
115 }
116 }
117
118 private boolean addToHolderToValueMap(Target value, Source holder) {
119 return ChangeGranularity.DUPLICATE != holderToValueMap.addPair(holder, value);
120 }
121
122 private boolean addToValueToHolderMap(Target value, Source holder) {
123 return ChangeGranularity.DUPLICATE != valueToHolderMap.addPair(value, holder);
124 }
125
126 /**
127 * @throws IllegalStateException
128 */
129 private boolean removeFromHolderToValueMap(Target value, Source holder) {
130 return ChangeGranularity.DUPLICATE != holderToValueMap.removePair(holder, value);
131 }
132
133 /**
134 * @throws IllegalStateException
135 */
136 private boolean removeFromValueToHolderMap(Target value, Source holder) {
137 return ChangeGranularity.DUPLICATE != valueToHolderMap.removePair(value, holder);
138 }
139
140 @SuppressWarnings("unchecked")
141 @Override
142 public int countTuples(TupleMask seedMask, ITuple seed) {
143 switch (seedMask.getSize()) {
144 case 0: // unseeded
145 // TODO we currently assume V2H map exists
146 return totalRowCount;
147 case 1: // lookup by source or target
148 int seedIndex = seedMask.indices[0];
149 if (seedIndex == 0) { // lookup by source
150 Source source = (Source) seed.get(0);
151 return getDistinctValuesOfHolder(source).size();
152 } else if (seedIndex == 1) { // lookup by target
153 Target target = (Target) seed.get(0);
154 return getDistinctHoldersOfValue(target).size();
155 } else
156 throw new IllegalArgumentException(seedMask.toString());
157 case 2: // containment check
158 // hack: if mask is not identity, then it is [1,0]/2, which is its own inverse
159 Source source = (Source) seedMask.getValue(seed, 0);
160 Target target = (Target) seedMask.getValue(seed, 1);
161 if (containsRow(source, target))
162 return 1;
163 else
164 return 0;
165 default:
166 throw new IllegalArgumentException(seedMask.toString());
167 }
168 }
169
170 @Override
171 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
172 // always exact count
173 if (groupMask.getSize() == 0) {
174 return totalRowCount == 0 ? Optional.of(0L) : Optional.of(1L);
175 } else if (groupMask.getSize() == 2) {
176 return Optional.of((long)totalRowCount);
177 } else if (groupMask.indices[0] == 0) { // project to holder
178 return Optional.of((long)getHolderToValueMap().countKeys());
179 } else { // (groupMask.indices[0] == 0) // project to value
180 return Optional.of((long)getValueToHolderMap().countKeys());
181 }
182 }
183
184 @Override
185 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
186 switch (seedMask.getSize()) {
187 case 0: // unseeded
188 // TODO we currently assume V2H map exists
189 return getAllDistinctValuesStream()
190 .flatMap(value -> valueToHolderMap.lookup(value).distinctValues().stream()
191 .map(source -> Tuples.staticArityFlatTupleOf(source, value)));
192
193 case 1: // lookup by source or target
194 int seedIndex = seedMask.indices[0];
195 if (seedIndex == 0) { // lookup by source
196 @SuppressWarnings("unchecked")
197 Source source = (Source) seed.get(0);
198 return getDistinctValuesOfHolder(source).stream()
199 .map(target -> Tuples.staticArityFlatTupleOf(source, target));
200 } else if (seedIndex == 1) { // lookup by target
201 @SuppressWarnings("unchecked")
202 Target target = (Target) seed.get(0);
203 return getDistinctHoldersOfValue(target).stream()
204 .map(source -> Tuples.staticArityFlatTupleOf(source, target));
205 } else
206 throw new IllegalArgumentException(seedMask.toString());
207 case 2: // containment check
208 // hack: if mask is not identity, then it is [1,0]/2, which is its own inverse
209 @SuppressWarnings("unchecked")
210 Source source = (Source) seedMask.getValue(seed, 0);
211 @SuppressWarnings("unchecked")
212 Target target = (Target) seedMask.getValue(seed, 1);
213
214 if (containsRow(source, target))
215 return Stream.of(Tuples.staticArityFlatTupleOf(source, target));
216 else
217 return Stream.empty();
218 default:
219 throw new IllegalArgumentException(seedMask.toString());
220 }
221 }
222
223 @Override
224 @SuppressWarnings("unchecked")
225 public Iterable<? extends Object> enumerateValues(TupleMask seedMask, ITuple seed) {
226 if (seedMask.getSize() != 1)
227 throw new IllegalArgumentException(seedMask.toString());
228
229 int seedIndex = seedMask.indices[0];
230 if (seedIndex == 0) { // lookup by source
231 return getDistinctValuesOfHolder((Source) seed.get(0));
232 } else if (seedIndex == 1) { // lookup by target
233 return getDistinctHoldersOfValue((Target) seed.get(0));
234 } else
235 throw new IllegalArgumentException(seedMask.toString());
236
237 }
238 @Override
239 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
240 if (seedMask.getSize() != 1)
241 throw new IllegalArgumentException(seedMask.toString());
242
243 int seedIndex = seedMask.indices[0];
244 if (seedIndex == 0) { // lookup by source
245 return getDistinctValuesOfHolder((Source) seed.get(0)).stream();
246 } else if (seedIndex == 1) { // lookup by target
247 return getDistinctHoldersOfValue((Target) seed.get(0)).stream();
248 } else
249 throw new IllegalArgumentException(seedMask.toString());
250
251 }
252
253 @Override
254 @SuppressWarnings("unchecked")
255 public boolean containsTuple(ITuple seed) {
256 return containsRow((Source) seed.get(0), (Target) seed.get(1));
257 }
258
259 public boolean containsRow(Source source, Target target) {
260 // TODO we currently assume V2H map exists
261 if (valueToHolderMap != null) {
262 IMemoryView<Source> holders = valueToHolderMap.lookup(target);
263 return holders != null && holders.containsNonZero(source);
264 } else
265 throw new UnsupportedOperationException("TODO implement");
266 }
267
268 public Iterable<Source> getAllDistinctHolders() {
269 return getHolderToValueMap().distinctKeys();
270 }
271 public Stream<Source> getAllDistinctHoldersStream() {
272 return getHolderToValueMap().distinctKeysStream();
273 }
274 public Iterable<Target> getAllDistinctValues() {
275 return getValueToHolderMap().distinctKeys();
276 }
277 public Stream<Target> getAllDistinctValuesStream() {
278 return getValueToHolderMap().distinctKeysStream();
279 }
280
281 public Set<Source> getDistinctHoldersOfValue(Target value) {
282 IMemoryView<Source> holdersMultiset = getValueToHolderMap().lookup(value);
283 if (holdersMultiset == null)
284 return Collections.emptySet();
285 else
286 return holdersMultiset.distinctValues();
287 }
288
289 public Set<Target> getDistinctValuesOfHolder(Source holder) {
290 IMemoryView<Target> valuesMultiset = getHolderToValueMap().lookup(holder);
291 if (valuesMultiset == null)
292 return Collections.emptySet();
293 else
294 return valuesMultiset.distinctValues();
295 }
296
297 private IMultiLookup<Source, Target> getHolderToValueMap() {
298 if (holderToValueMap == null) {
299 holderToValueMap = CollectionsFactory.createMultiLookup(Object.class, MemoryType.SETS, // no duplicates, as
300 // this is the
301 // secondary
302 // collection
303 Object.class);
304
305 // TODO we currently assume V2H map exists
306 for (Target value : valueToHolderMap.distinctKeys()) {
307 for (Source holder : valueToHolderMap.lookup(value).distinctValues()) {
308 holderToValueMap.addPair(holder, value);
309 }
310 }
311 }
312 return holderToValueMap;
313 }
314
315 private IMultiLookup<Target, Source> getValueToHolderMap() {
316 // TODO we currently assume V2H map exists
317 return valueToHolderMap;
318 }
319
320}
diff --git a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java b/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java
deleted file mode 100644
index 428ea78b..00000000
--- a/subprojects/viatra-runtime-matchers/src/main/java/tools/refinery/viatra/runtime/matchers/scopes/tables/SimpleUnaryTable.java
+++ /dev/null
@@ -1,140 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2018, Gabor Bergmann, IncQuery Labs Ltd.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html.
6 *
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9
10package tools.refinery.viatra.runtime.matchers.scopes.tables;
11
12import java.util.Optional;
13import java.util.stream.Stream;
14
15import tools.refinery.viatra.runtime.matchers.context.IInputKey;
16import tools.refinery.viatra.runtime.matchers.tuple.ITuple;
17import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
18import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
19import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
20import tools.refinery.viatra.runtime.matchers.util.Accuracy;
21import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
22import tools.refinery.viatra.runtime.matchers.util.Direction;
23import tools.refinery.viatra.runtime.matchers.util.IMemory;
24
25/**
26 * Simple value set.
27 * <p>
28 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
29 * part of a work in progress. There is no guarantee that this API will
30 * work or that it will remain the same.
31 *
32 * @since 2.0
33 * @author Gabor Bergmann
34 */
35public class SimpleUnaryTable<Value> extends AbstractIndexTable implements ITableWriterUnary.Table<Value> {
36
37 protected IMemory<Value> values = CollectionsFactory.createMultiset(); // TODO use SetMemory if unique
38
39 private boolean unique;
40
41 /**
42 * @param unique
43 * client promises to only insert a given tuple with multiplicity one
44 */
45 public SimpleUnaryTable(IInputKey inputKey, ITableContext tableContext, boolean unique) {
46 super(inputKey, tableContext);
47 this.unique = unique;
48 if (1 != inputKey.getArity())
49 throw new IllegalArgumentException(inputKey.toString());
50 }
51
52 @Override
53 public void write(Direction direction, Value value) {
54 if (direction == Direction.INSERT) {
55 boolean changed = values.addOne(value);
56 if (unique && !changed) {
57 String msg = String.format(
58 "Error: trying to add duplicate value %s to the unique set %s. This indicates some errors in underlying model representation.",
59 value, getInputKey().getPrettyPrintableName());
60 logError(msg);
61 }
62 if (changed && emitNotifications) {
63 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(value), true);
64 }
65 } else { // DELETE
66 boolean changed = values.removeOne(value);
67 if (unique && !changed) {
68 String msg = String.format(
69 "Error: trying to remove duplicate value %s from the unique set %s. This indicates some errors in underlying model representation.",
70 value, getInputKey().getPrettyPrintableName());
71 logError(msg);
72 }
73 if (changed && emitNotifications) {
74 deliverChangeNotifications(Tuples.staticArityFlatTupleOf(value), false);
75 }
76 }
77 }
78
79 @Override
80 @SuppressWarnings("unchecked")
81 public boolean containsTuple(ITuple seed) {
82 return values.containsNonZero((Value) seed.get(0));
83 }
84
85 @Override
86 public int countTuples(TupleMask seedMask, ITuple seed) {
87 if (seedMask.getSize() == 0) { // unseeded
88 return values.size();
89 } else {
90 @SuppressWarnings("unchecked")
91 Value value = (Value) seed.get(0);
92 return values.containsNonZero(value) ? 1 : 0;
93 }
94 }
95
96
97 @Override
98 public Optional<Long> estimateProjectionSize(TupleMask groupMask, Accuracy requiredAccuracy) {
99 // always exact count
100 if (groupMask.getSize() == 0) {
101 return values.isEmpty() ? Optional.of(0L) : Optional.of(1L);
102 } else {
103 return Optional.of((long)values.size());
104 }
105 }
106
107
108 @Override
109 public Stream<? extends Tuple> streamTuples(TupleMask seedMask, ITuple seed) {
110 if (seedMask.getSize() == 0) { // unseeded
111 return values.distinctValues().stream().map(Tuples::staticArityFlatTupleOf);
112 } else {
113 @SuppressWarnings("unchecked")
114 Value value = (Value) seed.get(0);
115 if (values.containsNonZero(value))
116 return Stream.of(Tuples.staticArityFlatTupleOf(value));
117 else
118 return Stream.empty();
119 }
120 }
121
122 @Override
123 public Iterable<? extends Object> enumerateValues(TupleMask seedMask, ITuple seed) {
124 if (seedMask.getSize() == 0) { // unseeded
125 return values;
126 } else {
127 throw new IllegalArgumentException(seedMask.toString());
128 }
129 }
130 @Override
131 public Stream<? extends Object> streamValues(TupleMask seedMask, ITuple seed) {
132 if (seedMask.getSize() == 0) { // unseeded
133 return values.asStream();
134 } else {
135 throw new IllegalArgumentException(seedMask.toString());
136 }
137 }
138
139
140}