// Path: strategy/src/main/java/com/msd/gin/halyard/vocab/HALYARD.java
// public final class HALYARD {
// 
//     HALYARD() {}
// 
//     private static final SimpleValueFactory SVF = SimpleValueFactory.getInstance();
// 
//     public static final String PREFIX = "halyard";
// 
//     public static final String NAMESPACE = "http://merck.github.io/Halyard/ns#";
// 
//     public static final IRI STATS_ROOT_NODE = SVF.createIRI(NAMESPACE, "statsRoot");
// 
//     public static final IRI STATS_GRAPH_CONTEXT = SVF.createIRI(NAMESPACE, "statsContext");
// 
//     public static final IRI SYSTEM_GRAPH_CONTEXT = SVF.createIRI(NAMESPACE, "system");
// 
//     public static final IRI NAMESPACE_PREFIX_PROPERTY = HALYARD.SVF.createIRI(NAMESPACE, "namespacePrefix");
// 
//     public final static IRI TABLE_NAME_PROPERTY = SVF.createIRI(NAMESPACE, "tableName");
// 
//     public final static IRI SPLITBITS_PROPERTY = SVF.createIRI(NAMESPACE, "splitBits");
// 
//     public final static IRI CREATE_TABLE_PROPERTY = SVF.createIRI(NAMESPACE, "createTable");
// 
//     public final static IRI PUSH_STRATEGY_PROPERTY = SVF.createIRI(NAMESPACE, "pushStrategy");
// 
//     public final static IRI EVALUATION_TIMEOUT_PROPERTY = SVF.createIRI(NAMESPACE, "evaluationTimeout");
// 
//     public final static IRI ELASTIC_INDEX_URL_PROPERTY = SVF.createIRI(NAMESPACE, "elasticIndexURL");
// 
//     public final static IRI SEARCH_TYPE = SVF.createIRI(NAMESPACE, "search");
// 
//     public final static IRI PARALLEL_SPLIT_FUNCTION = SVF.createIRI(NAMESPACE, "forkAndFilterBy");
// 
// }


import com.msd.gin.halyard.vocab.HALYARD;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.query.algebra.ArbitraryLengthPath;
import org.eclipse.rdf4j.query.algebra.BinaryTupleOperator;
import org.eclipse.rdf4j.query.algebra.BindingSetAssignment;
import org.eclipse.rdf4j.query.algebra.EmptySet;
import org.eclipse.rdf4j.query.algebra.Filter;
import org.eclipse.rdf4j.query.algebra.Join;
import org.eclipse.rdf4j.query.algebra.LeftJoin;
import org.eclipse.rdf4j.query.algebra.QueryModelNode;
import org.eclipse.rdf4j.query.algebra.Service;
import org.eclipse.rdf4j.query.algebra.SingletonSet;
import org.eclipse.rdf4j.query.algebra.StatementPattern;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.UnaryTupleOperator;
import org.eclipse.rdf4j.query.algebra.Var;
import org.eclipse.rdf4j.query.algebra.ZeroLengthPath;
import org.eclipse.rdf4j.query.algebra.evaluation.impl.EvaluationStatistics;
import org.eclipse.rdf4j.query.algebra.evaluation.impl.ExternalSet;

    public synchronized double getCardinality(TupleExpr expr, final Set<String> boundVariables, final Set<String> priorityVariables) {
        if (cc == null) {
            cc = new HalyardCardinalityCalcualtor(boundVariables, priorityVariables, null);
        }
        expr.visit(cc);
        return cc.getCardinality();
    }

    @Override
    protected CardinalityCalculator createCardinalityCalculator() {
        return new HalyardCardinalityCalcualtor(Collections.emptySet(), Collections.emptySet(), null);
    }

    private class HalyardCardinalityCalcualtor extends CardinalityCalculator {

        private Set<String> boundVars;
        private final Set<String> priorityVariables;
        private final Map<TupleExpr, Double> mapToUpdate;

        public HalyardCardinalityCalcualtor(Set<String> boundVariables, Set<String> priorityVariables, Map<TupleExpr, Double> mapToUpdate) {
            this.boundVars = boundVariables;
            this.priorityVariables = priorityVariables;
            this.mapToUpdate = mapToUpdate;
        }

        @Override
        protected double getCardinality(StatementPattern sp) {
            //always preffer HALYARD.SEARCH_TYPE object literals to move such statements higher in the joins tree
            Var objectVar = sp.getObjectVar();
// Path: strategy/src/main/java/com/msd/gin/halyard/vocab/HALYARD.java
// public final class HALYARD {
// 
//     HALYARD() {}
// 
//     private static final SimpleValueFactory SVF = SimpleValueFactory.getInstance();
// 
//     public static final String PREFIX = "halyard";
// 
//     public static final String NAMESPACE = "http://merck.github.io/Halyard/ns#";
// 
//     public static final IRI STATS_ROOT_NODE = SVF.createIRI(NAMESPACE, "statsRoot");
// 
//     public static final IRI STATS_GRAPH_CONTEXT = SVF.createIRI(NAMESPACE, "statsContext");
// 
//     public static final IRI SYSTEM_GRAPH_CONTEXT = SVF.createIRI(NAMESPACE, "system");
// 
//     public static final IRI NAMESPACE_PREFIX_PROPERTY = HALYARD.SVF.createIRI(NAMESPACE, "namespacePrefix");
// 
//     public final static IRI TABLE_NAME_PROPERTY = SVF.createIRI(NAMESPACE, "tableName");
// 
//     public final static IRI SPLITBITS_PROPERTY = SVF.createIRI(NAMESPACE, "splitBits");
// 
//     public final static IRI CREATE_TABLE_PROPERTY = SVF.createIRI(NAMESPACE, "createTable");
// 
//     public final static IRI PUSH_STRATEGY_PROPERTY = SVF.createIRI(NAMESPACE, "pushStrategy");
// 
//     public final static IRI EVALUATION_TIMEOUT_PROPERTY = SVF.createIRI(NAMESPACE, "evaluationTimeout");
// 
//     public final static IRI ELASTIC_INDEX_URL_PROPERTY = SVF.createIRI(NAMESPACE, "elasticIndexURL");
// 
//     public final static IRI SEARCH_TYPE = SVF.createIRI(NAMESPACE, "search");
// 
//     public final static IRI PARALLEL_SPLIT_FUNCTION = SVF.createIRI(NAMESPACE, "forkAndFilterBy");
// 
// }


// Path: strategy/src/main/java/com/msd/gin/halyard/optimizers/HalyardEvaluationStatistics.java
import com.msd.gin.halyard.vocab.HALYARD;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.query.algebra.ArbitraryLengthPath;
import org.eclipse.rdf4j.query.algebra.BinaryTupleOperator;
import org.eclipse.rdf4j.query.algebra.BindingSetAssignment;
import org.eclipse.rdf4j.query.algebra.EmptySet;
import org.eclipse.rdf4j.query.algebra.Filter;
import org.eclipse.rdf4j.query.algebra.Join;
import org.eclipse.rdf4j.query.algebra.LeftJoin;
import org.eclipse.rdf4j.query.algebra.QueryModelNode;
import org.eclipse.rdf4j.query.algebra.Service;
import org.eclipse.rdf4j.query.algebra.SingletonSet;
import org.eclipse.rdf4j.query.algebra.StatementPattern;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.UnaryTupleOperator;
import org.eclipse.rdf4j.query.algebra.Var;
import org.eclipse.rdf4j.query.algebra.ZeroLengthPath;
import org.eclipse.rdf4j.query.algebra.evaluation.impl.EvaluationStatistics;
import org.eclipse.rdf4j.query.algebra.evaluation.impl.ExternalSet;


    public synchronized double getCardinality(TupleExpr expr, final Set<String> boundVariables, final Set<String> priorityVariables) {
        if (cc == null) {
            cc = new HalyardCardinalityCalcualtor(boundVariables, priorityVariables, null);
        }
        expr.visit(cc);
        return cc.getCardinality();
    }

    @Override
    protected CardinalityCalculator createCardinalityCalculator() {
        return new HalyardCardinalityCalcualtor(Collections.emptySet(), Collections.emptySet(), null);
    }

    private class HalyardCardinalityCalcualtor extends CardinalityCalculator {

        private Set<String> boundVars;
        private final Set<String> priorityVariables;
        private final Map<TupleExpr, Double> mapToUpdate;

        public HalyardCardinalityCalcualtor(Set<String> boundVariables, Set<String> priorityVariables, Map<TupleExpr, Double> mapToUpdate) {
            this.boundVars = boundVariables;
            this.priorityVariables = priorityVariables;
            this.mapToUpdate = mapToUpdate;
        }

        @Override
        protected double getCardinality(StatementPattern sp) {
            //always preffer HALYARD.SEARCH_TYPE object literals to move such statements higher in the joins tree
            Var objectVar = sp.getObjectVar();
            if (objectVar.hasValue() && (objectVar.getValue() instanceof Literal) && HALYARD.SEARCH_TYPE.equals(((Literal) objectVar.getValue()).getDatatype())) {