aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-localsearch/src/main/java/tools/refinery/viatra/runtime/localsearch/planner/cost/impl/HybridMatcherConstraintCostFunction.java
blob: df9292f06b3c9c8a70efff2dc22f67683f16eb81 (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
/*******************************************************************************
 * Copyright (c) 2010-2016, Grill Balázs, IncQuery Labs Ltd
 * 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.localsearch.planner.cost.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import tools.refinery.viatra.runtime.localsearch.planner.cost.IConstraintEvaluationContext;
import tools.refinery.viatra.runtime.matchers.backend.IQueryResultProvider;
import tools.refinery.viatra.runtime.matchers.psystem.PConstraint;
import tools.refinery.viatra.runtime.matchers.psystem.PVariable;
import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.ConstantValue;
import tools.refinery.viatra.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
import tools.refinery.viatra.runtime.matchers.tuple.Tuples;

/**
 * This cost function is intended to be used on hybrid configuration, with the strict restriction than any
 * non-flattened positive pattern call is executed with Rete engine. This implementation provides the exact number
 * of matches by invoking the result provider for the called pattern.
 * 
 * @deprecated {@link StatisticsBasedConstraintCostFunction} should use {@link IQueryResultProvider#estimateCardinality(tools.refinery.viatra.runtime.matchers.tuple.TupleMask, org.eclipse.viatra.query.runtime.matchers.util.Accuracy)} 
 */
@Deprecated
public class HybridMatcherConstraintCostFunction extends IndexerBasedConstraintCostFunction {
    
    @Override
    protected double _calculateCost(PositivePatternCall patternCall, IConstraintEvaluationContext context) {
        // Determine local constant constraints which is used to filter results
        Tuple variables = patternCall.getVariablesTuple();
        Set<Object> variablesSet = variables.getDistinctElements();
        final Map<PVariable, Object> constantMap = new HashMap<>();
        for (PConstraint _constraint : patternCall.getPSystem().getConstraints()) {
            if (_constraint instanceof ConstantValue){
                ConstantValue constraint = (ConstantValue) _constraint;
                PVariable variable = (PVariable) constraint.getVariablesTuple().get(0);
                if (variablesSet.contains(variable) && context.getBoundVariables().contains(variable)) {
                    constantMap.put(variable, constraint.getSupplierKey());
                }
            }
        }
        
        // Determine filter
        Object[] filter = new Object[variables.getSize()];
        for(int i=0; i < variables.getSize(); i++){
            filter[i] = constantMap.get(variables.get(i));
        }

        // aggregate keys are the bound and not filtered variables
        // These will be fixed in runtime, but unknown at planning time
        // This is represented by indices to ease working with result tuples
        final Map<Object, Integer> variableIndices = variables.invertIndex();
        List<Integer> aggregateKeys = context.getBoundVariables().stream()
                .filter(input -> !constantMap.containsKey(input))
                .map(variableIndices::get)
                .collect(Collectors.toList());

        IQueryResultProvider resultProvider = context.resultProviderRequestor().requestResultProvider(patternCall, null);
        Map<Tuple, Integer> aggregatedCounts = new HashMap<>();
        
        // Iterate over all matches and count together matches that has equal values on
        // aggregateKeys positions. The cost of the pattern call is considered to be the
        // Maximum of these counted values
        
        int result = 0;
        // NOTE: a stream is not an iterable (cannot be iterated more than once), so to use it in a for-loop
        // it has to be wrapped; in the following line a lambda is used to implement Iterable#iterator()
        for (Tuple match : (Iterable<Tuple>) () -> resultProvider.getAllMatches(filter).iterator()) {
            Tuple extracted = Tuples.flatTupleOf(aggregateKeys.stream().map(match::get).toArray());
            int count = (aggregatedCounts.containsKey(extracted)) 
                ? aggregatedCounts.get(extracted) + 1
                : 1;                
            aggregatedCounts.put(extracted, count);
            if (result < count) {
                result = count;
            }
        }

        return result;
    }
    
}