aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/single/TransitiveClosureNode.java
blob: fdda4ef4fb86c11612ba1ed1a9b010d92f41b6f0 (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
141
142
143
144
145
146
147
/*******************************************************************************
 * Copyright (c) 2010-2012, Tamas Szabo, Gabor Bergmann, Istvan Rath and Daniel Varro
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-v20.html.
 *
 * SPDX-License-Identifier: EPL-2.0
 *******************************************************************************/
package tools.refinery.viatra.runtime.rete.single;

import tools.refinery.viatra.runtime.rete.itc.alg.incscc.IncSCCAlg;
import tools.refinery.viatra.runtime.rete.itc.alg.misc.Tuple;
import tools.refinery.viatra.runtime.rete.itc.graphimpl.Graph;
import tools.refinery.viatra.runtime.rete.itc.igraph.ITcDataSource;
import tools.refinery.viatra.runtime.rete.itc.igraph.ITcObserver;
import tools.refinery.viatra.runtime.matchers.tuple.Tuples;
import tools.refinery.viatra.runtime.matchers.util.Clearable;
import tools.refinery.viatra.runtime.matchers.util.Direction;
import tools.refinery.viatra.runtime.matchers.util.timeline.Timeline;
import tools.refinery.viatra.runtime.rete.network.NetworkStructureChangeSensitiveNode;
import tools.refinery.viatra.runtime.rete.network.ReinitializedNode;
import tools.refinery.viatra.runtime.rete.network.ReteContainer;
import tools.refinery.viatra.runtime.rete.network.communication.CommunicationGroup;
import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;

import java.util.Collection;
import java.util.Map;

/**
 * This class represents a transitive closure node in the Rete net.
 * <p>
 * This node must not be used in recursive {@link CommunicationGroup}s.
 *
 * @author Gabor Bergmann
 *
 */
public class TransitiveClosureNode extends SingleInputNode
        implements Clearable, ITcObserver<Object>, NetworkStructureChangeSensitiveNode, ReinitializedNode {

    private Graph<Object> graphDataSource;
    private ITcDataSource<Object> transitiveClosureAlgorithm;

    /**
     * Create a new transitive closure rete node.
     *
     * Client may optionally call {@link #reinitializeWith(Collection)} before using the node, instead of inserting the
     * initial set of tuples one by one.
     *
     * @param reteContainer
     *            the rete container of the node
     */
    public TransitiveClosureNode(ReteContainer reteContainer) {
        super(reteContainer);
        graphDataSource = new Graph<Object>();
        transitiveClosureAlgorithm = new IncSCCAlg<Object>(graphDataSource);
        transitiveClosureAlgorithm.attachObserver(this);
        reteContainer.registerClearable(this);
    }

    @Override
    public void networkStructureChanged() {
        if (this.reteContainer.isTimelyEvaluation() && this.reteContainer.getCommunicationTracker().isInRecursiveGroup(this)) {
            throw new IllegalStateException(this.toString() + " cannot be used in recursive differential dataflow evaluation!");
        }
        super.networkStructureChanged();
    }

    /**
     * Initializes the graph data source with the given collection of tuples.
     *
     * @param tuples
     *            the initial collection of tuples
     */
	@Override
    public void reinitializeWith(Collection<tools.refinery.viatra.runtime.matchers.tuple.Tuple> tuples) {
        clear();

        for (tools.refinery.viatra.runtime.matchers.tuple.Tuple t : tuples) {
            graphDataSource.insertNode(t.get(0));
            graphDataSource.insertNode(t.get(1));
            graphDataSource.insertEdge(t.get(0), t.get(1));
        }
        transitiveClosureAlgorithm.attachObserver(this);
    }

    @Override
    public void pullInto(final Collection<tools.refinery.viatra.runtime.matchers.tuple.Tuple> collector, final boolean flush) {
        for (final Tuple<Object> tuple : ((IncSCCAlg<Object>) transitiveClosureAlgorithm).getTcRelation()) {
            collector.add(Tuples.staticArityFlatTupleOf(tuple.getSource(), tuple.getTarget()));
        }
    }

    @Override
    public void pullIntoWithTimeline(
            final Map<tools.refinery.viatra.runtime.matchers.tuple.Tuple, Timeline<Timestamp>> collector,
            final boolean flush) {
        // use all zero timestamps because this node cannot be used in recursive groups anyway
        for (final Tuple<Object> tuple : ((IncSCCAlg<Object>) transitiveClosureAlgorithm).getTcRelation()) {
            collector.put(Tuples.staticArityFlatTupleOf(tuple.getSource(), tuple.getTarget()), Timestamp.INSERT_AT_ZERO_TIMELINE);
        }
    }

    @Override
    public void update(Direction direction, tools.refinery.viatra.runtime.matchers.tuple.Tuple updateElement,
            Timestamp timestamp) {
        if (updateElement.getSize() == 2) {
            Object source = updateElement.get(0);
            Object target = updateElement.get(1);

            if (direction == Direction.INSERT) {
                graphDataSource.insertNode(source);
                graphDataSource.insertNode(target);
                graphDataSource.insertEdge(source, target);
            }
            if (direction == Direction.DELETE) {
                graphDataSource.deleteEdgeIfExists(source, target);

                if (((IncSCCAlg<Object>) transitiveClosureAlgorithm).isIsolated(source)) {
                    graphDataSource.deleteNode(source);
                }
                if (!source.equals(target) && ((IncSCCAlg<Object>) transitiveClosureAlgorithm).isIsolated(target)) {
                    graphDataSource.deleteNode(target);
                }
            }
        }
    }

    @Override
    public void clear() {
        transitiveClosureAlgorithm.dispose();
        graphDataSource = new Graph<Object>();
        transitiveClosureAlgorithm = new IncSCCAlg<Object>(graphDataSource);
    }

    @Override
    public void tupleInserted(Object source, Object target) {
        tools.refinery.viatra.runtime.matchers.tuple.Tuple tuple = Tuples.staticArityFlatTupleOf(source, target);
        propagateUpdate(Direction.INSERT, tuple, Timestamp.ZERO);
    }

    @Override
    public void tupleDeleted(Object source, Object target) {
        tools.refinery.viatra.runtime.matchers.tuple.Tuple tuple = Tuples.staticArityFlatTupleOf(source, target);
        propagateUpdate(Direction.DELETE, tuple, Timestamp.ZERO);
    }

}