Package kodkod.engine.fol2sat

Source Code of kodkod.engine.fol2sat.BooleanFormulaFlattener

/*
* Kodkod -- Copyright (c) 2005-2007, Emina Torlak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package kodkod.engine.fol2sat;

import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;

import kodkod.engine.bool.BooleanAccumulator;
import kodkod.engine.bool.BooleanFactory;
import kodkod.engine.bool.BooleanFormula;
import kodkod.engine.bool.BooleanValue;
import kodkod.engine.bool.BooleanVariable;
import kodkod.engine.bool.BooleanVisitor;
import kodkod.engine.bool.ITEGate;
import kodkod.engine.bool.MultiGate;
import kodkod.engine.bool.NotGate;
import kodkod.engine.bool.Operator;
import kodkod.util.ints.IntSet;
import kodkod.util.ints.Ints;

/**
* <p>Given a {@link kodkod.engine.bool.BooleanValue boolean value}, v, and a
* {@link kodkod.engine.bool.BooleanFactory factory}, F,
* a BooleanFormulaFlattener eliminates as many
* intermediate gates as possible from v, and stores the flattened tree of v in F. 
* An intermediate gate's inputs are absorbed into the parent's iff the
* the gate's fanout is 1 and the gate and its parent are MultiGates with the same operator. 
* For example, suppose that the root corresponds to the formula
* ((1 || 2) || 3 || !(4 || 5) || (6 & (7 & 8))), and that the components of this formula are
* assigned the following labels:  (1 || 2) ---> 9, (4 || 5) ---> 10, !(4 || 5) ---> -10, (7 & 8) ---> 11,
* (6 & (7 & 8)) ---> 12, and ((1 || 2) || 3 || !(4 || 5) || (6 & 7 & 8)) ---> 13. 
* Calling this.flatten(root) will flatten the root to (1 || 2 || 3 || !(4 || 5) || (6 & 7 & 8)),
* re-assigning the labels as follows: (4 || 5) ---> 9, !(4 || 5) ---> -9, (6 & 7 & 8) ---> 10, and
* (1 || 2 || 3 || !(4 || 5) || (6 & 7 & 8)) ---> 11. 
*
* @author Emina Torlak
*/
final class BooleanFormulaFlattener implements BooleanVisitor<BooleanValue, BooleanAccumulator> {



  /**
   * Flattens the given value using f and returns it.
   * The method assumes that all variables at the leaves of
   * the root are components of f.
   * @requires root.*inputs in f.components
   * @effects f.components' = f.components & Variable + flatRoot.*inputs
   * @return {flatRoot : BooleanValue | [[flatRoot]] = [[root]] &&
   *           no d, p: flatRoot.*inputs & MultiGate | d in p.inputs && d.op = p.op && inputs.d != p } 
   */
  static final BooleanValue flatten(BooleanFormula root, BooleanFactory f) {
    final int oldCompDepth = f.comparisonDepth();
    f.setComparisonDepth(1);
    f.clear(); // remove everything but the variables from the factory
    final BooleanFormulaFlattener flattener = new BooleanFormulaFlattener(root, f);
    final BooleanValue flatRoot = root.accept(flattener, null);
    f.setComparisonDepth(oldCompDepth);
    return flatRoot;
  }

  private final BooleanFactory factory;
  private final IntSet flattenable;
  private final Map<MultiGate,BooleanValue> cache;

  /**
   * Constructs a new FlatteningVisitor.  The returned visitor can only be applied to the specified
   * root value.  All the variables at the leaves of the given root must have been created by the
   * given factory.
   * @requires (root.*inputs & Variable) in factory.components
   */
  private BooleanFormulaFlattener(BooleanFormula root, BooleanFactory factory) {
    this.factory = factory;
    final FlatteningDataGatherer dataGatherer = new FlatteningDataGatherer(root);
    root.accept(dataGatherer, null);
    this.flattenable = dataGatherer.flattenable;
    dataGatherer.visited.removeAll(flattenable);
    this.cache = new IdentityHashMap<MultiGate,BooleanValue>(dataGatherer.visited.size());
  }

  /**
   * If p is null, returns v.  Otherwise, adds v to p and
   * returns the result.
   */
  private final BooleanValue addToParent(BooleanValue v, BooleanAccumulator parent) {
    return parent==null ? v : parent.add(v);
  }

  /**
   * Flattens the given multigate into its parent, if they have the multigate is not shared
   * and it has the same operator as the parent.
   * @return flattened gate
   * @see kodkod.engine.bool.BooleanVisitor#visit(kodkod.engine.bool.MultiGate, java.lang.Object)
   */
  public BooleanValue visit(MultiGate multigate, BooleanAccumulator parent) {
    final Operator.Nary op = multigate.op();
    if (flattenable.contains(multigate.label())) { // multigate's inputs are absorbed into its parent's inputs
//      System.out.println("Flattenable: " + multigate);
      for(Iterator<BooleanFormula> inputs = multigate.iterator(); inputs.hasNext();) {
        if (inputs.next().accept(this, parent)==op.shortCircuit())
          return op.shortCircuit();
      }
      return parent;
    } else { // construct a gate that corresponds to the multigate
//      System.out.println("Unflattenable: " + multigate);
      BooleanValue replacement = cache.get(multigate);

      if (replacement == null) {
        final BooleanAccumulator newGate = BooleanAccumulator.treeGate(op);
        for(Iterator<BooleanFormula> inputs = multigate.iterator(); inputs.hasNext();) {
          if (inputs.next().accept(this,newGate)==op.shortCircuit()) {
            return op.shortCircuit();
          }
        }
        replacement = factory.accumulate(newGate);
        cache.put(multigate, replacement);
      }

      return addToParent(replacement, parent);
    }
  }

  /**
   * Returns the ite gate.
   * @return itegate
   * @see kodkod.engine.bool.BooleanVisitor#visit(kodkod.engine.bool.ITEGate, java.lang.Object)
   */
  public BooleanValue visit(ITEGate itegate, BooleanAccumulator parent) {
    return addToParent(factory.ite(itegate.input(0).accept(this,null), itegate.input(1).accept(this,null),
        itegate.input(2).accept(this,null)), parent);
  }

  /**
   * Returns the not gate.
   * @return negation
   * @see kodkod.engine.bool.BooleanVisitor#visit(kodkod.engine.bool.NotGate, java.lang.Object)
   */
  public BooleanValue visit(NotGate negation, BooleanAccumulator parent) {
    return addToParent(factory.not(negation.input(0).accept(this,null)), parent);
  }

  /**
   * Returns the variable.
   * @see kodkod.engine.bool.BooleanVisitor#visit(kodkod.engine.bool.BooleanVariable, java.lang.Object)
   */
  public BooleanValue visit(BooleanVariable variable, BooleanAccumulator parent) {
    return addToParent(variable, parent);
  }
 

 
  /**
   * A visitor that determins which gates can be flattened.  Specifically, when
   * applied to a given root, the flattenable field of the visitor contains the
   * labels of all m such that m is a MultiGate descendent of the root and
   * #inputs.m = 1 && (inputs.m).op = m.op => s.contains(m.label).  That is,
   * flattenable = {i: int | some m: root.^inputs & MultiGate | #inputs.m = 1 && (inputs.m).op = m.op && m.label = i}
   */
  private static final class FlatteningDataGatherer implements BooleanVisitor<Object, Operator> {
    /* contains the labels of all the flattenable multi gates */
    final IntSet flattenable;
    /* contains the labels of all the visited multi gates */
    final IntSet visited;

    /**
     * Constructs a new flattenning data gatherer.   The returned visitor can only be
     * applied to the specified root value.
     */
    private FlatteningDataGatherer(BooleanFormula root) {
      final int maxLit = StrictMath.abs(root.label());
      this.flattenable = Ints.bestSet(maxLit+1);
      this.visited = Ints.bestSet(maxLit+1);
    }

    public Object visit(MultiGate multigate, Operator parentOp) {
      final int label = multigate.label();
      if (visited.contains(label)) { // we've seen this node already
        flattenable.remove(label);
      } else { // haven't seen it yet
        visited.add(label);
        if (parentOp == multigate.op()) flattenable.add(label);
        // visit children
        for(Iterator<BooleanFormula> inputs = multigate.iterator(); inputs.hasNext();) {
          inputs.next().accept(this, multigate.op());
        }
      }

      return null;
    }

    public Object visit(ITEGate itegate, Operator parentOp) {
      if (visited.add(itegate.label())) { // not visited
        itegate.input(0).accept(this,null);
        itegate.input(1).accept(this,null);
        itegate.input(2).accept(this,null);
      }
      return null;
    }

    public Object visit(NotGate negation, Operator parentOp) {
      negation.input(0).accept(this,null);
      return null;
    }

    public Object visit(BooleanVariable variable, Operator arg) {
      return null;
    }
   

  }
}
TOP

Related Classes of kodkod.engine.fol2sat.BooleanFormulaFlattener

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.
yTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');