Example #1
0
        public static void FromOperator(IOperator op)
        {
            var permList = new List <List <IObject> >();

            foreach (Term variable in op.Terms)
            {
                permList.Add(typeDict[variable.Type] as List <IObject>);
            }

            foreach (var combination in EnumerableExtension.GenerateCombinations(permList))
            {
                // Add bindings
                var opClone            = op.Clone() as Operator;
                var termStringList     = from term in opClone.Terms select term.Variable;
                var constantStringList = from objConst in combination select objConst.Name;
                opClone.AddBindings(termStringList.ToList(), constantStringList.ToList());
                var legal = true;
                foreach (var precon in opClone.Preconditions)
                {
                    if (!NonStaticPredicates.Contains(precon.Name))
                    {
                        // this predicate is static
                        if (!Init.Contains(precon))
                        {
                            legal = false;
                            break;
                        }
                    }
                }
                if (!legal)
                {
                    continue;
                }

                // this ensures that this ground operator has a unique ID
                var groundOperator = new Operator(opClone.Name, opClone.Terms, opClone.Bindings, opClone.Preconditions, opClone.Effects);

                if (GroundLibrary.ContainsKey(groundOperator.ID))
                {
                    throw new System.Exception();
                }

                GroundActions.Add(groundOperator as IOperator);
                GroundLibrary[groundOperator.ID] = groundOperator;
            }
        }
        public static List <IOperator> FromOperatorWithReturn(IOperator op)
        {
            var listToReturn = new List <IOperator>();
            var permList     = new List <List <string> >();

            foreach (Term variable in op.Terms)
            {
                permList.Add(TypeDict[variable.Type] as List <string>);
            }

            foreach (var combination in EnumerableExtension.GenerateCombinations(permList))
            {
                // Add bindings
                var opClone            = op.Clone() as Operator;
                var termStringList     = from term in opClone.Terms select term.Variable;
                var constantStringList = combination;

                opClone.AddBindings(termStringList.ToList(), constantStringList.ToList());

                if (!opClone.NonEqualTermsAreNonequal())
                {
                    continue;
                }

                //Debug.Log("operator: " + opClone.ToString());

                // this ensures that this ground operator has a unique ID
                var groundOperator = new Operator(opClone.Name, opClone.Terms, opClone.Bindings, opClone.Preconditions, opClone.Effects);

                if (GroundActionFactory.GroundActions.Contains(groundOperator))
                {
                    continue;
                }

                if (GroundLibrary.ContainsKey(groundOperator.ID))
                {
                    throw new System.Exception();
                }

                InsertOperator(groundOperator as IOperator);
                listToReturn.Add(groundOperator as IOperator);
            }

            return(listToReturn);
        }
Example #3
0
        /// <summary>
        /// The Decomposition is composed of a sub-plan with at least sub-step at height "height"
        /// </summary>
        /// <returns>A list of decompositions with ground terms and where each sub-step is ground. </returns>
        public List <Decomposition> Compose(int height)
        {
            ///////////////////////////////////////
            // START BY ADDING BINDINGS TO TERMS //
            ///////////////////////////////////////
            var permList = new List <List <string> >();

            foreach (Term variable in Terms)
            {
                permList.Add(GroundActionFactory.TypeDict[variable.Type] as List <string>);
            }

            var decompList = new List <Decomposition>();

            foreach (var combination in EnumerableExtension.GenerateCombinations(permList))
            {
                // Add bindings
                var decompClone        = Clone() as Decomposition;
                var termStringList     = from term in decompClone.Terms select term.Variable;
                var constantStringList = combination;

                decompClone.AddBindings(termStringList.ToList(), constantStringList.ToList());

                /////////////////////////////////////////////////////////
                // PROPAGATE BINDINGS TO NONEQUALITY CONSTRAINTS
                /////////////////////////////////////////////////////////
                var newNonEqualities = new List <List <ITerm> >();
                foreach (var nonequals in NonEqualities)
                {
                    var newNonEquals = new List <ITerm>();
                    newNonEquals.Add(decompClone.Terms.First(dterm => dterm.Variable.Equals(nonequals[0].Variable)));
                    newNonEquals.Add(decompClone.Terms.First(dterm => dterm.Variable.Equals(nonequals[1].Variable)));
                    newNonEqualities.Add(newNonEquals);
                }
                decompClone.NonEqualities = newNonEqualities;
                if (!decompClone.NonEqualTermsAreNonequal())
                {
                    continue;
                }

                // zip to dict
                var varDict = EnumerableExtension.Zip(termStringList, constantStringList).ToDictionary(x => x.Key, x => x.Value);


                /////////////////////////////////////////////////////////
                // BINDINGS ARE ADDED. NEED TO APPLY BINDINGS TO SUBSTEPS
                /////////////////////////////////////////////////////////

                // Need to propagate bindings to sub-steps
                foreach (var substep in decompClone.SubSteps)
                {
                    var op = substep.Action as Operator;
                    foreach (var term in substep.Terms)
                    {
                        op.AddBinding(term.Variable, varDict[term.Variable]);
                    }
                    foreach (var precon in substep.Preconditions)
                    {
                        foreach (var term in precon.Terms)
                        {
                            if (!term.Bound)
                            {
                                var decompTerm = decompClone.Terms.First(dterm => dterm.Variable.Equals(term.Variable));
                                op.Terms.Add(term);
                                op.AddBinding(term.Variable, decompTerm.Constant);
                            }
                        }
                    }
                    foreach (var eff in substep.Effects)
                    {
                        foreach (var term in eff.Terms)
                        {
                            if (!term.Bound)
                            {
                                var decompTerm = decompClone.Terms.First(dterm => dterm.Variable.Equals(term.Variable));
                                op.Terms.Add(term);
                                op.AddBinding(term.Variable, decompTerm.Constant);
                            }
                        }
                    }
                }



                ////////////////////////////////////////////////////////////////
                // FILTER CANDIDATES FOR SUBSTEPS AND PASS BACK GROUNDED DECOMPS
                ////////////////////////////////////////////////////////////////
                var newGroundDecomps = FilterDecompCandidates(decompClone, height);
                foreach (var gdecomp in newGroundDecomps)
                {
                    decompList.Add(gdecomp);
                }
                //Console.WriteLine("Check");
            }

            return(decompList);
        }
Example #4
0
        /// <summary>
        /// Filters candidates for substeps, at least one with height "height"
        /// </summary>
        /// <param name="decomp"></param>
        /// <returns> List of decompositions with ground sub-steps. </returns>
        public static List <Decomposition> FilterDecompCandidates(Decomposition decomp, int height)
        {
            // find and replace sub-steps
            var comboList = new List <List <IOperator> >();
            var ID_List   = new List <int>();

            foreach (var substep in decomp.SubSteps)
            {
                ID_List.Add(substep.ID);
                // each substep has ground terms that are already consistent. Composite IS-A Operator
                var cndts = ConsistentSteps(substep.Action as Operator);

                // If there's no cndts for this substep, then abandon this decomp.
                if (cndts.Count == 0)
                {
                    return(new List <Decomposition>());
                }

                comboList.Add(cndts);
            }

            List <Decomposition> decompList = new List <Decomposition>();

            foreach (var combination in EnumerableExtension.GenerateCombinations(comboList))
            {
                var decompClone           = decomp.Clone() as Decomposition;
                var newSubsteps           = new List <IPlanStep>();
                var substepDict           = new Dictionary <int, IPlanStep>();
                var order                 = 0;
                var hasPrerequisiteHeight = false;
                foreach (var item in combination)
                {
                    if (item.Height >= height)
                    {
                        // meets height requirement
                        hasPrerequisiteHeight = true;
                    }
                    var originalID = ID_List[order++];
                    if (item.Height > 0)
                    {
                        var newPlanStep = new CompositePlanStep(item as Composite);
                        substepDict[originalID] = newPlanStep;
                        newSubsteps.Add(newPlanStep);
                    }
                    else
                    {
                        var newPlanStep = new PlanStep(item);
                        substepDict[originalID] = newPlanStep;
                        newSubsteps.Add(newPlanStep);
                    }
                }

                // Did not meet requirements for height.
                if (!hasPrerequisiteHeight)
                {
                    continue;
                }

                var newSuborderings = new List <Tuple <IPlanStep, IPlanStep> >();
                foreach (var subordering in decomp.SubOrderings)
                {
                    var first  = substepDict[subordering.First.ID];
                    var second = substepDict[subordering.Second.ID];
                    newSuborderings.Add(new Tuple <IPlanStep, IPlanStep>(first, second));
                }

                var linkWorlds = new List <List <CausalLink <IPlanStep> > >();
                linkWorlds.Add(new List <CausalLink <IPlanStep> >());
                var newSublinks = new List <CausalLink <IPlanStep> >();
                foreach (var sublink in decomp.SubLinks)
                {
                    var head  = substepDict[sublink.Head.ID];
                    var tail  = substepDict[sublink.Tail.ID];
                    var cndts = head.Effects.Where(eff => eff.IsConsistent(sublink.Predicate) && tail.Preconditions.Any(pre => pre.Equals(eff)));

                    //// swap tall members
                    //if (head.Height > 0)
                    //{
                    //    var Chead = head as CompositePlanStep;
                    //    head = Chead.GoalStep;
                    //}
                    //if (tail.Height > 0)
                    //{
                    //    var Ctail = tail as CompositePlanStep;
                    //    tail = Ctail.InitialStep;
                    //}

                    if (cndts.Count() == 0)
                    {
                        // forfeit this entire subplan
                        linkWorlds = new List <List <CausalLink <IPlanStep> > >();
                        continue;
                    }
                    if (cndts.Count() == 1)
                    {
                        var cndt       = cndts.First();
                        var dependency = cndt.Clone() as Predicate;
                        var newLink    = new CausalLink <IPlanStep>(dependency, head, tail);
                        newLink.Tail.Fulfill(cndt);
                        foreach (var linkworld in linkWorlds)
                        {
                            linkworld.Add(newLink);
                        }
                    }
                    else
                    {
                        foreach (var cndt in cndts)
                        {
                            var dependency = cndt.Clone() as Predicate;

                            var newLink = new CausalLink <IPlanStep>(dependency, head, tail);
                            newLink.Tail.Fulfill(cndt);

                            var clonedLinks = EnumerableExtension.CloneList(newSublinks);

                            linkWorlds.Add(clonedLinks);
                            foreach (var linkworld in linkWorlds)
                            {
                                linkworld.Add(newLink);
                            }
                        }
                    }
                }

                foreach (var linkworld in linkWorlds)
                {
                    var newDecomp = decomp.Clone() as Decomposition;
                    newDecomp.SubSteps     = newSubsteps;
                    newDecomp.SubOrderings = newSuborderings;
                    newDecomp.SubLinks     = linkworld;

                    decompList.Add(newDecomp);
                }
            }
            return(decompList);
        }
        // difference between this and overrided method is that this packages list of decompositions with a substep dictionary int -> replaced plan step
        public static List <Tuple <TimelineDecomposition, Dictionary <int, IPlanStep> > > FilterDecompCandidates(TimelineDecomposition decomp)
        {
            // find and replace sub-steps
            var comboList = new List <List <IOperator> >();
            var ID_List   = new List <int>();

            foreach (var substep in decomp.SubSteps)
            {
                ID_List.Add(substep.ID);
                // each substep has ground terms that are already consistent. Composite IS-A Operator
                var cndts = ConsistentSteps(substep.Action as Operator);

                // If there's no cndts for this substep, then abandon this decomp.
                if (cndts.Count == 0)
                {
                    return(new List <Tuple <TimelineDecomposition, Dictionary <int, IPlanStep> > >());
                }

                comboList.Add(cndts);
            }

            // update to this method is to track, for each decomposition, which number substep goes to which grounded plan step
            List <Tuple <TimelineDecomposition, Dictionary <int, IPlanStep> > > decompMap = new List <Tuple <TimelineDecomposition, Dictionary <int, IPlanStep> > >();

            foreach (var combination in EnumerableExtension.GenerateCombinations(comboList))
            {
                var decompClone = decomp.Clone() as TimelineDecomposition;
                var newSubsteps = new List <IPlanStep>();
                var substepDict = new Dictionary <int, IPlanStep>();

                var order = 0;
                foreach (var item in combination)
                {
                    var originalID  = ID_List[order++];
                    var newPlanStep = new PlanStep(item);
                    substepDict[originalID] = newPlanStep;
                    newSubsteps.Add(newPlanStep);
                }

                var newSuborderings = new List <Tuple <IPlanStep, IPlanStep> >();
                foreach (var subordering in decomp.SubOrderings)
                {
                    var first  = substepDict[subordering.First.ID];
                    var second = substepDict[subordering.Second.ID];
                    newSuborderings.Add(new Tuple <IPlanStep, IPlanStep>(first, second));
                }

                var linkWorlds = new List <List <CausalLink <IPlanStep> > >();
                linkWorlds.Add(new List <CausalLink <IPlanStep> >());
                var newSublinks = new List <CausalLink <IPlanStep> >();
                foreach (var sublink in decomp.SubLinks)
                {
                    var head = substepDict[sublink.Head.ID];
                    var tail = substepDict[sublink.Tail.ID];
                    List <IPredicate> cndts = new List <IPredicate>();
                    //var cndts = head.Effects.Where(eff => eff.IsConsistent(sublink.Predicate) && tail.Preconditions.Any(pre => pre.Equals(eff)));
                    foreach (var eff in head.Effects)
                    {
                        foreach (var pre in tail.Preconditions)
                        {
                            if (eff.Equals(pre))
                            {
                                cndts.Add(eff);
                                //Debug.Log("here");
                            }
                        }
                    }

                    if (cndts.Count() == 0)
                    {
                        // forfeit this entire subplan
                        linkWorlds = new List <List <CausalLink <IPlanStep> > >();
                        continue;
                    }
                    if (cndts.Count() == 1)
                    {
                        var cndt       = cndts.First();
                        var dependency = cndt.Clone() as Predicate;
                        var newLink    = new CausalLink <IPlanStep>(dependency, head, tail);
                        newLink.Tail.Fulfill(cndt);
                        foreach (var linkworld in linkWorlds)
                        {
                            linkworld.Add(newLink);
                        }
                    }
                    else
                    {
                        foreach (var cndt in cndts)
                        {
                            var dependency = cndt.Clone() as Predicate;

                            var newLink = new CausalLink <IPlanStep>(dependency, head, tail);
                            newLink.Tail.Fulfill(cndt);

                            var clonedLinks = EnumerableExtension.CloneList(newSublinks);

                            linkWorlds.Add(clonedLinks);
                            foreach (var linkworld in linkWorlds)
                            {
                                linkworld.Add(newLink);
                            }
                        }
                    }
                }

                foreach (var linkworld in linkWorlds)
                {
                    var newDecomp = decomp.Clone() as TimelineDecomposition;
                    newDecomp.SubSteps     = newSubsteps;
                    newDecomp.SubOrderings = newSuborderings;
                    newDecomp.SubLinks     = linkworld;

                    var outputTuple = new Tuple <TimelineDecomposition, Dictionary <int, IPlanStep> >(newDecomp, substepDict);
                    decompMap.Add(outputTuple);
                }
            }
            return(decompMap);
        }
Example #6
0
        /// <summary>
        /// The Decomposition is composed of a sub-plan with at least sub-step at height "height"
        /// </summary>
        /// <returns>A list of decompositions with ground terms and where each sub-step is ground. </returns>
        public static List <TimelineDecomposition> Compose(int height, TimelineDecomposition TD, List <CamSchema> camOptions, Dictionary <string, Vector3> locationMap)
        {
            ///////////////////////////////////////
            // START BY ADDING BINDINGS TO TERMS //
            ///////////////////////////////////////
            var permList = new List <List <string> >();

            foreach (Term variable in TD.Terms)
            {
                permList.Add(GroundActionFactory.TypeDict[variable.Type] as List <string>);
            }

            var decompList = new List <TimelineDecomposition>();

            foreach (var combination in EnumerableExtension.GenerateCombinations(permList))
            {
                // Add bindings
                var decompClone        = TD.Clone() as TimelineDecomposition;
                var termStringList     = from term in decompClone.Terms select term.Variable;
                var constantStringList = combination;

                decompClone.AddBindings(termStringList.ToList(), constantStringList.ToList());

                /////////////////////////////////////////////////////////
                // PROPAGATE BINDINGS TO NONEQUALITY CONSTRAINTS
                /////////////////////////////////////////////////////////
                var newNonEqualities = new List <List <ITerm> >();
                if (TD.NonEqualities == null)
                {
                    TD.NonEqualities = new List <List <ITerm> >();
                }
                else
                {
                    foreach (var nonequals in TD.NonEqualities)
                    {
                        var newNonEquals = new List <ITerm>();
                        newNonEquals.Add(decompClone.Terms.First(dterm => dterm.Variable.Equals(nonequals[0].Variable)));
                        newNonEquals.Add(decompClone.Terms.First(dterm => dterm.Variable.Equals(nonequals[1].Variable)));
                        newNonEqualities.Add(newNonEquals);
                    }
                    decompClone.NonEqualities = newNonEqualities;

                    if (!decompClone.NonEqualTermsAreNonequal())
                    {
                        continue;
                    }
                }

                // zip to dict
                var varDict = EnumerableExtension.Zip(termStringList, constantStringList).ToDictionary(x => x.Key, x => x.Value);

                /////////////////////////////////////////////////////////
                // BINDINGS ARE ADDED. NEED TO APPLY BINDINGS TO SUBSTEPS
                /////////////////////////////////////////////////////////

                // Need to propagate bindings to sub-steps
                foreach (var substep in decompClone.SubSteps)
                {
                    var op = substep.Action as Operator;
                    foreach (var term in substep.Terms)
                    {
                        op.AddBinding(term.Variable, varDict[term.Variable]);
                    }
                    foreach (var precon in substep.Preconditions)
                    {
                        foreach (var term in precon.Terms)
                        {
                            if (!term.Bound)
                            {
                                var decompTerm = decompClone.Terms.First(dterm => dterm.Variable.Equals(term.Variable));
                                op.Terms.Add(term);
                                op.AddBinding(term.Variable, decompTerm.Constant);
                            }
                        }
                    }
                    foreach (var eff in substep.Effects)
                    {
                        foreach (var term in eff.Terms)
                        {
                            if (!term.Bound)
                            {
                                var decompTerm = decompClone.Terms.First(dterm => dterm.Variable.Equals(term.Variable));
                                op.Terms.Add(term);
                                op.AddBinding(term.Variable, decompTerm.Constant);
                            }
                        }
                    }
                }

                ////////////////////////////////////////////////////////////////
                // FILTER CANDIDATES FOR SUBSTEPS AND PASS BACK GROUNDED DECOMPS
                ////////////////////////////////////////////////////////////////

                // legacy for fabula subplan. returns a list of decomp packages, whose second member is a map from fabula substep IDs to substeps
                var fabulaGroundedDecompMap = TimelineDecomposition.FilterDecompCandidates(decompClone);

                // foreach decomposition including a mapping from fabula substep IDs to substeps
                foreach (Tuple <TimelineDecomposition, Dictionary <int, IPlanStep> > decompPackage in fabulaGroundedDecompMap)
                {
                    // get candidates and ground for camera steps
                    var newGroundDecomps = TimelineDecompositionHelper.FilterTimelineDecompCandidates(TD, decompPackage, height, camOptions, locationMap);

                    foreach (var gdecomp in newGroundDecomps)
                    {
                        // This function updates the mapping from action variable names to step-variables, and repoints mapping to grounded fabula substep. These names used by camera shots.
                        gdecomp.UpdateActionVarMap(decompPackage.Second);
                        // Add new ground decomposition to map.
                        decompList.Add(gdecomp);
                    }
                }
            }

            return(decompList);
        }
Example #7
0
        /// <summary>
        /// Takes a fabula-valid decomposition and generates a list of discourse worlds (different camera shots to display the fabula)
        /// </summary>
        /// <param name="decompPackage"> Grounded fabula substeps and a mapping from step variables to those substeps </param>
        /// <param name="height"> Among CamOptions would include composite options... but may </param>
        /// <param name="camOptions"> From "Cameras" GameObject </param>
        /// <param name="locationMap"> Mapping location names to specific coordinates (used to determine orientation in space, and possibly for navigation estimates. </param>
        /// <returns> A list of TimelineDecomposition which all have fabula-valid and discourse-valid sub-plan</returns>
        public static List <TimelineDecomposition> FilterTimelineDecompCandidates(TimelineDecomposition TD, Tuple <TimelineDecomposition, Dictionary <int, IPlanStep> > decompPackage, int height,
                                                                                  List <CamSchema> camOptions, Dictionary <string, Vector3> locationMap)
        {
            var timelineDecompList = new List <TimelineDecomposition>();

            var decomp      = decompPackage.First;
            var substepDict = decompPackage.Second;

            // mapping ID of substeps to orientations
            var orientLocationTuple = GetOrientsAndLocations(decomp, locationMap);
            var orientDict          = orientLocationTuple.First;
            var locationDict        = orientLocationTuple.Second;

            // Easier list to reference later
            //var discourseSubStepList = new List<CamPlanStep>();

            // create permutation for each combination of legal subcams
            var permList = GetPermutationCameraShots(TD.discourseSubSteps, substepDict, TD.fabulaActionNameMap, orientDict, locationDict, camOptions);

            //ist<CamPlanStep> discourseSubSteps, Dictionary<int, IPlanStep> fabsubstepDict, Dictionary<string, IPlanStep> fabulaActionNameMap,
            //Dictionary<int, int> orientDict, Dictionary< int, string> locationDict, List<CamAttributesStruct> camOptions

            // foreach combination, check if step constraints are true
            foreach (var combination in EnumerableExtension.GenerateCombinations(permList))
            {
                // clone decomp
                var decompClone          = decomp.Clone() as TimelineDecomposition;
                var camSubStepDict       = new Dictionary <int, CamPlanStep>();
                var newDiscourseSubSteps = new List <CamPlanStep>();
                for (int j = 0; j < combination.Count; j++)
                {
                    // a reference to the camera object candidate
                    //var camObj = combination[j].AttributesToSchema();

                    // a reference to the j'th discourse step
                    var camStep = TD.discourseSubSteps[j].Clone() as CamPlanStep;
                    camStep.CamDetails = combination[j].Clone() as CamSchema;
                    //camStep.CamObject = camObj.gameObject;

                    // a cloning of the cam plan step
                    //var newPlanStep = camStep.Clone();
                    //newPlanStep.CamObject = camObj.gameObject;

                    // storing a mapping from old cam plan step ID to new cam plan step
                    camSubStepDict[camStep.ID] = camStep;
                    newDiscourseSubSteps.Add(camStep);
                }

                var boolOutcome = ValidateConstraints(substepDict, camSubStepDict, TD.fabConstraints, TD.discConstraints, orientDict);
                //    public static bool ValidateConstraints(Dictionary<int, IPlanStep> fabsubstepDict, Dictionary<int, CamPlanStep> discsubstepDict,
                //List<Tuple<string, Tuple<IPlanStep, IPlanStep>>> fabConstraints, List<Tuple<string, Tuple<IPlanStep, IPlanStep>>> discConstraints,
                //Dictionary<int, int> orientDict)
                if (!boolOutcome)
                {
                    continue;
                }

                // these are done here, but they could/should have been performed during regular legacy decomposition filtering.
                var newFabCntgs = new List <Tuple <IPlanStep, IPlanStep> >();
                foreach (var subCntg in TD.fabCntgs)
                {
                    var newcntg = new Tuple <IPlanStep, IPlanStep>(substepDict[subCntg.First.ID], substepDict[subCntg.Second.ID]);
                    newFabCntgs.Add(newcntg);
                }


                var newDOrderings = new List <Tuple <CamPlanStep, CamPlanStep> >();
                foreach (var subOrdering in TD.discOrderings)
                {
                    var newOrdering = new Tuple <CamPlanStep, CamPlanStep>(camSubStepDict[subOrdering.First.ID], camSubStepDict[subOrdering.Second.ID]);
                    newDOrderings.Add(newOrdering);
                }

                var newDiscCntgs = new List <Tuple <CamPlanStep, CamPlanStep> >();
                foreach (var subCntg in TD.discCntgs)
                {
                    var newcntg = new Tuple <CamPlanStep, CamPlanStep>(camSubStepDict[subCntg.First.ID], camSubStepDict[subCntg.Second.ID]);
                    newDiscCntgs.Add(newcntg);
                }


                var linkWorlds = new List <List <CausalLink <CamPlanStep> > >();
                linkWorlds.Add(new List <CausalLink <CamPlanStep> >());
                var newSublinks = new List <CausalLink <CamPlanStep> >();
                foreach (var subLink in TD.discLinks)
                {
                    var head  = camSubStepDict[subLink.Head.ID];
                    var tail  = camSubStepDict[subLink.Tail.ID];
                    var cndts = head.Effects.Where(eff => eff.IsConsistent(subLink.Predicate) && tail.Preconditions.Any(pre => pre.Equals(eff)));
                    if (cndts.Count() == 0)
                    {
                        // forfeit this entire subplan
                        linkWorlds = new List <List <CausalLink <CamPlanStep> > >();
                        break;
                    }
                    if (cndts.Count() == 1)
                    {
                        var cndt       = cndts.First();
                        var dependency = cndt.Clone() as Predicate;
                        var newLink    = new CausalLink <CamPlanStep>(dependency, head, tail);
                        newLink.Tail.Fulfill(cndt);
                        foreach (var linkworld in linkWorlds)
                        {
                            linkworld.Add(newLink);
                        }
                    }
                    else
                    {
                        foreach (var cndt in cndts)
                        {
                            var dependency = cndt.Clone() as Predicate;

                            var newLink = new CausalLink <CamPlanStep>(dependency, head, tail);
                            newLink.Tail.Fulfill(cndt);

                            var clonedLinks = EnumerableExtension.CloneList(newSublinks);

                            linkWorlds.Add(clonedLinks);
                            foreach (var linkworld in linkWorlds)
                            {
                                linkworld.Add(newLink);
                            }
                        }
                    }
                }

                foreach (var linkworld in linkWorlds)
                {
                    var newDecomp = decomp.Clone() as TimelineDecomposition;
                    newDecomp.discourseSubSteps = TD.discourseSubSteps;
                    newDecomp.discOrderings     = newDOrderings;
                    newDecomp.fabCntgs          = newFabCntgs;
                    newDecomp.discCntgs         = newDiscCntgs;
                    newDecomp.discLinks         = linkworld;

                    timelineDecompList.Add(newDecomp);
                }
            }

            return(timelineDecompList);
        }