aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/planning/SubPlan.java
blob: 1998df9dcaf0040b20827189137b5c17005a0ccf (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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*******************************************************************************
 * Copyright (c) 2004-2008 Gabor Bergmann 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.matchers.planning;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.stream.Collectors;

import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
import tools.refinery.viatra.runtime.matchers.planning.helpers.TypeHelper;
import tools.refinery.viatra.runtime.matchers.planning.operations.POperation;
import tools.refinery.viatra.runtime.matchers.planning.operations.PProject;
import tools.refinery.viatra.runtime.matchers.planning.operations.PStart;
import tools.refinery.viatra.runtime.matchers.psystem.PBody;
import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
import tools.refinery.viatra.runtime.matchers.psystem.TypeJudgement;

/**
 * A plan representing a subset of (or possibly all the) constraints evaluated. A SubPlan instance is responsible for
 * representing a state of the plan; but after it is initialized it is expected be immutable 
 *  (exception: inferred constraints, see {@link #inferConstraint(PConstraint)}).
 * 
 * <p> A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans. 
 * Important maintained information: <ul>
 * <li>set of <b>variables</b> whose values are known when the runtime evaluation is at this stage,
 * <li>set of <b>constraints</b> that are known to hold true at this point.
 * </ul>
 * 
 * <p> Recommended to instantiate via a {@link SubPlanFactory} or subclasses, 
 * so that query planners can subclass SubPlan if needed. 
 * 
 * @author Gabor Bergmann
 * 
 */
public class SubPlan {
    private PBody body;
    private List<? extends SubPlan> parentPlans;
    private POperation operation;

    private final Set<PVariable> visibleVariables; 
    private final Set<PVariable> allVariables; 
    private final Set<PVariable> introducedVariables; // delta compared to first parent
    private Set<PConstraint> allConstraints;
    private Set<PConstraint> deltaConstraints; // delta compared to all parents
    private Set<PConstraint> externallyInferredConstraints; // inferred in addition to direct consequences of the operation and parents 
    

    
    
    
    /**
     * A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans.
     */
    public SubPlan(PBody body, POperation operation, SubPlan... parentPlans) {
        this(body, operation, Arrays.asList(parentPlans));
    }
    /**
     * A SubPlan is constructed by applying a {@link POperation} on zero or more parent SubPlans.
     */
    public SubPlan(PBody body, POperation operation, List<? extends SubPlan> parentPlans) {
        super();
        this.body = body;
        this.parentPlans = parentPlans;
        this.operation = operation;
        
        this.externallyInferredConstraints = new HashSet<PConstraint>();
        this.deltaConstraints = new HashSet<PConstraint>(operation.getDeltaConstraints());
        
        this.allVariables = new HashSet<PVariable>();
        for (PConstraint constraint: deltaConstraints) {
            this.allVariables.addAll(constraint.getDeducedVariables());
        }
        this.allConstraints = new HashSet<PConstraint>(deltaConstraints);
        for (SubPlan parentPlan: parentPlans) {
            this.allConstraints.addAll(parentPlan.getAllEnforcedConstraints());
            this.allVariables.addAll(parentPlan.getAllDeducedVariables());
        }     
        
        // TODO this is ugly a bit
        if (operation instanceof PStart) {
            this.visibleVariables = new HashSet<PVariable>(((PStart) operation).getAPrioriVariables());
            this.allVariables.addAll(visibleVariables);
        } else if (operation instanceof PProject) { 
            this.visibleVariables = new HashSet<PVariable>(((PProject) operation).getToVariables());
        } else {
            this.visibleVariables = new HashSet<PVariable>();
            for (SubPlan parentPlan: parentPlans)
                this.visibleVariables.addAll(parentPlan.getVisibleVariables());
            for (PConstraint constraint: deltaConstraints)
                this.visibleVariables.addAll(constraint.getDeducedVariables());
        } 
        
        this.introducedVariables = new HashSet<PVariable>(this.visibleVariables);
        if (!parentPlans.isEmpty()) 
            introducedVariables.removeAll(parentPlans.get(0).getVisibleVariables());
        
        operation.checkConsistency(this);
    }
    
    
    @Override
    public String toString() {
        return toLongString();
    }
    public String toShortString() {
        return String.format("Plan{%s}:%s", 
                visibleVariables.stream().map(PVariable::getName).collect(Collectors.joining(",")),
                operation.getShortName());
    }
    public String toLongString() {
        return String.format("%s<%s>", 
                toShortString(),
                parentPlans.stream().map(Object::toString).collect(Collectors.joining("; ")));
    }


    /**
     * All constraints that are known to hold at this point
     */
    public Set<PConstraint> getAllEnforcedConstraints() {
        return allConstraints;
    }

    /**
     * The new constraints enforced at this stage of plan, that aren't yet enforced at parents
     * (results are also included in {@link SubPlan#getAllEnforcedConstraints()})
     */
    public Set<PConstraint> getDeltaEnforcedConstraints() {
        return deltaConstraints;
    }

    /**
     * Indicate that a given constraint was found to be automatically satisfied at this point 
     *   without additional operations. 
     * (results are also included in {@link SubPlan#getDeltaEnforcedConstraints()})
     *   
     * <p>Warning: not propagated automatically to child plans, 
     *  so best to invoke before constructing further SubPlans. </p>
     */
    public void inferConstraint(PConstraint constraint) {
        externallyInferredConstraints.add(constraint);
        deltaConstraints.add(constraint);
        allConstraints.add(constraint);
    }
    
    public PBody getBody() {
        return body;
    }
    
    /**
     * Variables which are assigned a value at this point 
     * (results are also included in {@link SubPlan#getAllDeducedVariables()})
     */
    public Set<PVariable> getVisibleVariables() {
        return visibleVariables;
    }
    /**
     * Variables which have been assigned a value; 
     * includes visible variables (see {@link #getVisibleVariables()}) 
     *   and additionally any variables hidden by a projection (see {@link PProject}). 
     */
    public Set<PVariable> getAllDeducedVariables() {
        return allVariables;
    }
    /**
     * Delta compared to first parent: variables that are visible here but were not visible at the first parent.
     */
    public Set<PVariable> getIntroducedVariables() {
        return introducedVariables;
    }
    public List<? extends SubPlan> getParentPlans() {
        return parentPlans;
    }
    public POperation getOperation() {
        return operation;
    }
    
    
    /**
     * The closure of all type judgments of enforced constraints at this point.
     * <p> No subsumption applied.
     */
    public Set<TypeJudgement> getAllImpliedTypeJudgements(IQueryMetaContext context) {
        Set<TypeJudgement> impliedJudgements = allImpliedTypeJudgements.get(context);
        if (impliedJudgements == null) {
            Set<TypeJudgement> equivalentJudgements = TypeHelper.getDirectJudgements(getAllEnforcedConstraints(), context);
            impliedJudgements = TypeHelper.typeClosure(equivalentJudgements, context);

            allImpliedTypeJudgements.put(context, impliedJudgements);
        }
        return impliedJudgements;
    }
    private WeakHashMap<IQueryMetaContext, Set<TypeJudgement>> allImpliedTypeJudgements = new WeakHashMap<IQueryMetaContext, Set<TypeJudgement>>();   
    
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((operation == null) ? 0 : operation.hashCode());
        result = prime * result
                + ((parentPlans == null) ? 0 : parentPlans.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof SubPlan))
            return false;
        SubPlan other = (SubPlan) obj;
        if (operation == null) {
            if (other.operation != null)
                return false;
        } else if (!operation.equals(other.operation))
            return false;
        if (parentPlans == null) {
            if (other.parentPlans != null)
                return false;
        } else if (!parentPlans.equals(other.parentPlans))
            return false;
        return true;
    }

    
}