Package wycs.transforms

Source Code of wycs.transforms.VerificationCheck

package wycs.transforms;

import static wycc.lang.SyntaxError.*;
import static wycs.solver.Solver.*;

import java.io.IOException;
import java.math.BigInteger;
import java.util.*;

import wyautl.core.*;
import wyautl.io.PrettyAutomataWriter;
import wyautl.rw.*;
import wyautl.rw.Rewriter.Stats;
import wyautl.util.BigRational;
import wybs.lang.Builder;
import wycc.lang.SyntacticElement;
import wycc.lang.Transform;
import wycc.util.Logger;
import wycc.util.Pair;
import wycc.util.Triple;
import wycs.builders.Wyal2WycsBuilder;
import wycs.core.Code;
import wycs.core.NormalForms;
import wycs.core.SemanticType;
import wycs.core.Types;
import wycs.core.Value;
import wycs.core.WycsFile;
import wycs.io.WycsFilePrinter;
import wycs.solver.Solver;
import wycs.solver.SolverUtil;
import wyfs.util.Trie;

/**
* Responsible for converting a <code>WycsFile</code> into an automaton that can
* then be simplified to test for satisfiability. The key challenge here is to
* break down the rich language of expressions described by the
* <code>WycsFile</code> format, such that they can be handled effectively by
* the <code>Solver</code>.
*
* @author David J. Pearce
*
*/
public class VerificationCheck implements Transform<WycsFile> {
    private enum RewriteMode { SIMPLE, STATICDISPATCH, GLOBALDISPATCH };

  /**
   * Determines whether this transform is enabled or not.
   */
  private boolean enabled = getEnable();

  /**
   * Determines whether debugging is enabled or not
   */
  private boolean debug = getDebug();

  /**
   * Determine what rewriter to use.
   */
  private RewriteMode rwMode = RewriteMode.STATICDISPATCH;

  /**
   * Determine the maximum number of reduction steps permitted
   */
  private int maxReductions = getMaxReductions();

  /**
   * Determine the maximum number of inference steps permitted
   */
  private int maxInferences = getMaxInferences();

  private final Wyal2WycsBuilder builder;

  private String filename;

  // ======================================================================
  // Constructor(s)
  // ======================================================================

  public VerificationCheck(Builder builder) {
    this.builder = (Wyal2WycsBuilder) builder;
  }

  // ======================================================================
  // Configuration Methods
  // ======================================================================

  public static String describeEnable() {
    return "Enable/disable verification";
  }

  public static boolean getEnable() {
    return true; // default value
  }

  public void setEnable(boolean flag) {
    this.enabled = flag;
  }

  public static String describeDebug() {
    return "Enable/disable debugging information";
  }

  public static boolean getDebug() {
    return false; // default value
  }

  public void setDebug(boolean flag) {
    this.debug = flag;
  }

  public static String describeRwMode() {
    return "Set the rewrite mode to use (simple or static-dispatch)";
  }

  public static String getRwmode() {
    return "staticdispatch"; // default value
  }

  public void setRwmode(String mode) {
    for(RewriteMode rw : RewriteMode.values()) {
      if(mode.equals(rw.name().toLowerCase())) {
        this.rwMode = rw;
        return;
      }
    }
    throw new RuntimeException("unknown rewrite mode: " + mode);
  }

  public static String describeMaxReductions() {
    return "Limits the number of reduction steps permitted";
  }

  public static int getMaxReductions() {
    return 500; // default value
  }

  public void setMaxReductions(int limit) {
    this.maxReductions = limit;
  }

  public static String describeMaxInferences() {
    return "Limits the number of inference steps permitted";
  }

  public static int getMaxInferences() {
    return 200; // default value
  }

  public void setMaxInferences(int limit) {
    this.maxInferences = limit;
  }


  // ======================================================================
  // Apply Method
  // ======================================================================

  /**
   * Verify the given list of Wycs statements.
   *
   * @param statements
   * @return the set of failing assertions (if any).
   */
  public void apply(WycsFile wf) {
    if (enabled) {
      this.filename = wf.filename();

      // Traverse each statement and verify any assertions we
      // encounter.
      List<WycsFile.Declaration> statements = wf.declarations();
      int count = 0;
      for (int i = 0; i != statements.size(); ++i) {
        WycsFile.Declaration stmt = statements.get(i);

        if (stmt instanceof WycsFile.Assert) {
          checkValid((WycsFile.Assert) stmt, ++count);
        } else if (stmt instanceof WycsFile.Function
            || stmt instanceof WycsFile.Macro) {
          // TODO: we could try to verify that the function makes
          // sense (i.e. that it's specification is satisfiable for at
          // least one input).
        } else {
          internalFailure("unknown statement encountered " + stmt,
              filename, stmt);
        }
      }
    }
  }

  private void checkValid(WycsFile.Assert stmt, int number) {
    Runtime runtime = Runtime.getRuntime();
    long startTime = System.currentTimeMillis();
    long startMemory = runtime.freeMemory();

    Automaton automaton = new Automaton();
    Automaton original = null;

    Code neg = Code.Unary(SemanticType.Bool,
        Code.Op.NOT, stmt.condition);
    // The following conversion is potentially very expensive, but is
    // currently necessary for the instantiate axioms phase.
    Code nnf = NormalForms.negationNormalForm(neg);

    ///debug(nnf,filename);
    int maxVar = findLargestVariable(nnf);

    Code vc = instantiateAxioms(nnf, maxVar + 1);

    //debug(vc,filename);

    int assertion = translate(vc,automaton,new HashMap<String,Integer>());
    automaton.setRoot(0, assertion);
    // NOTE: don't need to minimise or compact here since the rewriter does
    // this for me.
    //
    //    automaton.minimise();
    //    automaton.compact();

    if (debug) {
      debug(neg,filename);
      original = new Automaton(automaton);
      //debug(original);
    }

    Rewriter rewriter = createRewriter(automaton);
    boolean r = rewriter.apply();

    if(!r) {
      throw new AssertionFailure("timeout occurred during verification",stmt,rewriter,automaton,original);
    } else if(!automaton.get(automaton.getRoot(0)).equals(Solver.False)) {
      String msg = stmt.message;
      msg = msg == null ? "assertion failure" : msg;
      throw new AssertionFailure(msg,stmt,rewriter,automaton,original);
    }

    long endTime = System.currentTimeMillis();
    builder.logTimedMessage("[" + filename + "] Verified assertion #" + number,
        endTime - startTime, startMemory - runtime.freeMemory());
  }

  private int translate(Code expr, Automaton automaton, HashMap<String,Integer> environment) {
    int r;
    if(expr instanceof Code.Constant) {
      r = translate((Code.Constant) expr,automaton,environment);
    } else if(expr instanceof Code.Variable) {
      r = translate((Code.Variable) expr,automaton,environment);
    } else if(expr instanceof Code.Binary) {
      r = translate((Code.Binary) expr,automaton,environment);
    } else if(expr instanceof Code.Unary) {
      r = translate((Code.Unary) expr,automaton,environment);
    } else if(expr instanceof Code.Nary) {
      r = translate((Code.Nary) expr,automaton,environment);
    } else if(expr instanceof Code.Load) {
      r = translate((Code.Load) expr,automaton,environment);
    } else if(expr instanceof Code.Quantifier) {
      r = translate((Code.Quantifier) expr,automaton,environment);
    } else if(expr instanceof Code.FunCall) {
      r = translate((Code.FunCall) expr,automaton,environment);
    } else {
      internalFailure("unknown: " + expr.getClass().getName(),
          filename, expr);
      return -1; // dead code
    }

    //debug(automaton,r);
    return r;
  }

  private int translate(Code.Constant expr, Automaton automaton, HashMap<String,Integer> environment) {
    return convert(expr.value,expr,automaton);
  }

  private int translate(Code.Variable code, Automaton automaton, HashMap<String,Integer> environment) {
    if(code.operands.length > 0) {
      throw new RuntimeException("need to add support for variables with sub-components");
    }
    // TODO: just use an integer for variables directly
    String name = "r" + code.index;
    Integer idx = environment.get(name);
    // FIXME: need to handle code.operands as well!
    if(idx == null) {
      // FIXME: this is a hack to work around modified operands after a
      // loop.
      return Var(automaton,name);
    } else {
      return idx;
    }
  }

  private int translate(Code.Binary code, Automaton automaton, HashMap<String,Integer> environment) {
    int lhs = translate(code.operands[0],automaton,environment);
    int rhs = translate(code.operands[1],automaton,environment);

    int type = convert(automaton,code.type);

    switch(code.opcode) {
    case ADD:
      return SolverUtil.Add(automaton,lhs,rhs);
    case SUB:
      return SolverUtil.Sub(automaton,lhs,rhs);
    case MUL:
      return SolverUtil.Mul(automaton, lhs, rhs);
    case DIV:
      return SolverUtil.Div(automaton, lhs, rhs);
    case REM:
      return automaton.add(False);
    case EQ:
      return SolverUtil.Equals(automaton, type, lhs, rhs);
    case NEQ:
      return Not(automaton, SolverUtil.Equals(automaton, type, lhs, rhs));
    case LT:
      return SolverUtil.LessThan(automaton, type, lhs, rhs);
    case LTEQ:
      return SolverUtil.LessThanEq(automaton, type, lhs, rhs);
    case IN:
      return SubsetEq(automaton, type, Set(automaton, lhs), rhs);
    case SUBSET:
      return And(automaton,
          SubsetEq(automaton, type, lhs, rhs),
          Not(automaton, SolverUtil.Equals(automaton, type, lhs, rhs)));
    case SUBSETEQ:
      return SubsetEq(automaton, type, lhs, rhs);
    }
    internalFailure("unknown binary bytecode encountered (" + code + ")",
        filename, code);
    return -1;
  }

  private int translate(Code.Unary code, Automaton automaton, HashMap<String,Integer> environment) {
    int e = translate(code.operands[0],automaton,environment);
    switch(code.opcode) {
    case NOT:
      return Not(automaton, e);
    case NEG:
      return SolverUtil.Neg(automaton, e);
    case LENGTH:
      return LengthOf(automaton, e);
    }
    internalFailure("unknown unary bytecode encountered (" + code + ")",
        filename, code);
    return -1;
  }

  private int translate(Code.Nary code, Automaton automaton, HashMap<String,Integer> environment) {
    Code[] operands = code.operands;
    int[] es = new int[operands.length];
    for(int i=0;i!=es.length;++i) {
      es[i] = translate(operands[i],automaton,environment);
    }
    switch(code.opcode) {
    case AND:
      return And(automaton,es);
    case OR:
      return Or(automaton,es);
    case SET:
      return Set(automaton,es);
    case TUPLE:
      return Tuple(automaton,es);
    }
    internalFailure("unknown nary expression encountered (" + code + ")",
        filename, code);
    return -1;
  }

  private int translate(Code.Load code, Automaton automaton, HashMap<String,Integer> environment) {
    int e = translate(code.operands[0],automaton,environment);
    int i = automaton.add(new Automaton.Int(code.index));
    return Solver.Load(automaton,e,i);
  }

  private int translate(Code.FunCall code, Automaton automaton,
      HashMap<String, Integer> environment) {
    // uninterpreted function call
    int argument = translate(code.operands[0], automaton, environment);
    int[] es = new int[] {
        automaton.add(new Automaton.Strung(code.nid.toString())),
        argument };
    return Fn(automaton, es);
  }

  private int translate(Code.Quantifier code, Automaton automaton, HashMap<String,Integer> environment) {
    HashMap<String,Integer> nEnvironment = new HashMap<String,Integer>(environment);
    Pair<SemanticType,Integer>[] variables = code.types;
    int[] vars = new int[variables.length];
    for (int i = 0; i != variables.length; ++i) {
      Pair<SemanticType,Integer> p = variables[i];
      SemanticType type = p.first();
      String var = "r" + p.second();
      int varIdx = Var(automaton, var);
      nEnvironment.put(var, varIdx);
      int srcIdx;
      // FIXME: generate actual type of variable here
      srcIdx = automaton.add(AnyT);
      vars[i] = automaton.add(new Automaton.List(varIdx, srcIdx));
    }

    int avars = automaton.add(new Automaton.Set(vars));

    if(code.opcode == Code.Op.FORALL) {
      return ForAll(automaton, avars, translate(code.operands[0], automaton, nEnvironment));
    } else {
      return Exists(automaton, avars, translate(code.operands[0], automaton, nEnvironment));
    }
  }

  /**
   * Convert between a WYIL value and a WYRL value. Basically, this is really
   * stupid and it would be good for them to be the same.
   *
   * @param value
   * @return
   */
  private int convert(Value value, SyntacticElement element, Automaton automaton) {

    if (value instanceof Value.Bool) {
      Value.Bool b = (Value.Bool) value;
      return b.value ? automaton.add(True) : automaton.add(False);
    } else if (value instanceof Value.Integer) {
      Value.Integer v = (Value.Integer) value;
      return Num(automaton , BigRational.valueOf(v.value));
    } else if (value instanceof Value.Decimal) {
      Value.Decimal v = (Value.Decimal) value;
      return Num(automaton, new BigRational(v.value));
    } else if (value instanceof Value.String) {
      Value.String v = (Value.String) value;
      return Solver.String(automaton,v.value);
    } else if (value instanceof Value.Set) {
      Value.Set vs = (Value.Set) value;
      int[] vals = new int[vs.values.size()];
      int i = 0;
      for (Value c : vs.values) {
        vals[i++] = convert(c,element,automaton);
      }
      return Set(automaton , vals);
    } else if (value instanceof Value.Tuple) {
      Value.Tuple vt = (Value.Tuple) value;
      int[] vals = new int[vt.values.size()];
      for (int i = 0; i != vals.length; ++i) {
        vals[i] = convert(vt.values.get(i),element,automaton);
      }
      return Tuple(automaton , vals);
    } else {
      internalFailure("unknown value encountered (" + value + ", " + value.getClass().getName() + ")",
          filename,element);
      return -1;
    }
  }


  /**
   * Construct an automaton node representing a given semantic type.
   *
   * @param automaton
   * @param type --- to be converted.
   * @return the index of the new node.
   */
  public int convert(Automaton automaton, SemanticType type) {
    Automaton type_automaton = type.automaton();
    // The following is important to make sure that the type is in minimised
    // form before verification begins. This firstly reduces the amount of
    // work during verification, and also allows the functions in
    // SolverUtils to work properly.
    Rewriter rewriter = createRewriter(type_automaton);
    rewriter.apply();
    return automaton.addAll(type_automaton.getRoot(0), type_automaton);
  }

  public static void debug(Automaton automaton) {
    try {
      // System.out.println(automaton);
      PrettyAutomataWriter writer = new PrettyAutomataWriter(System.out,
          SCHEMA, "Or", "And");
      writer.write(automaton);
      writer.flush();
    } catch(IOException e) {
      System.out.println("I/O Exception - " + e);
    }
  }

  public static void debug(Code code, String filename) {
    ArrayList<WycsFile.Declaration> tmpDecls = new ArrayList();
    tmpDecls.add(new WycsFile.Assert("", code));
    WycsFile tmp = new WycsFile(Trie.ROOT, filename, tmpDecls);
    try {
      new WycsFilePrinter(System.err).write(tmp);
    } catch (IOException e) {
    }
  }

  public static class AssertionFailure extends RuntimeException {
    private final WycsFile.Assert assertion;
    private final Rewriter rewriter;
    private final Automaton reduced;
    private final Automaton original;

    public AssertionFailure(String msg, WycsFile.Assert assertion,
        Rewriter rewriter, Automaton reduced, Automaton original) {
      super(msg);
      this.assertion = assertion;
      this.rewriter = rewriter;
      this.reduced = reduced;
      this.original = original;
    }

    public WycsFile.Assert assertion() {
      return assertion;
    }

    public Rewriter rewriter() {
      return rewriter;
    }

    public Automaton reduction() {
      return reduced;
    }

    public Automaton original() {
      return original;
    }
  }


  // =============================================================================
  // Axiom Instantiation
  // =============================================================================


  /**
   * Blindly instantiate all axioms. Note, this function is assuming the
   * verification condition has already been negated for
   * proof-by-contradiction and converted into Negation Normal Form.
   *
   * @param condition
   *            Condition over which all axioms should be instantiated.
   * @param freeVariable
   *            First available free variable which can be used when
   *            instantiating axioms.
   * @return
   */
  public Code instantiateAxioms(Code condition, int freeVariable) {
    if (condition instanceof Code.Variable || condition instanceof Code.Constant) {
      // do nothing
      return condition;
    } else if (condition instanceof Code.Unary) {
      return instantiateAxioms((Code.Unary)condition, freeVariable);
    } else if (condition instanceof Code.Binary) {
      return instantiateAxioms((Code.Binary)condition, freeVariable);
    } else if (condition instanceof Code.Nary) {
      return instantiateAxioms((Code.Nary)condition, freeVariable);
    } else if (condition instanceof Code.Quantifier) {
      return instantiateAxioms((Code.Quantifier)condition, freeVariable);
    } else if (condition instanceof Code.FunCall) {
      return instantiateAxioms((Code.FunCall)condition, freeVariable);
    } else if (condition instanceof Code.Load) {
      return instantiateAxioms((Code.Load)condition, freeVariable);
    } else {
      internalFailure("invalid boolean expression encountered (" + condition
          + ")", filename, condition);
      return null;
    }
  }

  private Code instantiateAxioms(Code.Unary condition, int freeVariable) {
    switch(condition.opcode) {
    case NOT:
      return Code.Unary(condition.type, condition.opcode,
          instantiateAxioms(condition.operands[0], freeVariable), condition.attributes());
    default:
      internalFailure("invalid boolean expression encountered (" + condition
          + ")", filename, condition);
      return null;
    }
  }

  private Code instantiateAxioms(Code.Binary condition, int freeVariable) {
    switch (condition.opcode) {
    case EQ:
    case NEQ:
    case LT:
    case LTEQ:
    case IN:
    case SUBSET:
    case SUBSETEQ: {
      ArrayList<Code> axioms = new ArrayList<Code>();
      instantiateFromExpression(condition, axioms, freeVariable);
      return and(axioms,condition);
    }
    default:
      internalFailure("invalid boolean expression encountered (" + condition
          + ")", filename, condition);
      return null;
    }
  }

  private Code instantiateAxioms(Code.Nary condition, int freeVariable) {
    switch(condition.opcode) {
    case AND:
    case OR: {
      Code[] e_operands = new Code[condition.operands.length];
      for(int i=0;i!=e_operands.length;++i) {
        e_operands[i] = instantiateAxioms(condition.operands[i], freeVariable);
      }
      return Code.Nary(condition.type, condition.opcode, e_operands, condition.attributes());
    }
    default:
      internalFailure("invalid boolean expression encountered (" + condition
          + ")", filename, condition);
      return null;
    }
  }

  private Code instantiateAxioms(Code.Quantifier condition, int freeVariable) {
    return Code.Quantifier(condition.type, condition.opcode,
        instantiateAxioms(condition.operands[0], freeVariable), condition.types, condition.attributes());
  }

  private Code instantiateAxioms(Code.FunCall condition, int freeVariable) {
    ArrayList<Code> axioms = new ArrayList<Code>();
    try {
      WycsFile module = builder.getModule(condition.nid.module());
      // module should not be null if TypePropagation has already passed.
      Object d = module.declaration(condition.nid.name());
      if(d instanceof WycsFile.Function) {
        WycsFile.Function fn = (WycsFile.Function) d;
        if(fn.constraint != null) {
          // There are some axioms we can instantiate. First, we need to
          // construct the generic binding for this function.
          HashMap<String,SemanticType> generics = buildGenericBinding(fn.type.generics(),condition.type.generics());
          Code axiom = renameToAvoidCapture(fn.constraint,freeVariable);
          HashMap<Integer,Code> binding = new HashMap<Integer,Code>();
          binding.put(1, condition.operands[0]);
          binding.put(0, condition);
          axiom = axiom.substitute(binding).instantiate(
              generics);
          axioms.add(axiom);
        }
      } else if(d instanceof WycsFile.Macro){
        // we can ignore macros, because they are inlined separately by
        // MacroExpansion.
      } else {
        internalFailure("cannot resolve as function or macro call",
            filename, condition);
      }
    } catch(Exception ex) {
      internalFailure(ex.getMessage(), filename, condition, ex);
    }

    instantiateFromExpression(condition.operands[0], axioms, freeVariable);
    return and(axioms,condition);
  }

  private HashMap<String, SemanticType> buildGenericBinding(
      SemanticType[] from, SemanticType[] to) {
    HashMap<String, SemanticType> binding = new HashMap<String, SemanticType>();
    for (int i = 0; i != to.length; ++i) {
      SemanticType.Var v = (SemanticType.Var) from[i];
      binding.put(v.name(), to[i]);
    }
    return binding;
  }

  private Code instantiateAxioms(Code.Load condition, int freeVariable) {
    return Code.Load(condition.type, instantiateAxioms(condition.operands[0], freeVariable), condition.index,
        condition.attributes());
  }

  private void instantiateFromExpression(Code expression, ArrayList<Code> axioms, int freeVariable) {
    if (expression instanceof Code.Variable || expression instanceof Code.Constant) {
      // do nothing
    } else if (expression instanceof Code.Unary) {
      instantiateFromExpression((Code.Unary)expression,axioms, freeVariable);
    } else if (expression instanceof Code.Binary) {
      instantiateFromExpression((Code.Binary)expression,axioms, freeVariable);
    } else if (expression instanceof Code.Nary) {
      instantiateFromExpression((Code.Nary)expression,axioms, freeVariable);
    } else if (expression instanceof Code.Load) {
      instantiateFromExpression((Code.Load)expression,axioms, freeVariable);
    } else if (expression instanceof Code.FunCall) {
      instantiateFromExpression((Code.FunCall)expression,axioms, freeVariable);
    } else {
      internalFailure("invalid expression encountered (" + expression
          + ", " + expression.getClass().getName() + ")", filename, expression);
    }
  }

  private void instantiateFromExpression(Code.Unary expression, ArrayList<Code> axioms, int freeVariable) {
    instantiateFromExpression(expression.operands[0],axioms, freeVariable);

    if(expression.opcode == Code.Op.LENGTH) {
      Code lez = Code.Binary(SemanticType.Int, Code.Op.LTEQ,
          Code.Constant(Value.Integer(BigInteger.ZERO)), expression);
      axioms.add(lez);
    }
  }

  private void instantiateFromExpression(Code.Binary expression, ArrayList<Code> axioms, int freeVariable) {
    instantiateFromExpression(expression.operands[0],axioms, freeVariable);
    instantiateFromExpression(expression.operands[1],axioms, freeVariable);
  }

  private void instantiateFromExpression(Code.Nary expression, ArrayList<Code> axioms, int freeVariable) {
    Code[] e_operands = expression.operands;
    for(int i=0;i!=e_operands.length;++i) {
      instantiateFromExpression(e_operands[i],axioms, freeVariable);
    }
  }

  private void instantiateFromExpression(Code.Load expression, ArrayList<Code> axioms, int freeVariable) {
    instantiateFromExpression(expression.operands[0],axioms, freeVariable);
  }

  private void instantiateFromExpression(Code.FunCall expression, ArrayList<Code> axioms, int freeVariable) {
    instantiateFromExpression(expression.operands[0], axioms, freeVariable);

    try {
      WycsFile module = builder.getModule(expression.nid.module());
      // module should not be null if TypePropagation has already passed.
      WycsFile.Function fn = module.declaration(expression.nid.name(),
          WycsFile.Function.class);
      if (fn.constraint != null) {
        // There are some axioms we can instantiate. First, we need to
        // construct the generic binding for this function.
        HashMap<String, SemanticType> generics = buildGenericBinding(
            fn.type.generics(), expression.type.generics());
        Code axiom = renameToAvoidCapture(fn.constraint,freeVariable);
        HashMap<Integer,Code> binding = new HashMap<Integer,Code>();
        binding.put(1, expression.operands[0]);
        binding.put(0, expression);
        axiom = axiom.substitute(binding).instantiate(
            generics);
        axioms.add(axiom);
      }
    } catch (Exception ex) {
      internalFailure(ex.getMessage(), filename, expression, ex);
    }
  }

  private Code renameToAvoidCapture(Code code, int freeVariable) {
    HashSet<Pair<SemanticType,Integer>> usedVariables = new HashSet();
    findUsedVariables(code,usedVariables);
    return NormalForms.renameVariables(code,freeVariable);
  }

  /**
   * Determine the largest variable index within a given bytecode. This is
   * useful to avoid variable capture when importing axioms.
   *
   * @param condition
   * @return
   */
  private int findLargestVariable(Code condition) {
    if (condition instanceof Code.Variable) {
      // do nothing
      Code.Variable v = (Code.Variable) condition;
      return v.index;
    } else {
      int max = -1;
      for(Code c : condition.operands) {
        max = Math.max(findLargestVariable(c),max);
      }
      return max;
    }
  }

  /**
   * Determine the set of used variables within a given bytecode. This is
   * useful to avoid variable capture when importing axioms.
   *
   * @param condition
   * @return
   */
  private void findUsedVariables(Code condition, HashSet<Pair<SemanticType,Integer>> vars) {
    if (condition instanceof Code.Variable) {
      // do nothing
      Code.Variable v = (Code.Variable) condition;
      vars.add(new Pair<SemanticType,Integer>(v.type,v.index));
    } else {
      for(Code c : condition.operands) {
        findUsedVariables(c,vars);
      }
    }
  }

   private Code and(ArrayList<Code> axioms, Code c) {
    if(axioms.size() == 0) {
      return c;
    } else {
      Code[] clauses = new Code[axioms.size()+1];
      clauses[0] = c;
      for(int i=0;i!=axioms.size();++i) {
        clauses[i+1] = axioms.get(i);
      }
      return Code.Nary(SemanticType.Bool,Code.Op.AND,clauses);
    }
  }

  private Rewriter createRewriter(Automaton automaton) {
    IterativeRewriter.Strategy<InferenceRule> inferenceStrategy;
    IterativeRewriter.Strategy<ReductionRule> reductionStrategy;

    // First, construct a fresh rewriter for this file.
    switch(rwMode) {
    case STATICDISPATCH:
      inferenceStrategy = new UnfairStateRuleRewriteStrategy<InferenceRule>(
          automaton, Solver.inferences,Solver.SCHEMA);
      reductionStrategy = new UnfairStateRuleRewriteStrategy<ReductionRule>(
          automaton, Solver.reductions,Solver.SCHEMA);
      break;
    case GLOBALDISPATCH:
      // NOTE: I don't supply a max steps value here because the
      // default value would be way too small for the simple rewriter.
      inferenceStrategy = new UnfairRuleStateRewriteStrategy<InferenceRule>(
          automaton, Solver.inferences);
      reductionStrategy = new UnfairRuleStateRewriteStrategy<ReductionRule>(
          automaton, Solver.reductions);
      break;
    default:
      // NOTE: I don't supply a max steps value here because the
      // default value would be way too small for the simple rewriter.
      inferenceStrategy = new SimpleRewriteStrategy<InferenceRule>(
          automaton, Solver.inferences);
      reductionStrategy = new SimpleRewriteStrategy<ReductionRule>(
          automaton, Solver.reductions);
      break;
    }

    IterativeRewriter rewriter = new IterativeRewriter(automaton, inferenceStrategy,
        reductionStrategy, Solver.SCHEMA);

    rewriter.setMaxReductionSteps(maxReductions);
    rewriter.setMaxInferenceSteps(maxInferences);

    return rewriter;
  }
}
TOP

Related Classes of wycs.transforms.VerificationCheck

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.