[Week Sixteen] Programming Contest - Boolean Satisfiability

Welcome back to the weekly programming contests! If you are new to the contest or need a refresher don’t forget to read up on the rules and information Posted Here

This week’s challenge is to write a method that takes in one String (a valid boolean formula in the form: "(a | ~b | ...) & (b | a | c | ...) ...") and returns true if a there set of values for the variables exist that make the expression true and false if it is not possible. For this challenge '&' represents AND, '|' represents OR, and '~' represents NOT. If you would like some further reading, please see Wikipedia

You can assume all conjunctions are surrounded with parentheses, that the formatting of the whitespace found in the examples is true for all inputs, that all variables are a single lowercase letters a-z, and that the syntax is valid.

Examples:

verify("(a | b | c) & (~a | b | c)") -> true
verify("(a | b) & (~b) & (~a)") -> false
verify("(a | b) & (~a | ~b | ~c) & (~b) & (~a)") -> false
verify("(a | b) & (~a | ~b)") -> true
verify("(a) & (~b) & (~a | b)") -> false
verify("(~b) & (a | c) & (a | ~b)") -> true
verify("(a) & (~a)") -> false

Also, if you like these weekly programming problems, please make some suggestions for the contest or specific challenges (in the main thread)! This takes time out of my Sunday and its not always fun! Using suggested challenges makes it a lot faster and easier for me.

Imports are allowed for this challenge!

Challenge Closes: Sunday 2/21/16

Good luck!

Will all of the boolean variables always be a single lowercase letter (/[a-z]/)?

Yes. I knew I was forgetting something when writing the assumptions lol

Is this correct?:
~a | ~b = (~a) | (~b)
~a & ~b = (~a) & (~b)

Yes, also note that all ‘& terms’ will always be surrounded by parentheses in the input

might be cheating, but I’m using nashorn :stuck_out_tongue:

666 characters

public static ScriptEngine e;public static boolean v(String x){x=x.replace("|","||").replace("&","&&").replace("~","!");e=new ScriptEngineManager().getEngineByName("nashorn");Matcher m=Pattern.compile(".*?([a-z]).*?").matcher(x);Set v=new HashSet();while(m.find())v.add(x.substring(m.start(1),m.end(1)));return t(v,x);}public static boolean e(String x,Set<String>v,boolean s){for(String a:v)e.getContext().setAttribute(a,s,100);try{return(Boolean)e.eval(x);}catch(Exception t){return false;}}public static boolean t(Set v,String x){Set n=new HashSet(v);n.remove(n.iterator().next());for(int i=0;i<2;)if(e(x,v,i++<1)||(!n.isEmpty()&&t(n,x)))return true;return false;}

An expanded and more readable version:

    public static boolean verify(String expr) {
        expr = expr.replace("|", "||").replace("&", "&&").replace("~", "!");
        ScriptEngine e = new ScriptEngineManager().getEngineByName("nashorn");
        Matcher m = Pattern.compile(".*?([a-z]).*?").matcher(expr);
        Set<String> vars = new HashSet<>();
        while (m.find()) {
            vars.add(expr.substring(m.start(1), m.end(1)));
        }
        return test(vars, e, expr);
    }

    public static boolean exec(ScriptEngine e, String expr, Set<String> vars, boolean set) {
        for (String var : vars) {
            e.getContext().setAttribute(var, set, ScriptContext.ENGINE_SCOPE);
        }
        try {
            return (Boolean) e.eval(expr);
        } catch (ScriptException e1) {
            e1.printStackTrace();
            return false;
        }
    }

    public static boolean test(Set<String> vars, ScriptEngine e, String expr) {
        HashSet<String> n = new HashSet<>(vars);
        n.remove(n.iterator().next());
        for (int i = 0; i < 2;) {
            if (exec(e, expr, vars, i++ < 1) || (!n.isEmpty() && test(n, e, expr))) {
                return true;
            }
        }
        return false;
    }

Probably isn’t perfect

####Minfied (657 chars):

public static boolean v(String a){Set<Integer>b=new HashSet<>();for(char c:a.toCharArray())if(c>96&&c<123)b.add((int)c);int r=0,i=0,j,k,l=a.length(),c,v,m,g=38,h='|',o,f;for(;i<Math.pow(2,b.size());i++){int[]d=new int[b.size()];String s=Integer.toBinaryString(i);for(j=d.length-1,k=s.length()-1;j>=0&&k>=0;j--,k--)d[j]=s.charAt(k)-48;j=0;Map<Integer,Integer>e=new HashMap<>();for(int z:b)e.put(z,d[j++]);f=1;o=g;for(j=0;j<l;j++){c=a.charAt(j);if(c==40){v=1;m=g;boolean n=false;while(j<l&&c!=41){c=a.charAt(j++);m=c==h||c==g?c:m;Integer p=e.get(c);if(p!=null){p=n?p>0?0:1:p;v=m==g?v*p:v+p;}n=c=='~';}f=o==g?f*v:f+v;}o=c==h||c==g?c:o;}if(f>0)r=1;}return r>0;}

####Readable (sort of):

    // 1. Finds unique variables in the expression
    // 2. Counting between 0 and 2^(number of vars found), uses Integer.toBinaryString to assign a
    //    true/false (1/0) value to each variable.
    // 3. Loops through expression and evaluates using the above determined true/false values
    public static boolean verify(String in)
    {
        Set<Integer> args = new HashSet<>();
        for (char c : in.toCharArray())
        {
            // 97 & 122
            if (c >= 'a' && c <= 'z')
            {
                args.add((int) c);
            }
        }

        StringBuilder sb = new StringBuilder();

        int i = 0, j, k;
        for (; i < Math.pow(2, args.size()); i++)
        {
            int[] points = new int[args.size()];
            String s = Integer.toBinaryString(i);
            for (j = points.length - 1, k = s.length() - 1; j >= 0 && k >= 0; j--, k--)
            {
                points[j] = s.charAt(k) - '0'; // 48
            }

            j = 0;
            Map<Integer, Integer> _case = new HashMap<>();
            for (int c : args)
            {
                _case.put(c, points[j++]);
            }

            int result = 1, and = '&' /*38*/, or = '|', operator = and;
            for (j = 0; j < in.length(); j++)
            {
                int c = in.charAt(j);
                if (c == '(') // 40
                {
                    int val = 1, op = and;
                    boolean invert = false;
                    while (j < in.length() && c != ')') // 41
                    {
                        c = in.charAt(j++);
                        op = c == or || c == and ? c : op;
                        Integer p = _case.get(c);
                        if (p != null)
                        {
                            p = invert ? p > 0 ? 0 : 1 : p;
                            val = op == and ? val * p : val + p;
                        }
                        invert = c == '~';
                    }
                    result = operator == and ? result * val : result + val;
                }
                operator = c == or || c == and ? c : operator;
            }
            if (result > 0)
            {
                sb.append(sb.length() == 0 ? "Valid Case(s):\n" : "\n");
                j = _case.size();
                for (Map.Entry<Integer, Integer> e : _case.entrySet())
                {
                    sb.append((char) e.getKey().intValue()).append("=").append(e.getValue() == 1);
                    if (--j > 0) sb.append(",");
                }
            }
        }
        if (sb.length() > 0) System.out.println(sb.toString());
        return sb.length() > 0;
    }

419 characters

public static boolean v(String e){boolean s=e!=e;for(int i=0;i<1<<27;i++){s|=f(i,e);}return s;}public static boolean f(int v,String e){boolean r,n=e.charAt(0)=='~';int i=n?1:0,c=e.charAt(i),p=1;if(c=='('){while(p>0)if((c=e.charAt(++i))=='(')p++;else if(c==')')p--;r=f(v,e.substring(n?2:1,i));}else r=(v&1<<(c-'a'))!=0;r=n!=r;return ++i>=e.length()?r:e.charAt(++i)=='|'? r|f(v,e.substring(i+2)):r&f(v,e.substring(i+2));}

long version

    public static boolean verify(String expression) {
        boolean satisfiable = false;
        for (int value = 0; value < 1 << 27; value++) {
            satisfiable |= eval(value, expression);
        }
        return satisfiable;
    }

    public static boolean eval(int value, String expression) {
        boolean result, negative = expression.charAt(0) == '~';
        int index = negative ? 1 : 0, c = expression.charAt(index), parentheses = 1;
        if (c == '(') {
            while (parentheses > 0) if ((c = expression.charAt(++index)) == '(') parentheses++;
            else if (c == ')') parentheses--;
            result = eval(value, expression.substring(negative ? 2 : 1, index));
        } else result = (value & 1 << (c - 'a')) != 0;
        result = negative != result;
        return ++index >= expression.length() 
                ? result 
                : expression.charAt(++index) == '|' 
                        ? result | eval(value, expression.substring(index + 2)) 
                        : result & eval(value, expression.substring(index + 2));
    }
1 Like

247 Characters

public static boolean v(String a){int r=0,i=-1,j=1,f=1,e[]=new int[127];for(;++i<1<<j;r|=f++){j=0;for(int z:a.chars().distinct().toArray())e[z]=i>>j++;for(int c:a.toCharArray()){f=c>96&c<'{'?e[c]*4^f*2|f:c==41?f/4&f&1:c=='~'?2|f:f&5;}}return r>0;}

Unminified (still not readable, sorry):

public static boolean v(String a) {
    int r = 0, i = -1, j = 1, f = 1, e[] = new int[127];
    for (; ++i < 1 << j; r |= f++) {
        j = 0;
        for (int z : a.chars().distinct().toArray())
            e[z] = i >> j++;
        for (int c : a.toCharArray()) {
            f = c > 96 & c < '{'
                    ? e[c] * 4 ^ f * 2 | f
                    : c == 41
                        ? f / 4 & f & 1
                        : c == '~'
                            ? 2 | f
                            : f & 5;
        }
    }
    return r > 0;
}

This is based off of @dags’s answer, but has been altered to pretty much unrecognizable.
f stores three boolean values in its least significant bits, equivalent to @dags’s val, invert, result variables respectively.

1 Like

Feels a bit dirty but you can drop the braces around the last for loop of @jus1in’s to reach 245 characters

public static boolean v(String a){int r=0,i=-1,j=1,f=1,e[]=new int[127];for(;++i<1<<j;r|=f++){j=0;for(int z:a.chars().distinct().toArray())e[z]=i>>j++;for(int c:a.toCharArray())f=c>96&c<'{'?e[c]*4^f*2|f:c==41?f/4&f&1:c=='~'?2|f:f&5;}return r>0;}
2 Likes

244 characters

public static boolean v(String a){int r=0,i=0,f=1;for(List l=Arrays.asList(a.chars().distinct().boxed().toArray());++i<1<<l.size();r|=f++)for(int c:a.toCharArray())f=c>96&c<'{'?(i>>l.indexOf(c))*4^f*2|f:c==41?f/4&f&1:c=='~'?2|f:f&5;return r>0;}
    public static boolean v(String a) {
        int r = 0, i = 0, f = 1;
        for (List l = Arrays.asList(a.chars().distinct().boxed().toArray()); ++i < 1 << l.size(); r |= f++)
            for (int c : a.toCharArray())
                f = c > 96 & c < '{' ? (i >> l.indexOf(c)) * 4 ^ f * 2 | f : c == 41 ? f / 4 & f & 1 : c == '~' ? 2 | f : f & 5;
        return r > 0;
    }

This time it has no loops with brackets.

Congratulations to @jus1in for winning week 16! :wink:

The next challenge will be posted shortly.