<commit_before>package fape.core.planning.heuristics.temporal;

import fape.Planning;
import fape.core.planning.grounding.Fluent;
import fape.core.planning.grounding.GAction;
import fape.core.planning.planner.APlanner;
import fape.core.planning.planner.PlannerFactory;
import fape.util.IteratorConcat;
import fr.laas.fape.structures.DijkstraQueue;
import fr.laas.fape.structures.IR2IntMap;
import fr.laas.fape.structures.IRSet;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;

public class StateDepGraph implements DependencyGraph {

    static final int dbgLvl = 0;
    static final int dbgLvlDij = 0;

    /** Edges and nodes common to all graphs **/
    public DepGraphCore core;

    /** Planner by which this graph is used */
    public final APlanner planner;

    /** Timed initial litterals **/
    public final FactAction facts;

    /** Timed initial literals as a list of edges **/
    List<MinEdge> initMinEdges = new ArrayList<>();
    /** The previous edges indexed by their target fluent. **/
    Map<TempFluent.DGFluent, List<MinEdge>> initFluents = new HashMap<>();

    /** maximum delay of all edges of the graph (i.e. both egdes in the core and those from timed initial literals) **/
    int dmax;

    /** Associates all possible nodes to their earliest appearance (populated after propagation) **/
    IR2IntMap<Node> earliestAppearances = null;

    /** All GActions that be added to the plan (populated after propagation) **/
    IRSet<GAction> addableActs = null;

    /** Earliest appearance of all achievable fluents (populated after propagation) **/
    IR2IntMap<Fluent> fluentsEAs = null;

    /** Associates any possible node to its predecessor (i.e. the possible that gave it its current earliest appearance time).
     * It is currently only used and set by the dijkstra propagator. **/
    private IR2IntMap<Node> predecessors = null;

    public StateDepGraph(DepGraphCore core, List<TempFluent> initFacts, APlanner planner) {
        this.core = core;
        this.planner = planner;

        this.facts = core.store.getFactAction(initFacts);
        dmax = core.dmax;

        for(TempFluent tf : facts.getEffects()) {
            MinEdge e = new MinEdge(facts, tf.fluent, tf.getTime());
            initMinEdges.add(e);
            initFluents.putIfAbsent(tf.fluent, new ArrayList<>());
            initFluents.get(tf.fluent).add(e);
            dmax = Math.max(dmax, e.delay);
        }
    }

    /** Debug method that prints all possible GAction with their earliest appearance time **/
    private void printActions() {
        // complete action: show start
        System.out.println("\nactions: " +
                earliestAppearances.entrySet().stream()
                        .sorted((e1, e2) -> e1.getValue().compareTo(e2.getValue()))
                        .filter(n -> n.getKey() instanceof RAct)
                        .filter(n -> ((RAct) n.getKey()).tp.toString().equals("ContainerStart"))
                        .map(a -> "\n  [" + a.getValue() + "] " + ((RAct) a.getKey()).act)
                        .collect(Collectors.toList()));
    }

    @Override
    public Iterator<MaxEdge> inEdgesIt(ActionNode n) {
        if(n != facts)
            return core.inEdgesIt(n);
        else
            return Collections.emptyIterator(); // fact action has no incoming edges
    }

    @Override
    public Iterator<MinEdge> outEdgesIt(ActionNode n) {
        if(n != facts)
            return core.outEdgesIt(n);
        else
            return initMinEdges.iterator();

    }

    @Override
    public Iterator<MinEdge> inEdgesIt(TempFluent.DGFluent f) {
        if(initFluents.containsKey(f))
            return new IteratorConcat<>(core.inEdgesIt(f), initFluents.get(f).iterator());
        else
            return core.inEdgesIt(f);
    }

    @Override
    public Iterator<MaxEdge> outEdgesIt(TempFluent.DGFluent f) {
        return core.outEdgesIt(f); // no such edge can be added by a fact action
    }


    public IR2IntMap<Node> propagate(Optional<StateDepGraph> ancestorGraph) {

        if(dbgLvlDij > 3) {
            // used when debugging to make sure bellman ford and dijkstra yield the same results
            Propagator p = new BellmanFord(ancestorGraph);
            IR2IntMap<Node> easBF = p.getEarliestAppearances();

            Dijkstra dij = new Dijkstra(ancestorGraph);
            IR2IntMap<Node> easDij = dij.getEarliestAppearances();
            earliestAppearances = easDij;
            predecessors = dij.labelsPred;

            for(Node n : easBF.keys()) {
                assert easDij.containsKey(n);
            }
            for(Node n : easDij.keys()) {
                if(!easBF.containsKey(n))
                    dij.display(n);
                assert easBF.containsKey(n);
                if(!easBF.get(n).equals(easDij.get(n))) {
                    System.out.println(easBF.get(n) + "   " + easDij.get(n));
                    this.displayRec(n,1,1);
                }
                assert easBF.get(n).equals(easDij.get(n));
            }

        } else {
            // propagate and retrieve the results
            Dijkstra dij = new Dijkstra(ancestorGraph);
            earliestAppearances = dij.getEarliestAppearances();
            predecessors = dij.labelsPred;
        }

        // extract results as more general ground object (the representation here is slightly different)
        addableActs = new IRSet<>(core.store.getIntRep(GAction.class));
        fluentsEAs = new IR2IntMap<>(core.store.getIntRep(Fluent.class));
        for(Node n : earliestAppearances.keys()) {
            if (n instanceof RAct) {
                addableActs.add(((RAct) n).getAct());
            } else if(n instanceof TempFluent.SVFluent) {
                fluentsEAs.put(((TempFluent.SVFluent) n).fluent, earliestAppearances.get(n));
            }
        }

        if(dbgLvlDij >= 2 && ancestorGraph.isPresent()) {
            for(Node n : earliestAppearances.keys()) {
                if(!(n instanceof FactAction))
                    assert ancestorGraph.get().earliestAppearances.containsKey(n);
            }
        }

        // if this was the first propagation, we recreate a core graph containing only possible nodes
        if(!ancestorGraph.isPresent()) {
            List<RAct> feasibles = earliestAppearances.keySet().stream()
                    .filter(n -> n instanceof RAct)
                    .map(n -> (RAct) n)
                    .collect(Collectors.toList());
            DepGraphCore prevCore = core;
            core = new DepGraphCore(feasibles, core.store);
            if(dbgLvl >= 1) System.out.println("Shrank core graph to: "+core.getDefaultEarliestApprearances().size()
                    +" nodes. (Initially: "+prevCore.getDefaultEarliestApprearances().size()+")");
            if(APlanner.debugging) {
                String tmpDir = System.getProperty("java.io.tmpdir");
                String outFile = tmpDir + "/ground-instances.txt";
                System.out.println("Writing all ground action instances to: "+outFile);
                try {
                    PrintWriter pw = new PrintWriter(outFile, "UTF-8");
                    feasibles.stream().map(f -> f.act).collect(Collectors.toSet()).forEach(a -> pw.println(a.toString()));
                    pw.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }

        if(dbgLvl >= 2) printActions();

        return earliestAppearances;
    }

    /** Recursively display a nodes and its incoming edges. **/
    private void displayRec(Node n, int depth, int maxDepth) {
        if(depth > maxDepth)
            return;
        String baseSpace = depth == 1 ? " " : (depth == 2 ? "  " : (depth==3 ? "    " : (depth==4 ? "     " :"  to deep")));
        System.out.print(baseSpace+(earliestAppearances.containsKey(n) ? "["+earliestAppearances.get(n)+"] " : "[--] "));
        System.out.println(baseSpace+n);<commit_msg>[planning] When debugging, display information about the number of ground actions<commit_after>package fape.core.planning.heuristics.temporal;

import fape.Planning;
import fape.core.planning.grounding.Fluent;
import fape.core.planning.grounding.GAction;
import fape.core.planning.planner.APlanner;
import fape.core.planning.planner.PlannerFactory;
import fape.util.IteratorConcat;
import fr.laas.fape.structures.DijkstraQueue;
import fr.laas.fape.structures.IR2IntMap;
import fr.laas.fape.structures.IRSet;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;

public class StateDepGraph implements DependencyGraph {

    static final int dbgLvl = 0;
    static final int dbgLvlDij = 0;

    /** Edges and nodes common to all graphs **/
    public DepGraphCore core;

    /** Planner by which this graph is used */
    public final APlanner planner;

    /** Timed initial litterals **/
    public final FactAction facts;

    /** Timed initial literals as a list of edges **/
    List<MinEdge> initMinEdges = new ArrayList<>();
    /** The previous edges indexed by their target fluent. **/
    Map<TempFluent.DGFluent, List<MinEdge>> initFluents = new HashMap<>();

    /** maximum delay of all edges of the graph (i.e. both egdes in the core and those from timed initial literals) **/
    int dmax;

    /** Associates all possible nodes to their earliest appearance (populated after propagation) **/
    IR2IntMap<Node> earliestAppearances = null;

    /** All GActions that be added to the plan (populated after propagation) **/
    IRSet<GAction> addableActs = null;

    /** Earliest appearance of all achievable fluents (populated after propagation) **/
    IR2IntMap<Fluent> fluentsEAs = null;

    /** Associates any possible node to its predecessor (i.e. the possible that gave it its current earliest appearance time).
     * It is currently only used and set by the dijkstra propagator. **/
    private IR2IntMap<Node> predecessors = null;

    public StateDepGraph(DepGraphCore core, List<TempFluent> initFacts, APlanner planner) {
        this.core = core;
        this.planner = planner;

        this.facts = core.store.getFactAction(initFacts);
        dmax = core.dmax;

        for(TempFluent tf : facts.getEffects()) {
            MinEdge e = new MinEdge(facts, tf.fluent, tf.getTime());
            initMinEdges.add(e);
            initFluents.putIfAbsent(tf.fluent, new ArrayList<>());
            initFluents.get(tf.fluent).add(e);
            dmax = Math.max(dmax, e.delay);
        }
    }

    /** Debug method that prints all possible GAction with their earliest appearance time **/
    private void printActions() {
        // complete action: show start
        System.out.println("\nactions: " +
                earliestAppearances.entrySet().stream()
                        .sorted((e1, e2) -> e1.getValue().compareTo(e2.getValue()))
                        .filter(n -> n.getKey() instanceof RAct)
                        .filter(n -> ((RAct) n.getKey()).tp.toString().equals("ContainerStart"))
                        .map(a -> "\n  [" + a.getValue() + "] " + ((RAct) a.getKey()).act)
                        .collect(Collectors.toList()));
    }

    @Override
    public Iterator<MaxEdge> inEdgesIt(ActionNode n) {
        if(n != facts)
            return core.inEdgesIt(n);
        else
            return Collections.emptyIterator(); // fact action has no incoming edges
    }

    @Override
    public Iterator<MinEdge> outEdgesIt(ActionNode n) {
        if(n != facts)
            return core.outEdgesIt(n);
        else
            return initMinEdges.iterator();

    }

    @Override
    public Iterator<MinEdge> inEdgesIt(TempFluent.DGFluent f) {
        if(initFluents.containsKey(f))
            return new IteratorConcat<>(core.inEdgesIt(f), initFluents.get(f).iterator());
        else
            return core.inEdgesIt(f);
    }

    @Override
    public Iterator<MaxEdge> outEdgesIt(TempFluent.DGFluent f) {
        return core.outEdgesIt(f); // no such edge can be added by a fact action
    }


    public IR2IntMap<Node> propagate(Optional<StateDepGraph> ancestorGraph) {

        if(dbgLvlDij > 3) {
            // used when debugging to make sure bellman ford and dijkstra yield the same results
            Propagator p = new BellmanFord(ancestorGraph);
            IR2IntMap<Node> easBF = p.getEarliestAppearances();

            Dijkstra dij = new Dijkstra(ancestorGraph);
            IR2IntMap<Node> easDij = dij.getEarliestAppearances();
            earliestAppearances = easDij;
            predecessors = dij.labelsPred;

            for(Node n : easBF.keys()) {
                assert easDij.containsKey(n);
            }
            for(Node n : easDij.keys()) {
                if(!easBF.containsKey(n))
                    dij.display(n);
                assert easBF.containsKey(n);
                if(!easBF.get(n).equals(easDij.get(n))) {
                    System.out.println(easBF.get(n) + "   " + easDij.get(n));
                    this.displayRec(n,1,1);
                }
                assert easBF.get(n).equals(easDij.get(n));
            }

        } else {
            // propagate and retrieve the results
            Dijkstra dij = new Dijkstra(ancestorGraph);
            earliestAppearances = dij.getEarliestAppearances();
            predecessors = dij.labelsPred;
        }

        // extract results as more general ground object (the representation here is slightly different)
        addableActs = new IRSet<>(core.store.getIntRep(GAction.class));
        fluentsEAs = new IR2IntMap<>(core.store.getIntRep(Fluent.class));
        for(Node n : earliestAppearances.keys()) {
            if (n instanceof RAct) {
                addableActs.add(((RAct) n).getAct());
            } else if(n instanceof TempFluent.SVFluent) {
                fluentsEAs.put(((TempFluent.SVFluent) n).fluent, earliestAppearances.get(n));
            }
        }

        if(dbgLvlDij >= 2 && ancestorGraph.isPresent()) {
            for(Node n : earliestAppearances.keys()) {
                if(!(n instanceof FactAction))
                    assert ancestorGraph.get().earliestAppearances.containsKey(n);
            }
        }

        // if this was the first propagation, we recreate a core graph containing only possible nodes
        if(!ancestorGraph.isPresent()) {
            List<RAct> feasibles = earliestAppearances.keySet().stream()
                    .filter(n -> n instanceof RAct)
                    .map(n -> (RAct) n)
                    .collect(Collectors.toList());
            DepGraphCore prevCore = core;
            core = new DepGraphCore(feasibles, core.store);
            if(dbgLvl >= 1) System.out.println("Shrank core graph to: "+core.getDefaultEarliestApprearances().size()
                    +" nodes. (Initially: "+prevCore.getDefaultEarliestApprearances().size()+")");
            if(APlanner.debugging) {
                System.out.println(String.format("Initially %d ground actions. Reachability analysis reduced them to %d.",
                        prevCore.getDefaultEarliestApprearances().keySet().stream()
                                .filter(node -> node instanceof RAct)
                                .map(ract -> ((RAct) ract).act)
                                .collect(Collectors.toSet())
                                .size(),
                        core.getDefaultEarliestApprearances().keySet().stream()
                                .filter(node -> node instanceof RAct)
                                .map(ract -> ((RAct) ract).act)
                                .collect(Collectors.toSet())
                                .size()
                ));
                String tmpDir = System.getProperty("java.io.tmpdir");
                String outFile = tmpDir + "/ground-instances.txt";
                System.out.println("Writing all ground action instances to: "+outFile);
                try {
                    PrintWriter pw = new PrintWriter(outFile, "UTF-8");
                    feasibles.stream().map(f -> f.act).collect(Collectors.toSet()).forEach(a -> pw.println(a.toString()));
                    pw.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }

        if(dbgLvl >= 2) printActions();

        return earliestAppearances;
    }

    /** Recursively display a nodes and its incoming edges. **/
    private void displayRec(Node n, int depth, int maxDepth) {
        if(depth > maxDepth)
            return;
        String baseSpace = depth == 1 ? " " : (depth == 2 ? "  " : (depth==3 ? "    " : (depth==4 ? "     " :"  to deep")));
        System.out.print(baseSpace+(earliestAppearances.containsKey(n) ? "["+earliestAppearances.get(n)+"] " : "[--] "));
        System.out.println(baseSpace+n);
{'fraction_non_alphanumeric': 0.11571361612374033, 'fraction_numerical': 0.0029294586360440592, 'mean_word_length': 2.1325013763993392, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 79, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5454981', 'n_tokens_mistral': 5060, 'n_tokens_neox': 4840, 'n_words': 1135}