Package com.anjlab.sat3

Source Code of com.anjlab.sat3.Program

/*
* Copyright (c) 2010, 2011 AnjLab
*
* This file is part of
* Reference Implementation of Romanov's Polynomial Algorithm for 3-SAT Problem.
*
* Reference Implementation of Romanov's Polynomial Algorithm for 3-SAT Problem
* is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Reference Implementation of Romanov's Polynomial Algorithm for 3-SAT Problem
* is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with
* Reference Implementation of Romanov's Polynomial Algorithm for 3-SAT Problem.
* If not, see <http://www.gnu.org/licenses/>.
*/
package com.anjlab.sat3;

import static com.anjlab.sat3.Helper.printFormulas;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cern.colt.list.ObjectArrayList;

public class Program
{
    private static final String GENERATE_3SAT_OPTION = "g";
    private static final String FIND_HSS_ROUTE_OPTION = "r";
    private static final String CREATE_SKT_OPTION = "c";
    private static final String EVALUATE_OPTION = "e";
    private static final String RESULTS_OUTPUT_FILE_OPTION = "o";
    private static final String HELP_OPTION = "h";
    private static final String HSS_IMAGE_OUTPUT_FILENAME_OPTION = "i";
    private static final String USE_ABC_VAR_NAMES_OPTION = "u";
    private static final String DISABLE_ASSERTIONS_OPTION = "a";
    private static final String USE_PRETTY_PRINT_OPTION = "p";
   
    private static final Logger LOGGER = LoggerFactory.getLogger(Program.class);
   
    public static void main(String[] args) throws Exception
    {
        System.out.println("Reference Implementation of Romanov's Polynomial Algorithm for 3-SAT Problem"
                           + "\nCopyright (c) 2010 AnjLab"
                           + "\nThis program comes with ABSOLUTELY NO WARRANTY."
                           + "\nThis is free software, and you are welcome to redistribute it under certain conditions."
                           + "\nSee LICENSE.txt file or visit <http://www.gnu.org/copyleft/lesser.html> for details.");
       
        LOGGER.debug("Reading version number from manifest");
        String implementationVersion = Helper.getImplementationVersionFromManifest("3-SAT Core RI");
        System.out.println("Version: " + implementationVersion + "\n");
       
        Options options = getCommandLineOptions();
       
        CommandLineParser parser = new PosixParser();
        CommandLine commandLine = parser.parse(options, args);

        if (commandLine.getArgs().length != 1 || commandLine.hasOption(HELP_OPTION))
        {
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp(Program.class.getName() + " [OPTIONS] <input-file-name>" +
                    "\nWhere <input-file-name> is a path to file containing k-SAT formula instance in DIMACS CNF or Romanov SKT file format.", options);
            System.exit(0);
        }

        String formulaFile = commandLine.getArgs()[0];

        Helper.UsePrettyPrint = commandLine.hasOption(USE_PRETTY_PRINT_OPTION);
        Helper.EnableAssertions = !commandLine.hasOption(DISABLE_ASSERTIONS_OPTION);
        Helper.UseUniversalVarNames = !commandLine.hasOption(USE_ABC_VAR_NAMES_OPTION);
       
        Properties statistics = new Properties();
        StopWatch stopWatch = new StopWatch();
       
        try
        {
            statistics.put(Helper.IMPLEMENTATION_VERSION, implementationVersion);
           
            stopWatch.start("Load formula");
            ITabularFormula formula = Helper.loadFromFile(formulaFile);
            long timeElapsed = stopWatch.stop();
           
            statistics.put(Helper.INITIAL_FORMULA_LOAD_TIME, String.valueOf(timeElapsed));
           
            if (commandLine.hasOption(GENERATE_3SAT_OPTION))
            {
                String generated3SatFilename = formulaFile + "-3sat.cnf";
               
                LOGGER.info("Saving 3-SAT formula to {}...", generated3SatFilename);
                Helper.saveToDIMACSFileFormat(formula, generated3SatFilename);
            }
           
            if (formula.getVarCount() > 26)
            {
                LOGGER.info("Variables count > 26 => force using universal names for variables.");
                Helper.UseUniversalVarNames = true;
            }
           
            statistics.put(Helper.INITIAL_FORMULA_VAR_COUNT, String.valueOf(formula.getVarCount()));
            statistics.put(Helper.INITIAL_FORMULA_CLAUSES_COUNT, String.valueOf(formula.getClausesCount()));
           
            Helper.prettyPrint(formula);
            stopWatch.printElapsed();
           
            if (commandLine.hasOption(FIND_HSS_ROUTE_OPTION))
            {
                String hssPath = commandLine.getOptionValue(FIND_HSS_ROUTE_OPTION);
               
                stopWatch.start("Load HSS from " + hssPath);
                ObjectArrayList hss = Helper.loadHSS(hssPath);
                stopWatch.stop();
                stopWatch.printElapsed();
               
                findHSSRoute(commandLine, formulaFile, statistics, stopWatch, formula, null, null, hss, hssPath);
               
                return;
            }
           
            if (commandLine.hasOption(EVALUATE_OPTION))
            {
                String resultsFilename = commandLine.getOptionValue(EVALUATE_OPTION);
                boolean satisfiable = evaluateFormula(stopWatch, formula, resultsFilename);
                if (satisfiable)
                {
                    System.out.println("Formula evaluated as SAT");
                }
                else
                {
                    System.out.println("Formula evaluated as UNSAT");
                }
                //  Only evaluate formula value
                return;
            }
           
            //  Find if formula is SAT
           
            //  Clone initial formula to verify formula satisfiability later
            ITabularFormula formulaClone = null;
            if (Helper.EnableAssertions)
            {
                stopWatch.start("Clone initial formula");
                formulaClone = formula.clone();
                stopWatch.stop();
                stopWatch.printElapsed();
            }
           
            stopWatch.start("Create CTF");
            ObjectArrayList ct = Helper.createCTF(formula);
            timeElapsed = stopWatch.stop();
            printFormulas(ct);
            stopWatch.printElapsed();
           
            statistics.put(Helper.CTF_CREATION_TIME, String.valueOf(timeElapsed));
            statistics.put(Helper.CTF_COUNT, String.valueOf(ct.size()));
           
            LOGGER.info("CTF count: {}", ct.size());

            if (Helper.EnableAssertions)
            {
                assertNoTripletsLost(formula, ct);
            }

            //  Clone CTF to verify formula satisfiability against it later
            ObjectArrayList ctfClone = null;
           
            if (Helper.EnableAssertions)
            {
                ctfClone = Helper.cloneStructures(ct);
            }
           
            stopWatch.start("Create CTS");
            Helper.completeToCTS(ct, formula.getPermutation());
            timeElapsed = stopWatch.stop();
            printFormulas(ct);
            stopWatch.printElapsed();
           
            statistics.put(Helper.CTS_CREATION_TIME, String.valueOf(timeElapsed));
           
            if (commandLine.hasOption(CREATE_SKT_OPTION))
            {
                String sktFilename = formulaFile + ".skt";
                stopWatch.start("Convert CTS to " + sktFilename);
                Helper.convertCTStructuresToRomanovSKTFileFormat(ct, sktFilename);
                stopWatch.stop();
                stopWatch.printElapsed();
               
                return;
            }
           
            ObjectArrayList hss = unifyAndCreateHSS(statistics, stopWatch, ct);
           
            String hssPath = formulaFile + "-hss";
            stopWatch.start("Save HSS to " + hssPath + "...");
            Helper.saveHSS(hssPath, hss);
            stopWatch.stop();
            stopWatch.printElapsed();
           
            findHSSRoute(commandLine, formulaFile, statistics, stopWatch, formula, formulaClone, ctfClone, hss, hssPath);
        }
        catch (EmptyStructureException e)
        {
            stopWatch.stop();
            stopWatch.printElapsed();
           
            LOGGER.info("One of the structures was built empty", e);
           
            String resultsFilename = getResultsFilename(commandLine, formulaFile);
            stopWatch.start("Saving current statictics of calculations to " + resultsFilename);
            writeUnsatToFile(resultsFilename, statistics);
            stopWatch.stop();
            stopWatch.printElapsed();
           
            System.out.println("Formula not satisfiable");
        }
        finally
        {
            System.out.println("Program completed");
        }
    }

    private static ObjectArrayList unifyAndCreateHSS(Properties statistics, StopWatch stopWatch, ObjectArrayList cts)
    {
        long timeElapsed;
        stopWatch.start("Unify all CTS");
        Helper.unify(cts);
        timeElapsed = stopWatch.stop();
        printFormulas(cts);
        stopWatch.printElapsed();

        statistics.put(Helper.CTS_UNIFICATION_TIME, String.valueOf(timeElapsed));
       
        LOGGER.info("CTF: {}", cts.size());
       
        ObjectArrayList hss = null;
        try
        {
            stopWatch.start("Create HSS");
            hss = Helper.createHyperStructuresSystem(cts, statistics);
        }
        finally
        {
            timeElapsed = stopWatch.stop();
            stopWatch.printElapsed();
            if (hss != null)
            {
                statistics.put(Helper.BASIC_CTS_FINAL_CLAUSES_COUNT, String.valueOf(((IHyperStructure) hss.get(0)).getBasicCTS().getClausesCount()));
            }
            statistics.put(Helper.HSS_CREATION_TIME, String.valueOf(timeElapsed));
        }
        return hss;
    }

    private static void findHSSRoute(CommandLine commandLine, String formulaFile,
            Properties statistics, StopWatch stopWatch,
            ITabularFormula formula, ITabularFormula formulaClone,
            ObjectArrayList ctfClone, ObjectArrayList hss, String hssPath)
            throws IOException
    {
        long timeElapsed;
        //  TODO Configure hssTempPath using CL options
        String hssTempPath = hssPath + "-temp";
        stopWatch.start("Find HSS route");
        ObjectArrayList route = Helper.findHSSRouteByReduce(hss, hssTempPath);
        timeElapsed = stopWatch.stop();
        stopWatch.printElapsed();
       
        statistics.put(Helper.SEARCH_HSS_ROUTE_TIME, String.valueOf(timeElapsed));
       
        if (Helper.EnableAssertions)
        {
            if (formulaClone != null)
            {
                if (!formula.equals(formulaClone))
                {
                    LOGGER.warn("Initial formula differs from its cloned version");
                }
            }
        }
       
        String hssImageFile = formulaFile + "-hss-0.png";
       
        if (commandLine.hasOption(HSS_IMAGE_OUTPUT_FILENAME_OPTION))
        {
            hssImageFile = commandLine.getOptionValue(HSS_IMAGE_OUTPUT_FILENAME_OPTION);
        }
       
        stopWatch.start("Write HSS as image to " + hssImageFile);
        Helper.writeToImage(((SimpleVertex) route.get(route.size() - 1)).getHyperStructure(), route, null, hssImageFile);
        stopWatch.stop();
        stopWatch.printElapsed();
       
        stopWatch.start("Verify formula is satisfiable using variable values from HSS route");
        verifySatisfiable(formula, route);
        if (Helper.EnableAssertions)
        {
            if (ctfClone != null)
            {
                verifySatisfiable(ctfClone, route);
            }
        }
        stopWatch.stop();
        stopWatch.printElapsed();
       
        String resultsFilename = getResultsFilename(commandLine, formulaFile);
        stopWatch.start("Write HSS route to " + resultsFilename);
        writeSatToFile(formula, resultsFilename, statistics, route);
        stopWatch.stop();
        stopWatch.printElapsed();
    }

    private static boolean evaluateFormula(StopWatch stopWatch,
            ITabularFormula formula, String resultsFilename)
            throws FileNotFoundException, IOException
    {
        stopWatch.start("Evaluate formula");
        boolean satisfiable;
        Properties properties = new Properties();
        FileInputStream is = null;
        try
        {
            is = new FileInputStream(new File(resultsFilename));
            properties.load(is);
            satisfiable = formula.evaluate(properties);
            stopWatch.stop();
            stopWatch.printElapsed();
        }
        finally
        {
            if (is != null)
            {
                is.close();
            }
        }
        return satisfiable;
    }

    private static void writeUnsatToFile(String resultsFile, Properties statistics) throws IOException
    {
        OutputStream out = null;
        try
        {
            out = new FileOutputStream(new File(resultsFile));
           
            statistics.store(out, "Unsatisfiable");
        }
        finally
        {
            if (out != null)
            {
                out.close();
            }
        }
    }

    private static void writeSatToFile(ITabularFormula formula, String resultsFile, Properties statistics, ObjectArrayList route) throws IOException
    {
        OutputStream out = null;
        try
        {
            out = new FileOutputStream(new File(resultsFile));
           
            IVertex vertex = null;
            for (int i = 0; i < route.size(); i++)
            {
                vertex = (IVertex) route.get(i);
               
                writeToStatistics(formula, statistics, vertex.getPermutation().getAName(), vertex.getTripletValue().isNotA());
            }
            if (vertex != null)
            {
                writeToStatistics(formula, statistics, vertex.getPermutation().getBName(), vertex.getTripletValue().isNotB());
                writeToStatistics(formula, statistics, vertex.getPermutation().getCName(), vertex.getTripletValue().isNotC());
            }
           
            statistics.store(out, "Satisfiable. Variable values from HSS route");
        }
        finally
        {
            if (out != null)
            {
                out.close();
            }
        }
    }

    private static void writeToStatistics(ITabularFormula formula, Properties statistics, int varName, boolean varValue)
    {
        String stringValue = String.valueOf(varValue);
        statistics.put("_" + varName, stringValue);
       
        int originalVarName = formula.getOriginalVarName(varName);
        if (originalVarName > 0)
        {
            statistics.put(String.valueOf(originalVarName), stringValue);
        }
    }

    private static String getResultsFilename(CommandLine commandLine, String formulaFile)
    {
        String resultsFile = formulaFile + "-results.txt";
        if (commandLine.hasOption(RESULTS_OUTPUT_FILE_OPTION))
        {
            resultsFile = commandLine.getOptionValue(RESULTS_OUTPUT_FILE_OPTION);
        }
        return resultsFile;
    }

    @SuppressWarnings("static-access")
    private static Options getCommandLineOptions()
    {
        Options options = new Options();
       
        options.addOption(OptionBuilder.withLongOpt("help")
                                       .withDescription("Prints this help message.")
                                       .create(HELP_OPTION));
       
        options.addOption(OptionBuilder.withLongOpt("use-pretty-print")
                                       .withDescription("If specified, program will print detailed information about " +
                                                        "formulas including triplet values." +
                                                        "\nUseful when studying how algorithm works (especially if variables count less than 20)." +
                                                        "\nDisabled by default.")
                                       .create(USE_PRETTY_PRINT_OPTION));
       
        options.addOption(OptionBuilder.withLongOpt("disable-assertions")
                                       .withDescription("Disables internal program self-check during execution. This may improve performance.")
                                       .create(DISABLE_ASSERTIONS_OPTION));
       
        options.addOption(OptionBuilder.withLongOpt("use-abc-var-names")
                                       .withDescription("If specified, program will use ABC names for variables " +
                                                        "(like 'a', 'b', ..., 'z' instead of 'x1', 'x2', etc.) during formula output." +
                                                        "\nDisabled by default. Forced disabled if variables count more than 26.")
                                       .create(USE_ABC_VAR_NAMES_OPTION));
       
        options.addOption(OptionBuilder.withLongOpt("hss-image-output")
                                       .hasArg()
                                       .withArgName("filename")
                                       .withDescription("File name where visual representation of resulting basic graph will be written (only for SAT instances). Defaults to <input-file-name>-hss-0.png")
                                       .create(HSS_IMAGE_OUTPUT_FILENAME_OPTION));

        options.addOption(OptionBuilder.withLongOpt("output")
                                       .hasArg()
                                       .withArgName("filename")
                                       .withDescription("File name where results of calculation will be written (time measurements and satisfying set for SAT instances). Defaults to <input-file-name>-results.txt")
                                       .create(RESULTS_OUTPUT_FILE_OPTION));
       
        options.addOption(OptionBuilder.withLongOpt("evaluate-formula")
                                       .hasArg()
                                       .withArgName("filename")
                                       .withDescription("Evaluate formula using variable values from this file.")
                                       .create(EVALUATE_OPTION));

        options.addOption(OptionBuilder.withLongOpt("create-skt")
                                       .withDescription("Convert input formula to Romanov SKT file format.")
                                       .create(CREATE_SKT_OPTION));

        options.addOption(OptionBuilder.withLongOpt("find-hss-route")
                                       .hasArg()
                                       .withArgName("dirname")
                                       .withDescription("Find route in HSS from folder <dirname>")
                                       .create(FIND_HSS_ROUTE_OPTION));

        options.addOption(OptionBuilder.withLongOpt("generate-3sat-formula")
                                       .withDescription("Generate 3-SAT formula from <input-file-name> and save it to <input-file-name>-3sat.cnf.")
                                       .create(GENERATE_3SAT_OPTION));

        return options;
    }

    private static void assertNoTripletsLost(ITabularFormula formula, ObjectArrayList ctf)
    {
        int tripletCount = 0;
        for (int i = 0; i < ctf.size(); i++)
        {
            ITabularFormula f = (ITabularFormula) ctf.get(i);
            for (int j = 0; j < f.getTiers().size(); j++)
            {
                ITier tier = f.getTier(j);
                if (!formula.containsAllValuesOf(tier))
                {
                    throw new AssertionError("CTF triplet not found in initial formula");
                }
                else
                {
                    tripletCount += tier.size();
                }
            }
        }
        if (tripletCount != formula.getClausesCount())
        {
            throw new AssertionError("Bad CTF: tripletCount != formula.getClausesCount()");
        }
    }

    private static void verifySatisfiable(ITabularFormula formula, ObjectArrayList route)
    {
        boolean satisfiable = false;
        try
        {
            satisfiable = formula.evaluate(route);
        }
        catch (NullPointerException e)
        {
            //  Bad route
            e.printStackTrace();
        }
       
        if (!satisfiable)
        {
            throw new AssertionError("HSS was built but initial formula is not satisfiable with values from HS route");
        }
        else
        {
            LOGGER.info("Initial formula verified as satisfiable with variables from HSS route");
        }
    }

    private static void verifySatisfiable(ObjectArrayList ctf, ObjectArrayList route)
    {
        boolean satisfiable = false;
        try
        {
            satisfiable = Helper.evaluate(ctf, route);
        }
        catch (NullPointerException e)
        {
            //  Bad route
            e.printStackTrace();
        }
       
        if (!satisfiable)
        {
            throw new AssertionError("HSS was built but CTF is not satisfiable with values from HS route");
        }
        else
        {
            LOGGER.info("CTF verified as satisfiable with variables from HSS route");
        }
    }
}
TOP

Related Classes of com.anjlab.sat3.Program

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.