// 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); }
/// <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); }