aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java')
-rw-r--r--subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java146
1 files changed, 146 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java
new file mode 100644
index 00000000..9214536c
--- /dev/null
+++ b/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/util/timeline/Timeline.java
@@ -0,0 +1,146 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, 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.util.timeline;
10
11import java.util.ArrayList;
12import java.util.Iterator;
13import java.util.List;
14
15import tools.refinery.viatra.runtime.matchers.util.Direction;
16import tools.refinery.viatra.runtime.matchers.util.Signed;
17
18/**
19 * A timeline describes the life cycle of a piece of data (typically a tuple in a relation) as a sequence of moments.
20 * Even moments represent appearances, odd moments represent disappearances. A timeline is immutable, once created, it
21 * is not possible to extend it with further moments.
22 *
23 * @author Tamas Szabo
24 * @since 2.4
25 */
26public abstract class Timeline<Timestamp extends Comparable<Timestamp>> {
27
28 public abstract Iterable<Signed<Timestamp>> asChangeSequence();
29
30 public abstract boolean isPresentAtInfinity();
31
32 public abstract boolean isEmpty();
33
34 public abstract int size();
35
36 public abstract Signed<Timestamp> getSigned(final int index);
37
38 public abstract Timestamp getUnsigned(final int index);
39
40 public Timeline<Timestamp> mergeMultiplicative(final Timeline<Timestamp> that) {
41 final List<Timestamp> result = new ArrayList<>();
42 int thisIdx = 0, thatIdx = 0;
43 Timestamp thisNext = thisIdx < this.size() ? this.getUnsigned(thisIdx) : null;
44 Timestamp thatNext = thatIdx < that.size() ? that.getUnsigned(thatIdx) : null;
45
46 while (thisNext != null || thatNext != null) {
47 int thisMinusThat = 0;
48 if (thisNext != null && thatNext != null) {
49 thisMinusThat = thisNext.compareTo(thatNext);
50 }
51 if (thisNext == null || thisMinusThat > 0) {
52 if (thisIdx % 2 == 1) {
53 result.add(thatNext);
54 }
55 thatIdx++;
56 thatNext = thatIdx < that.size() ? that.getUnsigned(thatIdx) : null;
57 } else if (thatNext == null || thisMinusThat < 0) {
58 if (thatIdx % 2 == 1) {
59 result.add(thisNext);
60 }
61 thisIdx++;
62 thisNext = thisIdx < this.size() ? this.getUnsigned(thisIdx) : null;
63 } else {
64 if (thisIdx % 2 == thatIdx % 2) {
65 result.add(thisNext);
66 }
67 thisIdx++;
68 thatIdx++;
69 thatNext = thatIdx < that.size() ? that.getUnsigned(thatIdx) : null;
70 thisNext = thisIdx < this.size() ? this.getUnsigned(thisIdx) : null;
71 }
72 }
73
74 return Timelines.createFrom(result);
75 }
76
77 /**
78 * Merges this timeline with the given timestamp diff. The expectation is that the resulting timeline starts with an
79 * insertion. The logic is similar to a merge sort; we iterate side-by-side over the timeline and the diff. During
80 * the merge, cancellation can happen if at the same timestamp we observe different signs at the corresponding
81 * timeline and diff elements.
82 */
83 public Timeline<Timestamp> mergeAdditive(final Diff<Timestamp> diff) {
84 final Iterator<Signed<Timestamp>> thisItr = this.asChangeSequence().iterator();
85 final Iterator<Signed<Timestamp>> diffItr = diff.iterator();
86 final List<Timestamp> result = new ArrayList<>();
87 Direction expected = Direction.INSERT;
88 Signed<Timestamp> thisNext = thisItr.hasNext() ? thisItr.next() : null;
89 Signed<Timestamp> diffNext = diffItr.hasNext() ? diffItr.next() : null;
90
91 while (thisNext != null || diffNext != null) {
92 int thisMinusDiff = 0;
93 if (thisNext != null && diffNext != null) {
94 thisMinusDiff = thisNext.getPayload().compareTo(diffNext.getPayload());
95 }
96
97 if (thisNext == null || thisMinusDiff > 0) {
98 if (!expected.equals(diffNext.getDirection())) {
99 throw new IllegalStateException(
100 String.format("Expected direction (%s) constraint violated! %s %s @%s", expected, this,
101 diff, diffNext.getPayload()));
102 }
103 result.add(diffNext.getPayload());
104 diffNext = diffItr.hasNext() ? diffItr.next() : null;
105 expected = expected.opposite();
106 } else if (diffNext == null || thisMinusDiff < 0) {
107 if (!expected.equals(thisNext.getDirection())) {
108 throw new IllegalStateException(
109 String.format("Expected direction (%s) constraint violated! %s %s @%s", expected, this,
110 diff, thisNext.getPayload()));
111 }
112 result.add(thisNext.getPayload());
113 thisNext = thisItr.hasNext() ? thisItr.next() : null;
114 expected = expected.opposite();
115 } else {
116 // they cancel out each other
117 if (diffNext.getDirection().equals(thisNext.getDirection())) {
118 throw new IllegalStateException(String.format("Changes do not cancel out each other! %s %s @%s",
119 this, diff, thisNext.getPayload()));
120 }
121 diffNext = diffItr.hasNext() ? diffItr.next() : null;
122 thisNext = thisItr.hasNext() ? thisItr.next() : null;
123 }
124 }
125
126 return Timelines.createFrom(result);
127 }
128
129 @Override
130 public String toString() {
131 final StringBuilder builder = new StringBuilder();
132 builder.append("[");
133 boolean first = true;
134 for (final Signed<Timestamp> element : this.asChangeSequence()) {
135 if (first) {
136 first = false;
137 } else {
138 builder.append(", ");
139 }
140 builder.append(element.toString());
141 }
142 builder.append("]");
143 return builder.toString();
144 }
145
146}