workcraft/workcraft

View on GitHub
workcraft/CpogPlugin/src/org/workcraft/plugins/cpog/tasks/ScencoSolver.java

Summary

Maintainability
A
3 hrs
Test Coverage
package org.workcraft.plugins.cpog.tasks;

import org.workcraft.dom.visual.VisualTransformableNode;
import org.workcraft.formula.BooleanFormula;
import org.workcraft.formula.jj.ParseException;
import org.workcraft.plugins.circuit.CircuitSettings;
import org.workcraft.plugins.circuit.utils.VerilogUtils;
import org.workcraft.plugins.circuit.verilog.VerilogModule;
import org.workcraft.plugins.cpog.*;
import org.workcraft.plugins.cpog.EncoderSettings.GenerationMode;
import org.workcraft.plugins.cpog.encoding.Encoding;
import org.workcraft.plugins.cpog.tools.CpogParsingTool;
import org.workcraft.utils.ExecutableUtils;
import org.workcraft.utils.FileUtils;
import org.workcraft.utils.Hierarchy;
import org.workcraft.utils.WorkspaceUtils;
import org.workcraft.workspace.WorkspaceEntry;

import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;

public class ScencoSolver {

    public static final String ACCESS_SCENCO_ERROR = "SCENCO error";
    public static final String MSG_NOT_ENOUGH_SCENARIOS = "Not enough scenarios. Select at least two scenarios.";
    public static final String MSG_TOO_MANY_SCENARIOS = "Too many scenarios selected.";
    public static final String MSG_SELECTION_MODE_UNDEFINED = "Selection mode undefined.";
    public static final String MSG_SAT_BASED_ERROR = "SAT-Based encoding cannot handle the graphs selected";
    public static final String MSG_GATE_LIB_NOT_PRESENT = "Gate library not present. Please insert this " +
                                                          "(genlib format) inside ABC folder.";
    public static final String MSG_ABC_NOT_PRESENT = "Find out more information on " +
                                                     "\"http://www.eecs.berkeley.edu/~alanmi/abc/\" or try to " +
                                                     "set Abc path in Workcraft settings.";
    private static final String VERILOG_TMP_NAME = "micro.v";

    private final EncoderSettings settings;
    private final WorkspaceEntry we;
    private final ScencoExecutionSupport cpogBuilder;
    private VisualCpog cpog;

    // SETTING PARAMETERS FOR CALLING SCENCO
    private String scencoCommand;
    private String espressoCommand;
    private String abcTool;
    private String gatesLibrary;
    private String verbose = "";
    private String genMode = "";
    private String modBitFlag = "";
    private String modBit = "";
    private String numSol = "";
    private String customFlag = "";
    private String customPath = "";
    private String effort = "";
    private String espressoFlag = "";
    private String abcFlag = "";
    private String gateLibFlag = "";
    private String cpogSize = "";
    private String disableFunction = "";
    private String oldSynt = "";
    private String verilogFlag = "";

    private int v;
    private int a;
    private int n;
    private int m;
    private char[][][] constraints;
    private ArrayList<VisualTransformableNode> scenarios;
    private HashMap<String, Integer> events;
    private ArrayList<Point2D> positions;
    private ArrayList<Integer> count;
    private File directory;
    private File verilogFile;
    private HashMap<String, BooleanFormula> formulaeName;
    private String[] optEnc;
    private int freeVariables;
    private int pr;
    private Variable[] vars;
    private VisualVariable[] predicatives;

    public ScencoSolver(EncoderSettings settings, WorkspaceEntry we) {
        this.settings = settings;
        this.we = we;
        this.cpogBuilder = new ScencoExecutionSupport();
    }

    public ArrayList<String> getScencoArguments() {
        cpog = WorkspaceUtils.getAs(we, VisualCpog.class);
        scenarios = CpogParsingTool.getScenarios(cpog);
        we.captureMemento();

        cpogBuilder.resetVars(verbose, genMode, numSol, customFlag, customPath, effort,
                                espressoFlag, abcFlag, gateLibFlag, cpogSize, disableFunction, oldSynt);

        events = new HashMap<>();
        positions = new ArrayList<>();
        count = new ArrayList<>();

        // Scenario contains single graphs compose CPOG
        m = scenarios.size();
        // scan scenarios
        n = cpogBuilder.scanScenarios(m, scenarios, events, positions, count);

        // construct constraints
        constraints = new char[m][n][n];
        int[][] graph = new int[n][n];
        ArrayList<String> check = cpogBuilder.constructConstraints(constraints, graph, m, n,
                scenarios, events, positions, count);
        if (check.get(0).contains("ERROR")) {
            return check;
        }

        // group similar constraints
        optEnc = new String[m];
        HashMap<String, Integer> task = new HashMap<>();
        formulaeName = new HashMap<>();
        cpogBuilder.groupConstraints(n, m, constraints, task);

        char[][] matrix = new char[m][task.size()];
        String[] instance = new String[m];
        for (String s : task.keySet()) {
            for (int i = 0; i < m; i++) matrix[i][task.get(s)] = s.charAt(i);
        }

        for (int i = 0; i < m; i++) instance[i] = new String(matrix[i]);

        // GET PREDICATES FROM WORKCRAFT ENVIRONMENT
        predicatives = new VisualVariable[n];
        pr = 0;
        for (VisualVariable variable : Hierarchy.getChildrenOfType(cpog.getRoot(), VisualVariable.class)) {
            predicatives[pr++] = variable;
        }

        if (settings.getGenMode() != GenerationMode.OLD_SYNT) {
            freeVariables = settings.getBits();
            vars = new Variable[freeVariables + pr];
            for (int i = 0; i < freeVariables; i++) vars[i] = cpog.createVisualVariable().getReferencedComponent();
            for (int i = 0; i < pr; i++) vars[freeVariables + i] = predicatives[i].getReferencedComponent();
        }

        String prefix = FileUtils.getTempPrefix(we.getTitle());
        directory = FileUtils.createTempDirectory(prefix);
        File scenarioFile = new File(directory, "scenarios.cpog");
        File encodingFile = new File(directory, "custom.enc");
        File resultDirectory = new File(directory, "result");
        verilogFile = new File(directory, VERILOG_TMP_NAME);
        resultDirectory.mkdir();

        ArrayList<String> args = new ArrayList<>();
        if ((cpogBuilder.writeCpogIntoFile(m, scenarios, scenarioFile, encodingFile, settings)) != 0) {
            FileUtils.deleteOnExitRecursively(directory);
            args.add("ERROR");
            args.add("Error on writing scenario file.");
            args.add("Workcraft error");
            return args;
        }

        instantiateParameters();

        if (settings.isAbcFlag()) {
            File f = new File(abcTool);
            if (!f.exists() || f.isDirectory()) {
                FileUtils.deleteOnExitRecursively(directory);
                args.add("ERROR");
                args.add(MSG_ABC_NOT_PRESENT);
                args.add(ACCESS_SCENCO_ERROR);
                return args;
            } else {
                abcFlag = "-a";
                gateLibFlag = "-lib";
                f = new File(gatesLibrary);
                if (!f.exists() || f.isDirectory()) {
                    FileUtils.deleteOnExitRecursively(directory);
                    args.add("ERROR");
                    args.add(MSG_GATE_LIB_NOT_PRESENT);
                    args.add(ACCESS_SCENCO_ERROR);
                    return args;
                } else {
                    if (!settings.isCpogSize()) {
                        verilogFlag = "-ver";
                    }
                }
            }
        } else {
            abcFlag = "";
            abcTool = "";
            gateLibFlag = "";
            gatesLibrary = "";
        }

        // SAT-based encoding
        if (settings.getGenMode() == GenerationMode.SCENCO) {
            Encoding solution = null;

            solution = cpogBuilder.satBasedRun(pr, vars, instance, settings.getCircuitSize());
            if (solution == null) {
                FileUtils.deleteOnExitRecursively(directory);
                we.cancelMemento();
                args.add("ERROR");
                args.add(MSG_SAT_BASED_ERROR);
                args.add(ACCESS_SCENCO_ERROR);
                return args;
            }

            boolean[][] encoding = solution.getCode();
            PrintStream output = null;
            try {
                output = new PrintStream(encodingFile, StandardCharsets.UTF_8);
            } catch (IOException e) {
                e.printStackTrace();
            }

            for (int i = 0; i < m; i++) {
                for (int j = 0; j < settings.getBits(); j++) {
                    char c = encoding[i][j] ? '1' : '0';
                    output.print(c);
                }
                output.println();
            }
            output.println(settings.getBits());
            output.close();
        }

        // FILL IN PARAMETERS FOR CALLING PROGRAMER PROPERLY
        if (settings.isCpogSize()) cpogSize = "-cs";
        if (settings.isCostFunc()) disableFunction = "-d";
        if (settings.isVerboseMode()) verbose = "-v";
        if (settings.isEffort()) effort = "all";
        else effort = "min";
        if (settings.isCustomEncMode()) {
            customFlag = "-set";
            customPath = encodingFile.getAbsolutePath();
        }
        switch (settings.getGenMode()) {
        case OPTIMAL_ENCODING:
            genMode = "-top";
            numSol = String.valueOf(settings.getSolutionNumber());
            break;
        case RECURSIVE:
            if (settings.isCustomEncMode()) {
                modBitFlag = "-bit";
                modBit = String.valueOf(settings.getBits());
            }
            break;
        case RANDOM:
            genMode = "-r";
            if (settings.isCustomEncMode()) {
                customFlag = "-set";
                customPath = encodingFile.getAbsolutePath();
                modBitFlag = "-bit";
                modBit = String.valueOf(settings.getBits());
            }
            numSol = String.valueOf(settings.getSolutionNumber());
            break;
        case SCENCO:
            customFlag = "-set";
            genMode = "-top";
            numSol = "1";
            break;
        case OLD_SYNT:
            customFlag = "-set";
            customPath = encodingFile.getAbsolutePath();
            oldSynt = "-old";
            genMode = "-top";
            numSol = "1";
            break;
        case SEQUENTIAL:
            customFlag = "-set";
            customPath = encodingFile.getAbsolutePath();
            genMode = "-top";
            numSol = "1";
            break;
        default:
            FileUtils.deleteOnExitRecursively(directory);
            args.add("ERROR");
            args.add(MSG_SELECTION_MODE_UNDEFINED);
            args.add(ACCESS_SCENCO_ERROR);
            return args;
        }

        //Adding arguments to list
        scencoCommand = ExecutableUtils.getAbsoluteCommandPath(CpogSettings.getScencoCommand());
        if (scencoCommand != null && !scencoCommand.isEmpty()) args.add(scencoCommand);
        if (scenarioFile.getAbsolutePath() != null && !scenarioFile.getAbsolutePath().isEmpty()) args.add(scenarioFile.getAbsolutePath());
        args.add("-m");
        if (effort != null && !effort.isEmpty()) args.add(effort);
        if (genMode != null && !genMode.isEmpty()) args.add(genMode);
        if (numSol != null && !numSol.isEmpty()) args.add(numSol);
        if (customFlag != null && !customFlag.isEmpty()) args.add(customFlag);
        if (customPath != null && !customPath.isEmpty()) args.add(customPath);
        if (verbose != null && !verbose.isEmpty()) args.add(verbose);
        if (cpogSize != null && !cpogSize.isEmpty()) args.add(cpogSize);
        if (disableFunction != null && !disableFunction.isEmpty()) args.add(disableFunction);
        if (oldSynt != null && !oldSynt.isEmpty()) args.add(oldSynt);
        if (espressoFlag != null && !espressoFlag.isEmpty()) args.add(espressoFlag);
        if (espressoCommand != null && !espressoCommand.isEmpty()) args.add(espressoCommand);
        if (abcFlag != null && !abcFlag.isEmpty()) args.add(abcFlag);
        if (abcTool != null && !abcTool.isEmpty()) args.add(abcTool);
        if (gateLibFlag != null && !gateLibFlag.isEmpty()) args.add(gateLibFlag);
        if (gatesLibrary != null && !gatesLibrary.isEmpty()) args.add(gatesLibrary);
        args.add("-res");
        if ((resultDirectory.getAbsolutePath() != null) && !resultDirectory.getAbsolutePath().isEmpty()) args.add(resultDirectory.getAbsolutePath());
        if (modBitFlag != null && !modBitFlag.isEmpty()) args.add(modBitFlag);
        if (modBit != null && !modBit.isEmpty()) args.add(modBit);
        if (verilogFlag != null && !verilogFlag.isEmpty()) {
            args.add(verilogFlag);
            args.add(verilogFile.getAbsolutePath());
        }

        // final return
        return args;
    }

    public void handleResult(String[] outputLines, String resultDirectoryPath) {
        String[] optFormulaeVertices = new String[n * n];
        String[] optVertices = new String[n];
        String[] optSources = new String[n * n];
        String[] optDests = new String[n * n];
        String[] optFormulaeArcs = new String[n * n];
        String[] arcNames = new String[n * n];

        try {
            for (int i = 0; i < outputLines.length; i++) {
                if (settings.isVerboseMode()) {
                    System.out.println(outputLines[i]);
                }

                // Read Optimal Encoding
                if (outputLines[i].contains("MIN: ")) {

                    StringTokenizer string = new StringTokenizer(outputLines[i], " ");
                    int j = 0;
                    string.nextElement();
                    while (j < m) {
                        optEnc[j++] = (String) string.nextElement();
                    }
                }

                // Read Optimal Formulae
                if (outputLines[i].contains(".start_formulae")) {
                    i++;
                    v = 0;
                    a = 0;
                    while (!outputLines[i].contains(".end_formulae")) {
                        if (settings.isVerboseMode()) {
                            System.out.println(outputLines[i]);
                        }
                        StringTokenizer st2 = new StringTokenizer(outputLines[i], ",");
                        String el = (String) st2.nextElement();
                        if ("V".equals(el)) { //formula of a vertex
                            String vertexName = (String) st2.nextElement();
                            if (!settings.GO_SIGNAL.equals(vertexName) && !settings.DONE_SIGNAL.equals(vertexName)) {
                                optVertices[v] = vertexName;
                                st2.nextElement();
                                optFormulaeVertices[v++] = (String) st2.nextElement();
                            }
                        } else {
                            optSources[a] = (String) st2.nextElement();
                            optDests[a] = (String) st2.nextElement();
                            arcNames[a] = optSources[a] + "->" + optDests[a];
                            st2.nextElement();
                            optFormulaeArcs[a++] = (String) st2.nextElement();
                        }
                        i++;
                    }

                }

                // Read statistics
                if (outputLines[i].contains(".statistics")) {
                    i++;
                    while (!outputLines[i].contains(".end_statistics")) {
                        System.out.println(outputLines[i]);
                        i++;
                    }
                }
            }

            if (settings.getGenMode() != GenerationMode.SCENCO) {
                freeVariables = optEnc[0].length();
            } else {
                freeVariables = settings.getBits();
            }

            // Print controller
            cpogBuilder.printController(m, resultDirectoryPath, optEnc);

            Encoding solution = null;

            // READ OUTPUT OF SCENCO INSTANTIATING THE OPTIMAL ENCODING SOLUTION
            // AND CONNECTING IT TO EACH VISUAL VERTEX EXPLOITING A MAP
            System.out.println("Op-code selected for graphs:");
            for (int i = 0; i < m; i++) {
                optEnc[i] = optEnc[i].replace('-', 'X');
                String name;
                if (scenarios.get(i).getLabel().isEmpty()) {
                    name = "CPOG " + i;
                } else {
                    name = scenarios.get(i).getLabel();
                }
                System.out.println(name + ": " + optEnc[i]);
            }

            solution = new Encoding(null, null);
            BooleanFormula[] formulas = new BooleanFormula[v + a];

            if (settings.getGenMode() == GenerationMode.OLD_SYNT) {
                vars = new Variable[freeVariables + pr];
                for (int i = 0; i < freeVariables; i++) vars[i] = cpog.createVisualVariable().getReferencedComponent();
                for (int i = 0; i < pr; i++) vars[freeVariables + i] = predicatives[i].getReferencedComponent();
            }

            // Set optimal formulae to graphs
            try {
                cpogBuilder.connectFormulaeToVisualVertex(v, a, vars, formulaeName, optFormulaeVertices,
                        optVertices, optFormulaeArcs, arcNames);
            } catch (ParseException e) {
                e.printStackTrace();
            }

            //Set formulas
            solution.setFormulas(formulas);

            // Set optimal encoding to graphs
            boolean[][] optEncoding = new boolean[m][];
            for (int i = 0; i < m; i++) {
                optEncoding[i] = new boolean[freeVariables + pr];
                for (int j = 0; j < freeVariables; j++) {
                    if (optEnc[i].charAt(j) == '0' || optEnc[i].charAt(j) == '-') optEncoding[i][j] = false;
                    else    optEncoding[i][j] = true;
                }
                for (int j = freeVariables; j < freeVariables + pr; j++) {
                    optEncoding[i][j] = false;
                }

            }
            solution.setCode(optEncoding);

            boolean[][] encoding = solution.getCode();

            // CREATE RESULT PART
            VisualScenario resultCpog = cpog.createVisualScenario();
            resultCpog.setLabel("Composition");
            VisualVertex[] vertices = new VisualVertex[n];

            //INSTANTIATING THE ENCODING INTO GRAPHS IN WORKCRAFT
            cpogBuilder.instantiateEncoding(m, freeVariables, scenarios, vars, encoding, pr,
                    events, vertices, cpog, resultCpog, positions, count, formulaeName);

            // Building CPOG
            cpogBuilder.buildCpog(n, m, constraints, cpog, vertices, formulaeName);

            we.saveMemento();
        } finally {
            // clean up temporary files
            FileUtils.deleteOnExitRecursively(directory);
        }
    }

    private void instantiateParameters() {
        scencoCommand = ExecutableUtils.getAbsoluteCommandPath(CpogSettings.getScencoCommand());
        espressoCommand = ExecutableUtils.getAbsoluteCommandPath(CpogSettings.getEspressoCommand());
        abcTool = CpogSettings.getAbcTool();
        gatesLibrary = ExecutableUtils.getAbsoluteCommandPath(CircuitSettings.getGateLibrary());
        espressoFlag = "-e";
    }

    public File getDirectory() {
        return directory;
    }

    public Boolean isVerilog() {
        return !verilogFlag.isEmpty();
    }

    public VerilogModule getVerilogModule() {
        return VerilogUtils.importTopVerilogModule(verilogFile);
    }

}