org.sosy_lab.java_smt.basicimpl.AbstractBooleanFormulaManager.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.java_smt.basicimpl.AbstractBooleanFormulaManager.java

Source

/*
 *  JavaSMT is an API wrapper for a collection of SMT solvers.
 *  This file is part of JavaSMT.
 *
 *  Copyright (C) 2007-2016  Dirk Beyer
 *  All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.sosy_lab.java_smt.basicimpl;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.BooleanFormulaManager;
import org.sosy_lab.java_smt.api.Formula;
import org.sosy_lab.java_smt.api.FormulaType;
import org.sosy_lab.java_smt.api.FunctionDeclaration;
import org.sosy_lab.java_smt.api.FunctionDeclarationKind;
import org.sosy_lab.java_smt.api.QuantifiedFormulaManager.Quantifier;
import org.sosy_lab.java_smt.api.visitors.BooleanFormulaTransformationVisitor;
import org.sosy_lab.java_smt.api.visitors.BooleanFormulaVisitor;
import org.sosy_lab.java_smt.api.visitors.DefaultFormulaVisitor;
import org.sosy_lab.java_smt.api.visitors.FormulaVisitor;
import org.sosy_lab.java_smt.api.visitors.TraversalProcess;

public abstract class AbstractBooleanFormulaManager<TFormulaInfo, TType, TEnv, TFuncDecl>
        extends AbstractBaseFormulaManager<TFormulaInfo, TType, TEnv, TFuncDecl> implements BooleanFormulaManager {

    private @Nullable BooleanFormula trueFormula = null;
    private @Nullable BooleanFormula falseFormula = null;

    protected AbstractBooleanFormulaManager(FormulaCreator<TFormulaInfo, TType, TEnv, TFuncDecl> pCreator) {
        super(pCreator);
    }

    private BooleanFormula wrap(TFormulaInfo formulaInfo) {
        return getFormulaCreator().encapsulateBoolean(formulaInfo);
    }

    @Override
    public BooleanFormula makeVariable(String pVar) {
        checkVariableName(pVar);
        return wrap(makeVariableImpl(pVar));
    }

    protected abstract TFormulaInfo makeVariableImpl(String pVar);

    @Override
    public BooleanFormula makeTrue() {
        if (trueFormula == null) {
            trueFormula = wrap(makeBooleanImpl(true));
        }
        return trueFormula;
    }

    @Override
    public BooleanFormula makeFalse() {
        if (falseFormula == null) {
            falseFormula = wrap(makeBooleanImpl(false));
        }
        return falseFormula;
    }

    @Override
    public BooleanFormula makeBoolean(boolean value) {
        return value ? makeTrue() : makeFalse();
    }

    protected abstract TFormulaInfo makeBooleanImpl(boolean value);

    @Override
    public BooleanFormula not(BooleanFormula pBits) {
        TFormulaInfo param1 = extractInfo(pBits);
        return wrap(not(param1));
    }

    protected abstract TFormulaInfo not(TFormulaInfo pParam1);

    @Override
    public BooleanFormula and(BooleanFormula pBits1, BooleanFormula pBits2) {
        TFormulaInfo param1 = extractInfo(pBits1);
        TFormulaInfo param2 = extractInfo(pBits2);

        return wrap(and(param1, param2));
    }

    protected abstract TFormulaInfo and(TFormulaInfo pParam1, TFormulaInfo pParam2);

    @Override
    public BooleanFormula and(Collection<BooleanFormula> pBits) {
        if (pBits.isEmpty()) {
            return makeBoolean(true);
        }
        if (pBits.size() == 1) {
            return Iterables.getOnlyElement(pBits);
        }
        TFormulaInfo result = andImpl(Collections2.transform(pBits, this::extractInfo));
        return wrap(result);
    }

    @Override
    public BooleanFormula and(BooleanFormula... pBits) {
        return and(Arrays.asList(pBits));
    }

    protected TFormulaInfo andImpl(Collection<TFormulaInfo> pParams) {
        TFormulaInfo result = makeBooleanImpl(true);
        for (TFormulaInfo formula : pParams) {
            result = and(result, formula);
        }
        return result;
    }

    @Override
    public BooleanFormula or(BooleanFormula pBits1, BooleanFormula pBits2) {
        TFormulaInfo param1 = extractInfo(pBits1);
        TFormulaInfo param2 = extractInfo(pBits2);

        return wrap(or(param1, param2));
    }

    @Override
    public BooleanFormula or(BooleanFormula... pBits) {
        return or(Arrays.asList(pBits));
    }

    protected abstract TFormulaInfo or(TFormulaInfo pParam1, TFormulaInfo pParam2);

    @Override
    public BooleanFormula xor(BooleanFormula pBits1, BooleanFormula pBits2) {
        TFormulaInfo param1 = extractInfo(pBits1);
        TFormulaInfo param2 = extractInfo(pBits2);

        return wrap(xor(param1, param2));
    }

    @Override
    public BooleanFormula or(Collection<BooleanFormula> pBits) {
        if (pBits.isEmpty()) {
            return makeBoolean(false);
        }
        if (pBits.size() == 1) {
            return Iterables.getOnlyElement(pBits);
        }
        TFormulaInfo result = orImpl(Collections2.transform(pBits, this::extractInfo));
        return wrap(result);
    }

    protected TFormulaInfo orImpl(Collection<TFormulaInfo> pParams) {
        TFormulaInfo result = makeBooleanImpl(false);
        for (TFormulaInfo formula : pParams) {
            result = or(result, formula);
        }
        return result;
    }

    protected abstract TFormulaInfo xor(TFormulaInfo pParam1, TFormulaInfo pParam2);

    /**
     * Creates a formula representing an equivalence of the two arguments.
     *
     * @param pBits1 a Formula
     * @param pBits2 a Formula
     * @return {@code f1 <-> f2}
     */
    @Override
    public final BooleanFormula equivalence(BooleanFormula pBits1, BooleanFormula pBits2) {
        TFormulaInfo param1 = extractInfo(pBits1);
        TFormulaInfo param2 = extractInfo(pBits2);
        return wrap(equivalence(param1, param2));
    }

    protected abstract TFormulaInfo equivalence(TFormulaInfo bits1, TFormulaInfo bits2);

    @Override
    public final BooleanFormula implication(BooleanFormula pBits1, BooleanFormula pBits2) {
        TFormulaInfo param1 = extractInfo(pBits1);
        TFormulaInfo param2 = extractInfo(pBits2);
        return wrap(implication(param1, param2));
    }

    protected TFormulaInfo implication(TFormulaInfo bits1, TFormulaInfo bits2) {
        return or(not(bits1), bits2);
    }

    @Override
    public final boolean isTrue(BooleanFormula pBits) {
        return isTrue(extractInfo(pBits));
    }

    protected abstract boolean isTrue(TFormulaInfo bits);

    @Override
    public final boolean isFalse(BooleanFormula pBits) {
        return isFalse(extractInfo(pBits));
    }

    protected abstract boolean isFalse(TFormulaInfo bits);

    /**
     * Creates a formula representing "IF cond THEN f1 ELSE f2"
     *
     * @param pBits a Formula
     * @param f1 a Formula
     * @param f2 a Formula
     * @return (IF cond THEN f1 ELSE f2)
     */
    @Override
    public final <T extends Formula> T ifThenElse(BooleanFormula pBits, T f1, T f2) {
        FormulaType<T> t1 = getFormulaCreator().getFormulaType(f1);
        FormulaType<T> t2 = getFormulaCreator().getFormulaType(f2);
        checkArgument(t1.equals(t2), "Cannot create if-then-else formula with branches of different types: "
                + "%s is of type %s; %s is of type %s", f1, t1, f2, t2);
        TFormulaInfo result = ifThenElse(extractInfo(pBits), extractInfo(f1), extractInfo(f2));
        return getFormulaCreator().encapsulate(t1, result);
    }

    protected abstract TFormulaInfo ifThenElse(TFormulaInfo cond, TFormulaInfo f1, TFormulaInfo f2);

    @Override
    public <R> R visit(BooleanFormula pFormula, BooleanFormulaVisitor<R> visitor) {
        return formulaCreator.visit(pFormula, new DelegatingFormulaVisitor<>(visitor));
    }

    @Override
    public void visitRecursively(BooleanFormula pF, BooleanFormulaVisitor<TraversalProcess> pFormulaVisitor) {
        formulaCreator.visitRecursively(new DelegatingFormulaVisitor<>(pFormulaVisitor), pF,
                Predicates.instanceOf(BooleanFormula.class)::apply);
    }

    @Override
    public BooleanFormula transformRecursively(BooleanFormula f, BooleanFormulaTransformationVisitor pVisitor) {
        return formulaCreator.transformRecursively(new DelegatingFormulaVisitor<>(pVisitor), f,
                p -> p instanceof BooleanFormula);
    }

    private class DelegatingFormulaVisitor<R> implements FormulaVisitor<R> {
        private final BooleanFormulaVisitor<R> delegate;

        DelegatingFormulaVisitor(BooleanFormulaVisitor<R> pDelegate) {
            delegate = pDelegate;
        }

        @Override
        public R visitFreeVariable(Formula f, String name) {

            // Only boolean formulas can appear here.
            assert f instanceof BooleanFormula;
            BooleanFormula casted = (BooleanFormula) f;
            return delegate.visitAtom(casted, FunctionDeclarationImpl.of(name, FunctionDeclarationKind.VAR,
                    ImmutableList.of(), FormulaType.BooleanType, formulaCreator.getBooleanVarDeclaration(casted)));
        }

        @Override
        public R visitBoundVariable(Formula f, int deBruijnIdx) {

            // Only boolean formulas can appear here.
            assert f instanceof BooleanFormula;
            return delegate.visitBoundVar((BooleanFormula) f, deBruijnIdx);
        }

        @Override
        public R visitConstant(Formula f, Object value) {
            checkState(value instanceof Boolean);
            return delegate.visitConstant((boolean) value);
        }

        private List<BooleanFormula> getBoolArgs(List<Formula> args) {
            @SuppressWarnings("unchecked")
            List<BooleanFormula> out = (List<BooleanFormula>) (List<?>) args;
            return out;
        }

        @Override
        public R visitFunction(Formula f, List<Formula> args, FunctionDeclaration<?> functionDeclaration) {
            switch (functionDeclaration.getKind()) {
            case AND:
                checkState(args.iterator().next() instanceof BooleanFormula);
                R out = delegate.visitAnd(getBoolArgs(args));
                return out;
            case NOT:
                checkState(args.size() == 1);
                Formula arg = args.get(0);

                checkArgument(arg instanceof BooleanFormula);
                return delegate.visitNot((BooleanFormula) arg);
            case OR:
                checkState(args.iterator().next() instanceof BooleanFormula);
                R out2 = delegate.visitOr(getBoolArgs(args));
                return out2;
            case IFF:
                checkState(args.size() == 2);
                Formula a = args.get(0);
                Formula b = args.get(1);
                checkState(a instanceof BooleanFormula && b instanceof BooleanFormula);
                R out3 = delegate.visitEquivalence((BooleanFormula) a, (BooleanFormula) b);
                return out3;
            case EQ:
                if (args.size() == 2 && args.get(0) instanceof BooleanFormula
                        && args.get(1) instanceof BooleanFormula) {
                    return delegate.visitEquivalence((BooleanFormula) args.get(0), (BooleanFormula) args.get(1));
                } else {
                    return delegate.visitAtom((BooleanFormula) f, toBooleanDeclaration(functionDeclaration));
                }
            case ITE:
                checkArgument(args.size() == 3);
                Formula ifC = args.get(0);
                Formula then = args.get(1);
                Formula elseC = args.get(2);
                checkState(ifC instanceof BooleanFormula && then instanceof BooleanFormula
                        && elseC instanceof BooleanFormula);
                return delegate.visitIfThenElse((BooleanFormula) ifC, (BooleanFormula) then,
                        (BooleanFormula) elseC);
            case XOR:
                checkArgument(args.size() == 2);
                Formula a1 = args.get(0);
                Formula a2 = args.get(1);
                checkState(a1 instanceof BooleanFormula && a2 instanceof BooleanFormula);
                return delegate.visitXor((BooleanFormula) a1, (BooleanFormula) a2);
            case IMPLIES:
                checkArgument(args.size() == 2);
                Formula b1 = args.get(0);
                Formula b2 = args.get(1);
                checkArgument(b1 instanceof BooleanFormula && b2 instanceof BooleanFormula);
                return delegate.visitImplication((BooleanFormula) b1, (BooleanFormula) b2);
            default:
                return delegate.visitAtom((BooleanFormula) f, toBooleanDeclaration(functionDeclaration));
            }
        }

        @Override
        public R visitQuantifier(BooleanFormula f, Quantifier quantifier, List<Formula> boundVariables,
                BooleanFormula body) {
            return delegate.visitQuantifier(quantifier, f, boundVariables, body);
        }

        @SuppressWarnings("unchecked")
        private FunctionDeclaration<BooleanFormula> toBooleanDeclaration(FunctionDeclaration<?> decl) {
            return (FunctionDeclaration<BooleanFormula>) decl;
        }
    }

    @Override
    public Set<BooleanFormula> toConjunctionArgs(BooleanFormula f, boolean flatten) {
        if (flatten) {
            return asFuncRecursive(f, conjunctionFinder);
        }
        return formulaCreator.visit(f, conjunctionFinder);
    }

    @Override
    public Set<BooleanFormula> toDisjunctionArgs(BooleanFormula f, boolean flatten) {
        if (flatten) {
            return asFuncRecursive(f, disjunctionFinder);
        }
        return formulaCreator.visit(f, disjunctionFinder);
    }

    /** Optimized non-recursive flattening implementation. */
    private Set<BooleanFormula> asFuncRecursive(BooleanFormula f, FormulaVisitor<Set<BooleanFormula>> visitor) {
        Set<BooleanFormula> output = new HashSet<>();
        Deque<BooleanFormula> toProcess = new ArrayDeque<>();
        Map<BooleanFormula, Set<BooleanFormula>> cache = new HashMap<>();
        toProcess.add(f);

        while (!toProcess.isEmpty()) {
            BooleanFormula s = toProcess.pop();
            Set<BooleanFormula> out = cache.get(s);
            if (out == null) {

                out = formulaCreator.visit(s, visitor);
                cache.put(s, out);
            }
            if (out.size() == 1 && s.equals(out.iterator().next())) {
                output.add(s);
            }
            for (BooleanFormula arg : out) {
                if (cache.get(arg) == null) { // Wasn't processed yet.
                    toProcess.add(arg);
                }
            }
        }

        return output;
    }

    private final FormulaVisitor<Set<BooleanFormula>> conjunctionFinder = new DefaultFormulaVisitor<Set<BooleanFormula>>() {
        @Override
        protected Set<BooleanFormula> visitDefault(Formula f) {
            assert f instanceof BooleanFormula;
            BooleanFormula bf = (BooleanFormula) f;
            if (isTrue(bf)) {
                return ImmutableSet.of();
            }
            return ImmutableSet.of((BooleanFormula) f);
        }

        @SuppressWarnings("unchecked")
        @Override
        public Set<BooleanFormula> visitFunction(Formula f, List<Formula> args,
                FunctionDeclaration<?> functionDeclaration) {
            if (functionDeclaration.getKind() == FunctionDeclarationKind.AND) {
                return ImmutableSet.copyOf((List<BooleanFormula>) (List<?>) args);
            }
            return visitDefault(f);
        }
    };

    /**
     * Optimized, but ugly, implementation of argument extraction. Avoids extra visitor instantiation.
     */
    private final FormulaVisitor<Set<BooleanFormula>> disjunctionFinder = new DefaultFormulaVisitor<Set<BooleanFormula>>() {
        @Override
        protected Set<BooleanFormula> visitDefault(Formula f) {
            assert f instanceof BooleanFormula;
            BooleanFormula bf = (BooleanFormula) f;
            if (isFalse(bf)) {
                return ImmutableSet.of();
            }
            return ImmutableSet.of((BooleanFormula) f);
        }

        @SuppressWarnings("unchecked")
        @Override
        public Set<BooleanFormula> visitFunction(Formula f, List<Formula> args,
                FunctionDeclaration<?> functionDeclaration) {
            if (functionDeclaration.getKind() == FunctionDeclarationKind.OR) {
                return ImmutableSet.copyOf((List<BooleanFormula>) (List<?>) args);
            }
            return visitDefault(f);
        }
    };
}