aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/construction/basiclinear/BasicLinearLayout.java
blob: bd22e1a0b2a954c5b66385f1bb26185dd71295f2 (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
/*******************************************************************************
 * Copyright (c) 2004-2010 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.rete.construction.basiclinear;

import java.util.Arrays;
import java.util.Collections;
import java.util.Set;

import org.apache.log4j.Logger;
import tools.refinery.viatra.runtime.matchers.backend.IQueryBackendHintProvider;
import tools.refinery.viatra.runtime.matchers.context.IQueryBackendContext;
import tools.refinery.viatra.runtime.matchers.context.IQueryMetaContext;
import tools.refinery.viatra.runtime.matchers.planning.IQueryPlannerStrategy;
import tools.refinery.viatra.runtime.matchers.planning.SubPlan;
import tools.refinery.viatra.runtime.matchers.planning.SubPlanFactory;
import tools.refinery.viatra.runtime.matchers.planning.helpers.BuildHelper;
import tools.refinery.viatra.runtime.matchers.planning.operations.PApply;
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.DeferredPConstraint;
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.VariableDeferredPConstraint;
import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.Equality;
import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExportedParameter;
import tools.refinery.viatra.runtime.matchers.psystem.basicdeferred.ExpressionEvaluation;
import tools.refinery.viatra.runtime.matchers.psystem.queries.PQuery;
import tools.refinery.viatra.runtime.matchers.util.CollectionsFactory;
import tools.refinery.viatra.runtime.rete.construction.RetePatternBuildException;

/**
 * Basic layout that builds a linear RETE net based on a heuristic ordering of constraints.
 * 
 * @author Gabor Bergmann
 * 
 */
public class BasicLinearLayout implements IQueryPlannerStrategy {

    //SubPlanProcessor planProcessor = new SubPlanProcessor();
    
    private IQueryBackendHintProvider hintProvider;
    private IQueryBackendContext bContext;
    /**
     * @param bContext
     * @since 1.5
     */
    public BasicLinearLayout(IQueryBackendContext bContext) {
        this.bContext = bContext;
        this.hintProvider = bContext.getHintProvider();
    }

    @Override
    public SubPlan plan(final PBody pSystem, Logger logger, IQueryMetaContext context) {
        SubPlanFactory planFactory = new SubPlanFactory(pSystem);
        PQuery query = pSystem.getPattern();
        //planProcessor.setCompiler(compiler);
        try {
            logger.debug(String.format(
                    "%s: patternbody build started for %s",
                    getClass().getSimpleName(), 
                    query.getFullyQualifiedName()));

            // STARTING THE LINE
            SubPlan plan = planFactory.createSubPlan(new PStart());

            Set<PConstraint> pQueue = CollectionsFactory.createSet(pSystem.getConstraints());

            // MAIN LOOP
            while (!pQueue.isEmpty()) {
                PConstraint pConstraint = Collections.min(pQueue,
                        new OrderingHeuristics(plan, context)); // pQueue.iterator().next();
                pQueue.remove(pConstraint);

                // if we have no better option than an unready deferred constraint, raise error
                if (pConstraint instanceof DeferredPConstraint) {
                    final DeferredPConstraint deferred = (DeferredPConstraint) pConstraint;
                    if (!deferred.isReadyAt(plan, context)) {
                        raiseForeverDeferredError(deferred, plan, context);
                    }
                }
                // TODO integrate the check above in SubPlan / POperation??
                
                // replace incumbent plan with its child
                plan = planFactory.createSubPlan(new PApply(pConstraint), plan);              		
            }

            // PROJECT TO PARAMETERS
            SubPlan finalPlan = planFactory.createSubPlan(new PProject(pSystem.getSymbolicParameterVariables()), plan);
            
            // FINAL CHECK, whether all exported variables are present + all constraint satisfied
            BuildHelper.finalCheck(pSystem, finalPlan, context);
            // TODO integrate the check above in SubPlan / POperation 
            
            logger.debug(String.format(
                    "%s: patternbody query plan concluded for %s as: %s",
                    getClass().getSimpleName(), 
                    query.getFullyQualifiedName(),
                    finalPlan.toLongString()));

            return finalPlan;

        } catch (RetePatternBuildException ex) {
            ex.setPatternDescription(query);
            throw ex;
        }
    }

    /**
     * Called when the constraint is not ready, but cannot be deferred further.
     * 
     * @param plan
     * @throws RetePatternBuildException
     *             to indicate the error in detail.
     */
    private void raiseForeverDeferredError(DeferredPConstraint constraint, SubPlan plan, IQueryMetaContext context) {
        if (constraint instanceof Equality) {
            raiseForeverDeferredError((Equality)constraint, plan, context);
        } else if (constraint instanceof ExportedParameter) {
            raiseForeverDeferredError((ExportedParameter)constraint, plan, context);
        } else if (constraint instanceof ExpressionEvaluation) {
            raiseForeverDeferredError((ExpressionEvaluation)constraint, plan, context);
        } else if (constraint instanceof VariableDeferredPConstraint) {
            raiseForeverDeferredError(constraint, plan, context);
        }
    }
    
    private void raiseForeverDeferredError(Equality constraint, SubPlan plan, IQueryMetaContext context) {
        String[] args = { constraint.getWho().toString(), constraint.getWithWhom().toString() };
        String msg = "Cannot express equality of variables {1} and {2} if neither of them is deducable.";
        String shortMsg = "Equality between undeducible variables.";
        throw new RetePatternBuildException(msg, args, shortMsg, null);
    }
    private void raiseForeverDeferredError(ExportedParameter constraint, SubPlan plan, IQueryMetaContext context) {
        String[] args = { constraint.getParameterName() };
        String msg = "Pattern Graph Search terminated incompletely: "
                + "exported pattern variable {1} could not be determined based on the pattern constraints. "
                + "HINT: certain constructs (e.g. negative patterns or check expressions) cannot output symbolic parameters.";
        String shortMsg = "Could not deduce value of parameter";
        throw new RetePatternBuildException(msg, args, shortMsg, null);
    }
    private void raiseForeverDeferredError(ExpressionEvaluation constraint, SubPlan plan, IQueryMetaContext context) {
        if (constraint.checkTypeSafety(plan, context) == null) {
            raiseForeverDeferredError(constraint, plan);
        } else {
            String[] args = { toString(), constraint.checkTypeSafety(plan, context).toString() };
            String msg = "The checking of pattern constraint {1} cannot be deferred further, but variable {2} is still not type safe. "
                    + "HINT: the incremental matcher is not an equation solver, please make sure that all variable values are deducible.";
            String shortMsg = "Could not check all constraints due to undeducible type restrictions";
            throw new RetePatternBuildException(msg, args, shortMsg, null);
        }
    }
    private void raiseForeverDeferredError(VariableDeferredPConstraint constraint, SubPlan plan) {
        Set<PVariable> missing = CollectionsFactory.createSet(constraint.getDeferringVariables());//new HashSet<PVariable>(getDeferringVariables());
        missing.removeAll(plan.getVisibleVariables());
        String[] args = { toString(), Arrays.toString(missing.toArray()) };
        String msg = "The checking of pattern constraint {1} requires the values of variables {2}, but it cannot be deferred further. "
                + "HINT: the incremental matcher is not an equation solver, please make sure that all variable values are deducible.";
        String shortMsg = "Could not check all constraints due to undeducible variables";
        throw new RetePatternBuildException(msg, args, shortMsg, null);
    }
    
    
}