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

jp.kobe_u.sugar.SugarMain Maven / Gradle / Ivy

Go to download

This is a JSR331 interface for the open source Java constraint programming library "Sugar" v. 2.1.3

The newest version!
package jp.kobe_u.sugar;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.zip.GZIPInputStream;

import jp.kobe_u.sugar.converter.Converter;
import jp.kobe_u.sugar.csp.BooleanVariable;
import jp.kobe_u.sugar.csp.CSP;
import jp.kobe_u.sugar.csp.CSP.Objective;
import jp.kobe_u.sugar.csp.IntegerDomain;
import jp.kobe_u.sugar.csp.IntegerDomainDiet;
import jp.kobe_u.sugar.csp.IntegerDomainOld;
import jp.kobe_u.sugar.csp.IntegerVariable;
import jp.kobe_u.sugar.encoder.Encoder;
import jp.kobe_u.sugar.encoder.Problem;
import jp.kobe_u.sugar.expression.Expression;
import jp.kobe_u.sugar.expression.Parser;
import jp.kobe_u.sugar.expression.Sequence;
import jp.kobe_u.sugar.hook.ConverterHook;

/**
 * SugarMain main class.
 * @author Naoyuki Tamura ([email protected])
 */
public class SugarMain {
    CSP csp = null;
    static boolean prolog = false;
    static boolean maxCSP = false;
    static boolean weightedCSP = false;
    static boolean competition = false;
    static boolean incremental = false;
    static boolean propagation = true;
    static boolean simplify_clauses = true;
    public static int debug = 0;

    private List toMaxCSP(List expressions0) throws SugarException {
        List expressions = new ArrayList();
        List sum = new ArrayList();
        sum.add(Expression.ADD);
        int n = 0;
        for (Expression x: expressions0) {
            if (x.isSequence(Expression.DOMAIN_DEFINITION)
                || x.isSequence(Expression.INT_DEFINITION)
                || x.isSequence(Expression.BOOL_DEFINITION)
                || x.isSequence(Expression.PREDICATE_DEFINITION)
                || x.isSequence(Expression.RELATION_DEFINITION)) {
                expressions.add(x);
            } else if (x.isSequence(Expression.OBJECTIVE_DEFINITION)) {
                throw new SugarException("Illegal " + x);
            } else {
                // (int _Cn 0 1)
                // (or (ge _Cn 1) constraint)
                Expression c = Expression.create("_C" + n);
                expressions.add(Expression.create(
                        Expression.INT_DEFINITION,
                        c,
                        Expression.ZERO,
                        Expression.ONE));
                x = (c.ge(Expression.ONE)).or(x);
                expressions.add(x);
                sum.add(c);
                n++;
            }
        }
        // (int _COST 0 n)
        // (ge _COST (add _C1 ... _Cn))
        // (objective minimize _COST)
        Expression cost = Expression.create("_COST");
        expressions.add(Expression.create(
                Expression.INT_DEFINITION,
                cost,
                Expression.ZERO,
                Expression.create(n)));
        expressions.add(cost.ge(Expression.create(sum)));
        expressions.add(Expression.create(
                Expression.OBJECTIVE_DEFINITION,
                Expression.MINIMIZE,
                cost));
        Logger.info("MAX CSP: " + n + " constraints");
        return expressions;
    }
    
    private List toWeightedCSP(List expressions0) throws SugarException {
        List expressions = new ArrayList();
        List sum = new ArrayList();
        sum.add(Expression.ADD);
        int n = 0;
        int maxWeight = 0;
        for (Expression x: expressions0) {
            if (x.isSequence(Expression.OBJECTIVE_DEFINITION)) {
                throw new SugarException("Illegal " + x);
            } else if (x.isSequence(Expression.WEIGHTED)) {
                Sequence seq = (Sequence)x;
                if (! seq.matches("WI.")) {
                    throw new SugarException("Bad definition " + seq);
                }
                int weight = seq.get(1).integerValue();
                x = seq.get(2);
                // (int _Cn 0 1)
                // (or (ge _Cn 1) constraint)
                Expression c = Expression.create("_C" + n);
                expressions.add(Expression.create(
                        Expression.INT_DEFINITION,
                        c,
                        Expression.ZERO,
                        Expression.ONE));
                x = (c.ge(Expression.ONE)).or(x);
                expressions.add(x);
                sum.add(c.mul(weight));
                maxWeight += weight;
                n++;
            } else {
                expressions.add(x);
            }
        }
        // (int _COST 0 maxWeight)
        // (ge _COST (add (* _C1 W1) ... (* _Cn Wn)))
        // (objective minimize _COST)
        Expression cost = Expression.create("_COST");
        expressions.add(Expression.create(
                Expression.INT_DEFINITION,
                cost,
                Expression.ZERO,
                Expression.create(maxWeight)));
        expressions.add(cost.ge(Expression.create(sum)));
        expressions.add(Expression.create(
                Expression.OBJECTIVE_DEFINITION,
                Expression.MINIMIZE,
                cost));
        Logger.info("Weighted CSP: " + n + " constraints");
        return expressions;
    }
    
    private List toGCNF(List expressions0) throws SugarException {
        List expressions = new ArrayList();
        int n = 0; 
        int label = 0;
        for (Expression x: expressions0) {
            if (x.isSequence(Expression.DOMAIN_DEFINITION)
                || x.isSequence(Expression.INT_DEFINITION)
                || x.isSequence(Expression.BOOL_DEFINITION)
                || x.isSequence(Expression.PREDICATE_DEFINITION)
                || x.isSequence(Expression.RELATION_DEFINITION)) {
                expressions.add(x);
            } else if (x.isSequence(Expression.OBJECTIVE_DEFINITION)) {
                throw new SugarException("Illegal " + x);
            } else {
                // (or (label 1) constraint)
                label++;
                x = Expression.create(Expression.LABEL, Expression.create(label)).or(x);
                expressions.add(x);
                n++;
            }
        }
        int topWeight = label;
        expressions.add(Expression.create(
                Expression.GROUPS_DEFINITION,
                Expression.create(label),
                Expression.create(topWeight)));
        Logger.info("Group CSP: " + n + " constraints");
        return expressions;
    }
    

    public List parse(String cspFileName) throws SugarException, IOException {
        // Parse
        Logger.fine("Parsing " + cspFileName);
        InputStream in;
        if (cspFileName.endsWith(".gz")) {
            in = new GZIPInputStream(new FileInputStream(cspFileName));
        } else {
            in = new FileInputStream(cspFileName);
        }
        BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
        Parser parser = new Parser(reader, prolog);
        List expressions = parser.parse();
        reader.close();
        reader = null;
        in.close();
        in = null;
        parser = null;
        Runtime.getRuntime().gc();
        Logger.info("parsed " + expressions.size() + " expressions");
        if (debug > 0) {
            for (Expression x : expressions)
                System.out.println("c " + x);
        }
        Logger.status();
        // GCNF or MaxCSP or WeightedCSP translation 
        if (Problem.GCNF || Problem.GWCNF) {
            expressions = toGCNF(expressions);
        } else if (maxCSP) {
            expressions = toMaxCSP(expressions);
        } else if (weightedCSP) {
            expressions = toWeightedCSP(expressions);
        }
        return expressions;
    }
    
    public void translate(String cspFileName) throws SugarException, IOException {
        List expressions = parse(cspFileName);
        // Conversion
        Logger.fine("Converting to clausal form CSP");
        csp = new CSP();
        Converter converter = new Converter(csp);
        Converter.INCREMENTAL_PROPAGATION = propagation;
        converter.convert(expressions);
        converter = null;
        expressions = null;
        Expression.clear();
        Runtime.getRuntime().gc();
        Logger.fine("CSP : " + csp.summary());
        Logger.status();
        if (propagation) {
            // Propagation
            Logger.fine("Propagation in CSP");
            csp.propagate();
            Logger.fine("CSP : " + csp.summary());
            if (debug > 0) {
                csp.output(System.out, "c ");
            }
            Logger.status();
        }
        if (csp.isUnsatisfiable()) {
            Logger.info("CSP is unsatisfiable after propagation");
            Logger.println("s UNSATISFIABLE");
            return;
        }
        if (simplify_clauses) {
            // Simplification
            Logger.fine("Simplifing CSP clauses by introducing new Boolean variables");
            csp.simplify();
            Logger.info("CSP : " + csp.summary());
            if (debug > 0) {
                csp.output(System.out, "c ");
            }
            Logger.status();
        }
        Runtime.getRuntime().gc();
    }
    
    public void encode(String cspFileName, String satFileName, String mapFileName)
    throws SugarException, IOException {
        translate(cspFileName);
        if (csp.isUnsatisfiable()) {
            return;
        }
        Logger.fine("Encoding CSP to SAT : " + satFileName);
        Encoder encoder = new Encoder(csp);
        encoder.encode(satFileName);
        Logger.fine("Writing map file : " + mapFileName);
        encoder.outputMap(mapFileName);
        Logger.status();
        Logger.info("SAT : " + encoder.summary());
    }
    
    public void decode(String outFileName, String mapFileName)
    throws SugarException, IOException {
        Logger.fine("Decoding " + outFileName);
        CSP csp = new CSP();
        List objectiveVariableNames = null;
        BufferedReader rd = new BufferedReader(
                new InputStreamReader(new FileInputStream(mapFileName), "UTF-8"));
        while (true) {
            String line = rd.readLine();
            if (line == null)
                break;
            String[] s = line.split("\\s+");
            if (s[0].equals("objective")) {
                if (s[1].equals(SugarConstants.MINIMIZE)) {
                    csp.setObjective(Objective.MINIMIZE);
                } else if (s[1].equals(SugarConstants.MAXIMIZE)) {
                    csp.setObjective(Objective.MAXIMIZE);
                }
                objectiveVariableNames = new ArrayList();
                for (int i = 2; i < s.length; i++)
                    objectiveVariableNames.add(s[i]);
            } else if (s[0].equals("int")) {
                String name = s[1];
                int code = Integer.parseInt(s[2]);
                IntegerDomain domain = null;
                if (s.length == 4) {
                    int lb;
                    int ub;
                    int pos = s[3].indexOf("..");
                    if (pos < 0) {
                        lb = ub = Integer.parseInt(s[3]);
                    } else {
                        lb = Integer.parseInt(s[3].substring(0, pos));
                        ub = Integer.parseInt(s[3].substring(pos+2));
                    }
                    domain = IntegerDomain.create(lb, ub);
                } else {
                    SortedSet d = new TreeSet();
                    for (int i = 3; i < s.length; i++) {
                        int lb;
                        int ub;
                        int pos = s[i].indexOf("..");
                        if (pos < 0) {
                            lb = ub = Integer.parseInt(s[i]);
                        } else {
                            lb = Integer.parseInt(s[i].substring(0, pos));
                            ub = Integer.parseInt(s[i].substring(pos+2));
                        }
                        for (int value = lb; value <= ub; value++) {
                            d.add(value);
                        }
                    }
                    domain = IntegerDomain.create(d);
                }
                IntegerVariable v = new IntegerVariable(name, domain);
                v.setCode(code);
                csp.add(v);
            } else if (s[0].equals("bool")) {
                // TODO
                String name = s[1];
                int code = Integer.parseInt(s[2]);
                BooleanVariable v = new BooleanVariable(name);
                v.setCode(code);
                csp.add(v);
            }
        }
        rd.close();
        if (objectiveVariableNames != null) {
            List vs = new ArrayList();
            for (String name : objectiveVariableNames) {
                IntegerVariable v = csp.getIntegerVariable(name);
                if (v == null)
                    throw new SugarException("Unknown objective variable " + name);
                vs.add(v);
            }
            csp.setObjectiveVariables(vs);
        }
        Encoder encoder = new Encoder(csp);
        if (encoder.decode(outFileName)) {
            if (csp.getObjectiveVariables() == null) {
                Logger.println("s SATISFIABLE");
            } else {
                String s = "o";
                for (IntegerVariable v : csp.getObjectiveVariables()) {
                    String name = v.getName();
                    int value = v.getValue();
                    Logger.println("c OBJECTIVE " + name + " " + value);
                    s += " " + value;
                }
                Logger.println(s);
            }
            if (competition) {
                Logger.print("v");
                for (IntegerVariable v : csp.getIntegerVariables()) {
                    if (! v.isAux() && ! v.getName().startsWith("_")) {
                        Logger.print(" " + v.getValue());
                    }
                }
                Logger.println("");
            } else {
                for (IntegerVariable v : csp.getIntegerVariables()) {
                    if (! v.isAux() && ! v.getName().startsWith("_")) {
                        Logger.println("a " + v.getName() + "\t" + v.getValue());
                    }
                }
                for (BooleanVariable v : csp.getBooleanVariables()) {
                    if (! v.isAux() && ! v.getName().startsWith("_")) {
                        Logger.println("a " + v.getName() + "\t" + v.getValue());
                    }
                }
                Logger.println("a");
            }
        } else {
            Logger.println("s UNSATISFIABLE");
        }
    }

    public void outputCSP(String inputFileName, String outputFileName, String format, String outputHook)
            throws SugarException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        Logger.info("Translate CSP to " + format);
        translate(inputFileName);
        PrintWriter out = null;        
        if (outputFileName != null)
            out = new PrintWriter(new BufferedWriter(new FileWriter(outputFileName)));
        OutputInterface output;
        if (outputHook == null) {
            if (format.equals("smt"))
                output = new OutputSMT();
            else
                output = new Output();
        } else {
            Class clazz = Class.forName(outputHook);
            output = (OutputInterface)clazz.newInstance();
        }
        output.setCSP(csp);
        output.setOut(out);
        output.setFormat(format);
        output.output();
        out.close();
        Logger.status();
    }
    
    private static boolean setOption(String opt) {
        if (opt.matches("(no_)?peep(hole)?")) {
            Converter.OPT_PEEPHOLE = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?linear(ize)?")) {
            Converter.LINEARIZE = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?norm(alize_linearsum)?")) {
            Converter.NORMALIZE_LINEARSUM = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?prop(agation)?")) {
            propagation = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?simp(lify(_clauses)?)?")) {
            simplify_clauses = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?reduce(_arity)?") || opt.matches("(no_)?new_variable")) {
            Converter.REDUCE_ARITY = ! opt.startsWith("no_");
        } else if (opt.matches("arity=(\\d+)")) {
            int n = "arity=".length();
            Converter.MAX_ARITY = Integer.parseInt(opt.substring(n));
        } else if (opt.matches("(no_)?decomp(ose)?")) {
            Converter.setDecomposeAll(! opt.startsWith("no_"));
        } else if (opt.matches("(no_)?decomp(ose)?_rel(ation)?")) {
            Converter.DECOMPOSE_RELATION = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_alldiff(erent)?")) {
            Converter.DECOMPOSE_ALLDIFFERENT = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_(weightedsum|wsum)")) {
            Converter.DECOMPOSE_WEIGHTEDSUM = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_cumul(ative)?")) {
            Converter.DECOMPOSE_CUMULATIVE = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_elem(ent)?")) {
            Converter.DECOMPOSE_ELEMENT = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_disj(unctive)?")) {
            Converter.DECOMPOSE_DISJUNCTIVE = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_lex_less")) {
            Converter.DECOMPOSE_LEX_LESS = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_lex_lesseq")) {
            Converter.DECOMPOSE_LEX_LESSEQ = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_nvalue")) {
            Converter.DECOMPOSE_NVALUE = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_count")) {
            Converter.DECOMPOSE_COUNT = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_(global_cardinality|gc)")) {
            Converter.DECOMPOSE_GLOBAL_CARDINALITY = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?decomp(ose)?_(global_cardinality_with_costs|gcc)")) {
            Converter.DECOMPOSE_GLOBAL_CARDINALITY_WITH_COSTS = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?hints")) {
            Converter.HINT_ALLDIFF_PIGEON = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?hint_alldiff_pigeon") || opt.matches("(no_)?pigeon")) {
            Converter.HINT_ALLDIFF_PIGEON = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?replace(_arguments|_args)?")) {
            Converter.REPLACE_ARGUMENTS = ! opt.startsWith("no_");
        } else if (opt.matches("equiv=(\\d+)")) {
            int n = "equiv=".length();
            Converter.MAX_EQUIVMAP_SIZE = Integer.parseInt(opt.substring(n));
        } else if (opt.matches("linearsum=(\\d+)")) {
            int n = "linearsum=".length();
            Converter.MAX_LINEARSUM_SIZE = Long.parseLong(opt.substring(n));
        } else if (opt.matches("split=(\\d+)")) {
            int n = "split=".length();
            Converter.SPLITS = Integer.parseInt(opt.substring(n));
        } else if (opt.matches("(no_)?use_eq")) {
            Converter.USE_EQ = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?hold")) {
            Converter.HOLD_CONSTRAINTS = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?diet")) {
            IntegerDomain.USE_DIET_DOMAIN = ! opt.startsWith("no_");
        } else if (opt.matches("domain=(\\d+)")) {
            int n = "domain=".length();
            int size = Integer.parseInt(opt.substring(n));
            IntegerDomainOld.MAX_SET_SIZE = size;
            IntegerDomainDiet.MAX_SET_SIZE = size;
        } else if (opt.matches("(no_)?gcnf")) {
            Problem.GCNF = ! opt.startsWith("no_");
        } else if (opt.matches("(no_)?gwcnf")) {
            Problem.GWCNF = ! opt.startsWith("no_");
        } else if (opt.matches("simp_cache=(\\d+)")) {
            int n = "simp_cache=".length();
            int size = Integer.parseInt(opt.substring(n));
            if (size <= 0) {
                CSP.USE_SIMPLIFYCACHE = false;
            } else {
                CSP.USE_SIMPLIFYCACHE = true;
                CSP.MAX_SIMPLIFYCACHE_SIZE = size;
            }
        } else {
            return false;
        }
        return true;
    }
    
    public static void setDefaultOptions() {
        Converter.OPT_PEEPHOLE = true;
        Converter.LINEARIZE = true;
        Converter.NORMALIZE_LINEARSUM = true;
        propagation = true;
        simplify_clauses = true;
        Converter.REDUCE_ARITY = true;
        Converter.setDecomposeAll(true);
        Converter.DECOMPOSE_RELATION = false; // "true" has bug
        Converter.HINT_ALLDIFF_PIGEON = true;
        Converter.REPLACE_ARGUMENTS = false;
        Converter.USE_EQ = false;
        Converter.HOLD_CONSTRAINTS = false;
        IntegerDomain.USE_DIET_DOMAIN = false;
        Problem.GCNF = false;
        Problem.GWCNF = false;
        CSP.USE_SIMPLIFYCACHE = true;
        CSP.MAX_SIMPLIFYCACHE_SIZE = 1000;
    }
    
    public static void init() {
        setDefaultOptions();
        Converter.hooks = null;
    }
    
    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            setDefaultOptions();
            String outputHook = null;
            String option = "";
            int i = 0;
            while (i < args.length) {
                if (args[i].equals("-prolog")) {
                    prolog = true;
                } else if (args[i].equals("-max")) {
                    maxCSP = true;
                } else if (args[i].equals("-weighted")) {
                    weightedCSP = true;
                } else if (args[i].equals("-competition")) {
                    competition = true;
                } else if (args[i].equals("-incremental")) {
                    incremental = true;
                } else if (args[i].equals("-option") && i + 1 < args.length) {
                    String[] opts = args[i+1].split(",");
                    for (String opt : opts) {
                        if (! setOption(opt)) 
                            throw new SugarException("Unknown option " + opt);
                    }
                    i++;
                } else if (args[i].equals("-debug") && i + 1 < args.length) {
                    debug = Integer.parseInt(args[i+1]);
                    i++;
                } else if (args[i].equals("-conversionHooks") && i + 1 < args.length) {
                    String[] hookNames = args[i+1].split(",");
                    for (String hookName : hookNames) {
                        Class clazz = Class.forName(hookName);
                        ConverterHook hook = (ConverterHook)clazz.newInstance();
                        Converter.addHook(hook);
                    }
                    i++;
                } else if (args[i].equals("-outputHook") && i + 1 < args.length) {
                    outputHook = args[i+1];
                    i++;
                } else if (args[i].equals("-v") || args[i].equals("-verbose")) {
                    Logger.verboseLevel++;
                } else if (args[i].startsWith("-")) {
                    option = args[i];
                    break;
                }
                i++;
            }
            SugarMain sugarMain = new SugarMain();
            int n = args.length - i;
            if (option.equals("-to") && n == 4) {
                String format = args[i+1];
                String outputFileName = args[i+2];
                String inputFileName = args[i+3];
                if (outputFileName.equals("-"))
                    outputFileName = null;
                sugarMain.outputCSP(inputFileName, outputFileName, format, outputHook);
            } else if (option.equals("-encode") && n == 4) {
                String cspFileName = args[i+1];
                String satFileName = args[i+2];
                String mapFileName = args[i+3];
                sugarMain.encode(cspFileName, satFileName, mapFileName);
            } else if (option.equals("-decode") && n == 3) {
                String outFileName = args[i+1];
                String mapFileName = args[i+2];
                sugarMain.decode(outFileName, mapFileName);
            } else {
                String s = "";
                for (String a : args) {
                    s += " " + a;
                }
                throw new SugarException("Invalid arguments " + s);
            }
            Logger.status();
        } catch (Exception e) {
            Logger.println("c ERROR Exception " + e.getMessage());          
            for (StackTraceElement t : e.getStackTrace()) {
                Logger.info(t.toString());
            }
            Logger.println("s UNKNOWN");
            System.exit(1);
        } catch (Error e) {
            Logger.println("c ERROR Exception " + e.getMessage());          
            for (StackTraceElement t : e.getStackTrace()) {
                Logger.info(t.toString());
            }
            Logger.println("s UNKNOWN");
            System.exit(1);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy