/* * 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.convert; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.cclosure.CCTerm; /** * A DAG for pattern compilers. * @author Juergen Christ */ public class TermDAG { /** * Base class for all nodes in the DAG. This class stores to position of the * term in the registers. * @author Juergen Christ */ public static class TermNode { protected final List<Edge> mIncomming = new ArrayList<Edge>(); protected final List<Edge> mOutgoing = new ArrayList<Edge>(); int mRegPos = -1; public void addIncomming(Edge in) { // NOPMD mIncomming.add(in); } public void addOutgoing(Edge out) { // NOPMD mOutgoing.add(out); } public Iterable<Edge> getIncomming() { return mIncomming; } public Iterable<Edge> getOutgoing() { return mOutgoing; } public void setRegPos(int regPos) { mRegPos = regPos; } public int getRegPos() { return mRegPos; } public boolean isInRegister() { return mRegPos != -1; } public void removeFromRegister() { mRegPos = -1; } } /** * A markable edge from one node to another. The edge also stores to * position of the argument (<code>getTo()</code>) in the function * application (<code>getFrom()</code>). * @author Juergen Christ */ public static final class Edge { boolean mMarked; final TermNode mFrom,mTo; final int mNum; public Edge(TermNode from,TermNode to,int num) { mMarked = false; mFrom = from; mTo = to; mNum = num; from.addOutgoing(this); to.addIncomming(this); } public void mark() { mMarked = true; } public boolean isMarked() { return mMarked; } public int getNumber() { return mNum; } public TermNode getFrom() { return mFrom; } public TermNode getTo() { return mTo; } @Override public String toString() { return mFrom + " --> " + mTo; } } /** * A function application. At least one of the child nodes contains a * variable. * @author Juergen Christ */ public static class AppTermNode extends TermNode { final FunctionSymbol mSymbol; public AppTermNode(FunctionSymbol symbol) { mSymbol = symbol; } public FunctionSymbol getSymbol() { return mSymbol; } public int getChildCount() { assert(mOutgoing.size() == mSymbol.getParameterSorts().length); return mSymbol.getParameterSorts().length; } public void addChild(TermNode child,int pos) { new Edge(this,child,pos); } public Edge getChild(int pos) { final Edge res = mOutgoing.get(pos); if (res.getNumber() != pos) { for (final Edge e : mOutgoing) { if (e.getNumber() == pos) { return e; } } } return res; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append('(').append(mSymbol.getName()); for (final Edge e : mOutgoing) { sb.append(' ').append(e.mTo); } sb.append(')'); return sb.toString(); } } /** * A term that does not contain a variable. This might be any ground term * including function applications to other ground terms. * @author Juergen Christ */ public static class ConstTermNode extends TermNode { final Term mConst; public ConstTermNode(Term constant) { assert(constant.getFreeVars().length == 0); mConst = constant; } public Term getConstant() { return mConst; } @Override public String toString() { return mConst.toString(); } } /** * A variable in the DAG. * @author Juergen Christ */ public static class VarNode extends TermNode { final TermVariable mVar; public VarNode(TermVariable var) { mVar = var; } public TermVariable getVariable() { return mVar; } @Override public String toString() { return mVar.toString(); } } private final LinkedHashSet<TermNode> mRoots; private final ArrayList<ConstTermNode> mConsts; private final ArrayList<VarNode> mVars; private final HashMap<Term, TermNode> mNodes; public TermDAG() { mRoots = new LinkedHashSet<TermNode>(); mConsts = new ArrayList<ConstTermNode>(); mVars = new ArrayList<VarNode>(); mNodes = new HashMap<Term, TermNode>(); } /** * Build the DAG for all given triggers. * @param triggers Input triggers. * @return Term DAG representing the triggers. */ public TermNode[] buildDAG(Term[] triggers) { mRoots.clear(); mConsts.clear(); mVars.clear(); mNodes.clear(); for (final Term trig : triggers) { mRoots.add(insert(trig)); } return mRoots.toArray(new TermNode[mRoots.size()]); } public CCTerm[] getConstants(Clausifier converter) { final CCTerm[] res = new CCTerm[mConsts.size()]; int i = -1; for (final ConstTermNode ctn : mConsts) { res[++i] = converter.getSharedTerm(ctn.getConstant()).getCCTerm(); ctn.setRegPos(i); } return res; } public Iterable<ConstTermNode> getConstants() { return mConsts; } public Iterable<VarNode> getVars() { return mVars; } private TermNode insert(Term trig) { final TermNode cached = mNodes.get(trig); if (cached != null) { return cached; } if (trig.getFreeVars().length == 0) { final ConstTermNode ctn = new ConstTermNode(trig); mConsts.add(ctn); mNodes.put(trig,ctn); return ctn; } else if (trig instanceof TermVariable) { final VarNode vn = new VarNode((TermVariable)trig); mNodes.put(trig,vn); mVars.add(vn); return vn; } else { assert(trig instanceof ApplicationTerm); final ApplicationTerm at = (ApplicationTerm)trig; final AppTermNode atn = new AppTermNode(at.getFunction()); final Term[] params = at.getParameters(); for (int i = 0; i < params.length; ++i) { atn.addChild(insert(params[i]), i); } mNodes.put(trig,atn); return atn; } } }