/* * Copyright (C) 2009-2012 University of Freiburg * * This file is part of SMTInterpol. * * SMTInterpol 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. * * SMTInterpol 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 SMTInterpol. If not, see <http://www.gnu.org/licenses/>. */ package de.uni_freiburg.informatik.ultimate.smtinterpol.proof; import java.util.ArrayDeque; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Queue; import java.util.Set; import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.Clause; import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.Literal; import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.ResolutionNode.Antecedent; /** * Collect all units in a proof tree that occur more than once. This is * accomplished by a DAG traversal of the proof tree. If we see a node for the * last time, we visit it (i.e., add it to the unit queue if it is a unit clause * that occurs more than once) and visit the children. * @author Juergen Christ */ public class UnitCollector { /** * The occurrence map. */ private Map<Clause, Integer> mCounts; /** * The collected unit clauses. */ private Queue<Antecedent> mUnits; /** * The todo stack. */ private final Deque<Clause> mTodo = new ArrayDeque<Clause>(); /** * Set of all clauses already visited. */ private HashMap<Clause, Integer> mSeen; /** * Mapping of all root clauses to a set of unit literals. This is needed to * create the map of the deleted nodes per context. */ private HashMap<Clause, Set<Literal>> mDelUnits; /** * Collect all unit clauses that occur more than once in the proof tree * rooted at <code>unsat</code>. * @param unsat Root of the proof tree. * @param counts Clause counters. * @return Unit clauses in bottom-up order. */ public Queue<Antecedent> collectUnits( Clause unsat, Map<Clause, Integer> counts) { mCounts = counts; mDelUnits = new HashMap<Clause, Set<Literal>>(); mUnits = new ArrayDeque<Antecedent>(); mSeen = new HashMap<Clause, Integer>(); mTodo.push(unsat); run(); return mUnits; } /** * Process all clauses in a non-recursive way. */ private void run() { while (!mTodo.isEmpty()) { final Clause cls = mTodo.pop(); if (seen(cls)) { if (cls.getSize() == 1 && mCounts.get(cls) > 1) { // Unit with at least two children mUnits.add(new Antecedent(cls.getLiteral(0), cls)); } final ProofNode pn = cls.getProof(); if (!pn.isLeaf()) { Set<Literal> deletions = null; // Enqueue children final ResolutionNode rn = (ResolutionNode) pn; final Antecedent[] antes = rn.getAntecedents(); for (int i = antes.length - 1; i >= 0; --i) { if (antes[i].mAntecedent.getSize() == 1 && mCounts.get(antes[i].mAntecedent) > 1) { // We will lower this unit => Mark it deleted if (deletions == null) { deletions = new HashSet<Literal>(); } deletions.add(antes[i].mPivot); } mTodo.push(antes[i].mAntecedent); } mTodo.push(rn.getPrimary()); if (deletions != null) { mDelUnits.put(cls, deletions); } } } } } /** * Record that a clause is reached on a path through the DAG. Returns * <code>true</code> if and only if the clause is reached through the last * path in the DAG that can reach this path. * @param cls The clause just reached. * @return Is this clause reached for the last time? */ private boolean seen(Clause cls) { final Integer cnt = mSeen.get(cls); final int newcnt = cnt == null ? 1 : cnt + 1; mSeen.put(cls, newcnt); final int total = mCounts.get(cls); assert (newcnt <= total); return total == newcnt; } /** * Get the list of deleted nodes. This map stores for every result of an * ordered hyper resolution step the literals that occur as units in a * resolution step. * @return Deleted nodes per context. */ public Map<Clause, Set<Literal>> getDeletedNodes() { return mDelUnits; } }