All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ggp.base.util.assignments.ComplexAssignmentIterationPlan Maven / Gradle / Ivy

There is a newer version: 0.0.15
Show newest version
package org.ggp.base.util.assignments;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;

import org.ggp.base.util.gdl.GdlUtils;
import org.ggp.base.util.gdl.grammar.GdlConstant;
import org.ggp.base.util.gdl.grammar.GdlLiteral;
import org.ggp.base.util.gdl.grammar.GdlVariable;

import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;

/**
 * A {@link NewAssignmentIterationPlan} implementation that incorporates
 * all the possibilities of the old AssignmentIterator:
 *
 * 1) Iteration over sources of conjuncts (i.e. explicit lists of possible
 *    sentences that define multiple variables at once)
 * 2) Functional conjuncts: sentences that, once one (or some) variables
 *    are defined, leave only one possibility for the remaining variable.
 * 3) Normal iteration over the remaining variables.
 *
 * The tricky part will be finding ways to find the right plan (or a
 * "good-enough" plan) quickly enough. However, if we can convert the
 * old code's algorithm, that should be fine for now.
 */
public class ComplexAssignmentIterationPlan implements
NewAssignmentIterationPlan {
    private final ImmutableList assignmentOrder;
    private final ImmutableList strategies;

    private final ImmutableList strategyDefiningVarIndex;
    private final ImmutableList indexWithinStrategyForVarIndex;

    //TODO: In constructor, check consistency of strategies, assignment order
    public ComplexAssignmentIterationPlan(
            ImmutableList assignmentOrder,
            ImmutableList strategies,
            ImmutableList strategyDefiningVarIndex,
            ImmutableList indexWithinStrategyForVarIndex) {
        this.assignmentOrder = assignmentOrder;
        this.strategies = strategies;
        this.strategyDefiningVarIndex = strategyDefiningVarIndex;
        this.indexWithinStrategyForVarIndex = indexWithinStrategyForVarIndex;
        validatePlan();
    }

    //TODO: Probably want to convert these strategies from some other format
    public static NewAssignmentIterationPlan create(List assignmentOrder,
            List strategies) {
        if (strategies.isEmpty()) {
            Preconditions.checkArgument(assignmentOrder.isEmpty());
            return SingletonAssignmentIterationPlan.create();
        }

        List strategyDefiningVarIndex = Lists.newArrayList();
        List indexWithinStrategyForVarIndex = Lists.newArrayList();
        for (int i = 0; i < assignmentOrder.size(); i++) {
            strategyDefiningVarIndex.add(-1);
            indexWithinStrategyForVarIndex.add(-1);
        }

        for (int s = 0; s < strategies.size(); s++) {
            AssignmentStrategy strategy = strategies.get(s);
            List definedIndices = strategy.getDefinedIndices();
            for (int i = 0; i < definedIndices.size(); i++) {
                int varIndex = definedIndices.get(i);
                Preconditions.checkState(strategyDefiningVarIndex.get(varIndex) == -1);
                Preconditions.checkState(indexWithinStrategyForVarIndex.get(varIndex) == -1);
                strategyDefiningVarIndex.set(varIndex, s);
                indexWithinStrategyForVarIndex.set(varIndex, i);
            }
        }
        return new ComplexAssignmentIterationPlan(
                ImmutableList.copyOf(assignmentOrder),
                ImmutableList.copyOf(strategies),
                ImmutableList.copyOf(strategyDefiningVarIndex),
                ImmutableList.copyOf(indexWithinStrategyForVarIndex));
    }

    private void validatePlan() {
        //TODO: Add more validation checks
        for (AssignmentStrategy strategy : strategies) {
            Preconditions.checkState(isSorted(strategy.getDependentIndices()));
            Preconditions.checkState(isSorted(strategy.getDefinedIndices()));
        }
    }

    private boolean isSorted(List indices) {
        return Ordering.natural().isStrictlyOrdered(indices);
    }

    public class ComplexAssignmentIterator implements NewAssignmentIterator {
        private final List>> partialAssignmentsByStrategy;
        private final List currentPartialAssignmentIndex;
        private boolean done = false;

        public ComplexAssignmentIterator() {
            //Go through strategies, make sure they're all fulfilled
            //incrementStrategy will use set()
            partialAssignmentsByStrategy = Lists.newArrayListWithCapacity(strategies.size());
            currentPartialAssignmentIndex = Lists.newArrayListWithCapacity(strategies.size());
            for (int i = 0; i < strategies.size(); i++) {
                partialAssignmentsByStrategy.add(null);
                currentPartialAssignmentIndex.add(-1);
            }
            regenerateStrategy(0);
            if (partialAssignmentsByStrategy.get(0) == null
                    || partialAssignmentsByStrategy.get(0).isEmpty()) {
                done = true;
            }
        }

        private void regenerateStrategy(int strategyIndex) {
            //Collect assignments for the strategy given its predecessors
            AssignmentStrategy strategy = strategies.get(strategyIndex);
            List inputs = collectInputsFor(strategy);
            List> newPartialAssignments = strategy.getPartialAssignments(inputs);
            if (newPartialAssignments.isEmpty()) {
                //Need to recursively backtrack... or will that not quite work?
                int rejectedIndex = strategy.getRejectedIndex(inputs);
                if (rejectedIndex == AssignmentStrategy.NO_INDEX_REJECTED) {
                    //No more assignments are possible
                    done = true;
                    return;
                }
                //Advance the earlier strategy instead
                advanceStrategy(getStrategyToAdvanceFromVarIndex(rejectedIndex));
                return;
            }
            //(resetting indices as we go)
            partialAssignmentsByStrategy.set(strategyIndex, newPartialAssignments);
            currentPartialAssignmentIndex.set(strategyIndex, 0);
            //Then, unless we're the last one, increment the next strategy
            if (strategyIndex + 1 < strategies.size()) {
                regenerateStrategy(strategyIndex + 1);
            }
        }

        private void advanceStrategy(int strategyIndex) {
            //Can we advance?
            int curIndex = currentPartialAssignmentIndex.get(strategyIndex);
            if (curIndex + 1 < partialAssignmentsByStrategy.get(strategyIndex).size()) {
                //Yes, advance
                currentPartialAssignmentIndex.set(strategyIndex, curIndex + 1);
                if (strategyIndex + 1 < strategies.size()) {
                    regenerateStrategy(strategyIndex + 1);
                }
                return;
            } else {
                //No, advance an earlier strategy, if possible
                if (strategyIndex == 0) {
                    done = true;
                    return;
                } else {
                    advanceStrategy(strategyIndex - 1);
                }
            }
        }

        private int getStrategyToAdvanceFromVarIndex(int rejectedVarIndex) {
            return strategyDefiningVarIndex.get(rejectedVarIndex);
        }

        private List collectInputsFor(AssignmentStrategy strategy) {
            List inputs = Lists.newArrayListWithCapacity(strategy.getDependentIndices().size());
            for (int dependentIndex : strategy.getDependentIndices()) {
                inputs.add(getCurValueForVarIndex(dependentIndex));
            }
            return inputs;
        }

        private GdlConstant getCurValueForVarIndex(int varIndex) {
            int strategyIndex = strategyDefiningVarIndex.get(varIndex);
            int curAssignmentIndex = currentPartialAssignmentIndex.get(strategyIndex);
            int constantIndex = indexWithinStrategyForVarIndex.get(varIndex);
            return partialAssignmentsByStrategy.get(strategyIndex).get(curAssignmentIndex).get(constantIndex);
        }

        @Override
        public boolean hasNext() {
            return !done;
        }

        @Override
        public Map next() {
            Map curAssignment = collectAssignment();
            advanceStrategy(strategies.size() - 1);
            return curAssignment;
        }

        private Map collectAssignment() {
            Map assignment = Maps.newHashMapWithExpectedSize(assignmentOrder.size());
            for (int i = 0; i < assignmentOrder.size(); i++) {
                assignment.put(assignmentOrder.get(i), getCurValueForVarIndex(i));
            }
            return assignment;
        }

        @Override
        public void skipForward(Set unsatisfiableLiterals,
                Map assignment) {
            //			if (true) return;
            for (GdlLiteral literal : unsatisfiableLiterals) {
                //TODO: Does this really make sense?
                //No, only for odometers
                //We should only be skipping until this partial assignment is different somehow
                //				int lastVarIndex = getLastVarIndex(literal);
                List varIndicesInLiteral = getVarIndices(literal);
                int lastVarIndex = getMax(varIndicesInLiteral);
                //TODO: Might want to consider multiple strategies for advancement here?
                //Or do we want the last one?
                int strategyIndex = getStrategyToAdvanceFromVarIndex(lastVarIndex);
                //Get partial assignment
                //Need to skip past a partial assignment...
                //TODO: Need to make this the part of the assignment relevant to the
                //literal, not to the strategy
                skipPastPartialAssignmentInIndex(strategyIndex, varIndicesInLiteral, assignment);
            }
        }

        private int getMax(List varIndicesInLiteral) {
            int max = -1;
            for (int val : varIndicesInLiteral) {
                if (val > max) {
                    max = val;
                }
            }
            return max;
        }

        //		private Map getPartialAssignmentForStrategy(
        //				int strategyIndex, Map assignment) {
        //			//Figure out all the variables in the strategy index,
        //			// TODO Implement
        //		}

        private void skipPastPartialAssignmentInIndex(int strategyIndex,
                List varIndicesInLiteral, Map fullAssignment) {
            //			if (true) return;
            while (!done &&
                    partialAssignmentMatches(varIndicesInLiteral, fullAssignment)
                    /*getCurValueForVarIndex(varIndex) == valueToSkip*/) {
                advanceStrategy(strategyIndex);
            }
        }

        /**
         * Returns true iff all of the var indices listed have the same values in the
         * current assignment as in the given assignment.
         */
        private boolean partialAssignmentMatches(
                List varIndicesInLiteral,
                Map fullAssignment) {
            for (int varIndex : varIndicesInLiteral) {
                GdlVariable var = assignmentOrder.get(varIndex);
                if (getCurValueForVarIndex(varIndex) !=
                        fullAssignment.get(var)) {
                    return false;
                }
            }
            return true;
        }

        private boolean partialAssignmentMatches(
                int strategyIndex,
                List curPartialAssignmentForStrategy,
                Map fullAssignment) {
            List definedIndices = strategies.get(strategyIndex).getDefinedIndices();
            Preconditions.checkArgument(definedIndices.size() == curPartialAssignmentForStrategy.size());
            for (int i = 0; i < curPartialAssignmentForStrategy.size(); i++) {
                //What variable is this?
                int varIndex = definedIndices.get(i);
                GdlVariable var = assignmentOrder.get(varIndex);
                GdlConstant curValue = curPartialAssignmentForStrategy.get(i);
                if (fullAssignment.get(var) != curValue) {
                    return false;
                }
            }
            return true;
        }

        private List getCurPartialAssignmentForStrategy(int strategyIndex) {
            int curAssignmentIndex = currentPartialAssignmentIndex.get(strategyIndex);
            return partialAssignmentsByStrategy.get(strategyIndex).get(curAssignmentIndex);
        }

    }

    //	private int getAssignmentOrderIndex(GdlVariable var) {
    //		//TODO: Optimize?
    ////		return Lists.newArrayList(assignmentOrder).indexOf(var);
    ////		assignmentOrder.get(0);
    //		return 0;
    //	}


    private final LoadingCache lastVarIndexCache =
            CacheBuilder.newBuilder().build(new CacheLoader() {
                @Override
                public Integer load(GdlLiteral literal) throws Exception {
                    //Oddly, writing it this way causes the MPNF to give bad results
                    //Not going to try to track down the exact bug...
                    //TODO: Test with later versions of Java 8/ecj?
                    //					return GdlUtils.getVariables(literal).stream()
                    //						.mapToInt(assignmentOrder::indexOf)
                    //						.max().getAsInt();
                    List variables = GdlUtils.getVariables(literal);
                    int max = -1;
                    for (GdlVariable variable : variables) {
                        int curIndex = assignmentOrder.indexOf(variable);
                        if (curIndex > max) {
                            max = curIndex;
                        }
                    }
                    return max;
                }
            });
    private int getLastVarIndex(GdlLiteral literal) {
        return lastVarIndexCache.getUnchecked(literal);
    }

    private final LoadingCache> varIndicesCache =
            CacheBuilder.newBuilder().build(new CacheLoader>() {
                @Override
                public List load(GdlLiteral literal) throws Exception {
                    List variables = GdlUtils.getVariables(literal);
                    SortedSet indices = Sets.newTreeSet();
                    for (GdlVariable variable : variables) {
                        indices.add(assignmentOrder.indexOf(variable));
                    }
                    return ImmutableList.copyOf(indices);
                }
            });
    private List getVarIndices(GdlLiteral literal) {
        return varIndicesCache.getUnchecked(literal);
    }

    @Override
    public NewAssignmentIterator getIterator() {
        return new ComplexAssignmentIterator();
    }

    @Override
    public String toString() {
        return "ComplexAssignmentIterationPlan [assignmentOrder="
                + assignmentOrder + ", strategies=" + strategies + "]";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy