/* * 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.model; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm; import de.uni_freiburg.informatik.ultimate.logic.FormulaUnLet; import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol; import de.uni_freiburg.informatik.ultimate.logic.Rational; import de.uni_freiburg.informatik.ultimate.logic.Sort; import de.uni_freiburg.informatik.ultimate.logic.Term; import de.uni_freiburg.informatik.ultimate.logic.TermVariable; import de.uni_freiburg.informatik.ultimate.logic.Theory; import de.uni_freiburg.informatik.ultimate.smtinterpol.LogProxy; import de.uni_freiburg.informatik.ultimate.smtinterpol.convert.Clausifier; import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.BooleanVarAtom; import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.ITheory; import de.uni_freiburg.informatik.ultimate.smtinterpol.model.FunctionValue.Index; import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.cclosure.ArrayTheory; import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.cclosure.CClosure; import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.linar.LinArSolve; /** * A model represented as injection between integers and domain values. The * integers should be positive. Furthermore, the model reserves <code>-1</code> * for undefined values, <code>0</code> for the default value, and * <code>1</code> for the second value. * @author Juergen Christ */ public class Model implements de.uni_freiburg.informatik.ultimate.logic.Model { private final HashMap<Sort, SortInterpretation> mSorts = new HashMap<Sort, SortInterpretation>(); private final HashMap<Sort, ArraySortInterpretation> mArraySorts = new HashMap<Sort, ArraySortInterpretation>(); private final BoolSortInterpretation mBoolSort; private final NumericSortInterpretation mNumSorts; private final HashMap<FunctionSymbol, FunctionValue> mFuncVals = new HashMap<FunctionSymbol, FunctionValue>(); private final Theory mTheory; private final ModelEvaluator mEval; private final FormulaUnLet mUnlet = new FormulaUnLet( FormulaUnLet.UnletType.EXPAND_DEFINITIONS); private final boolean mPartialModel; public Model(Clausifier clausifier, Theory t, boolean partial) { mTheory = t; mPartialModel = partial; mBoolSort = new BoolSortInterpretation(); mNumSorts = new NumericSortInterpretation(); // Extract Boolean model final FunctionValue trueValue = new FunctionValue(mBoolSort.getTrueIdx()); final FunctionValue falseValue = new FunctionValue(mBoolSort.getFalseIdx()); for (final BooleanVarAtom atom : clausifier.getBooleanVars()) { final ApplicationTerm at = (ApplicationTerm) atom.getSMTFormula(t); FunctionValue value; if (atom.getDecideStatus() == null) { value = atom.getPreferredStatus() == atom ? trueValue : falseValue; } else { value = atom.getDecideStatus() == atom ? trueValue : falseValue; } mFuncVals.put(at.getFunction(), value); } // Extract different theories final CClosure cc = clausifier.getCClosure(); LinArSolve la = null; ArrayTheory array = null; for (final ITheory theory : clausifier.getEngine().getAttachedTheories()) { if (theory instanceof LinArSolve) { la = (LinArSolve) theory; } else if (theory instanceof ArrayTheory) { array = (ArrayTheory) theory; } else if (theory != cc) { throw new InternalError( "Modelproduction for theory not implemented: " + theory); } } final SharedTermEvaluator ste = new SharedTermEvaluator(la); if (la != null) { la.fillInModel(this, t, ste); } if (cc != null) { cc.fillInModel(this, t, ste); } if (array != null) { array.fillInModel(this, t, ste); } if (!partial) { for (final FunctionSymbol fs : t.getDeclaredFunctions().values()) { if (!fs.isIntern() && !mFuncVals.containsKey(fs)) { final SortInterpretation si = provideSortInterpretation(fs.getReturnSort()); // ensure the sort is inhabited si.ensureCapacity(1); map(fs, 0); } } } mEval = new ModelEvaluator(this); } public boolean checkTypeValues(LogProxy logger) { boolean correct = true; for (final Map.Entry<FunctionSymbol, FunctionValue> me : mFuncVals.entrySet()) { final FunctionSymbol fs = me.getKey(); if (fs.getReturnSort().getName().equals("Int")) { if (!mNumSorts.get(me.getValue().getDefault()).isIntegral()) { correct = false; if (fs.getParameterSorts().length == 0) { logger.fatal("Non-integral value for integer variable " + fs); } else { logger.fatal("Non-integral default value for function " + fs); } } for (final Map.Entry<Index,Integer> val : me.getValue().values().entrySet()) { if (!mNumSorts.get(val.getValue()).isIntegral()) { correct = false; logger.fatal("Non-integral value for function " + fs + " at index " + me.getKey()); } } } } return correct; } public int getFalseIdx() { return mBoolSort.getFalseIdx(); } public int getTrueIdx() { return mBoolSort.getTrueIdx(); } public int extendNumeric(FunctionSymbol fsym, Rational rat) { assert fsym.getReturnSort().isNumericSort(); assert !fsym.getReturnSort().getName().equals("Int") || rat.isIntegral(); final int idx = mNumSorts.extend(rat); mFuncVals.put(fsym, new FunctionValue(idx)); return idx; } public int putNumeric(Rational rat) { return mNumSorts.extend(rat); } public int extendFresh(Sort s) { if (s.isArraySort()) { ArraySortInterpretation si = mArraySorts.get(s); if (si == null) { si = new ArraySortInterpretation( provideSortInterpretation(s.getArguments()[0]), provideSortInterpretation(s.getArguments()[1])); mArraySorts.put(s, si); } return si.extendFresh(); } SortInterpretation si = mSorts.get(s); if (si == null) { si = new FiniteSortInterpretation(); mSorts.put(s, si); } return si.extendFresh(); } public Set<FunctionSymbol> getDefinedFunctions() { return Collections.unmodifiableSet(mFuncVals.keySet()); } Term index2Term(Index index, TermVariable[] vars) { final int[] idx = index.getArray(); assert vars.length == idx.length; final Term[] conj = new Term[vars.length]; for (int i = 0; i < vars.length; ++i) { conj[i] = mTheory.equals(vars[i], toModelTerm(idx[i], vars[i].getSort())); } return mTheory.and(conj); } public Term getFunctionDefinition(FunctionSymbol fs, TermVariable[] vars) { FunctionValue value = mFuncVals.get(fs); if (value == null) throw new IllegalArgumentException("No model for "+fs); if (fs.getParameterSorts().length != vars.length) throw new IllegalArgumentException("Wrong number of variables"); final int defaultVal = value.getDefault(); Sort resultSort = fs.getReturnSort(); Term definition = toModelTerm(defaultVal, resultSort); for (final Entry<Index, Integer> me : value.values().entrySet()) { if (me.getValue() != defaultVal) { Term cond = index2Term(me.getKey(), vars); Term val = toModelTerm(me.getValue(), resultSort); definition = mTheory.ifthenelse(cond, val, definition); } } return definition; } public Term getFunctionDefinition(String func, TermVariable[] args) { Sort[] argTypes = new Sort[args.length]; for (int i = 0; i < args.length; i++) { argTypes[i] = args[i].getSort(); } FunctionSymbol fs = mTheory.getFunction(func, argTypes); if (fs == null) throw new IllegalArgumentException ("Function "+func+" not defined."); return getFunctionDefinition(fs, args); } public FunctionValue map(FunctionSymbol fs, int value) { FunctionValue res = mFuncVals.get(fs); if (res == null) { res = new FunctionValue(value); mFuncVals.put(fs, res); } assert res.getDefault() == value; return res; } public FunctionValue map(FunctionSymbol fs, int[] args, int value) { assert fs.getParameterSorts().length == args.length; FunctionValue val = mFuncVals.get(fs); if (val == null) { val = new FunctionValue(); mFuncVals.put(fs, val); } val.put(value, args); return val; } Term getUndefined(Sort s) { final FunctionSymbol fsym = mTheory.getFunctionWithResult( "@undefined", null, s); return mTheory.term(fsym); } @Override public Term evaluate(Term input) { final Term unletted = mUnlet.unlet(input); return mEval.evaluate(unletted); } @Override public Map<Term, Term> evaluate(Term[] input) { final LinkedHashMap<Term, Term> values = new LinkedHashMap<Term, Term>(); for (final Term t : input) { values.put(t, evaluate(t)); } return values; } @Override public String toString() { final ModelFormatter mf = new ModelFormatter(mTheory, this); // if (!mSorts.isEmpty()) // mf.appendComment("Sort interpretations"); // for (Map.Entry<Sort, SortInterpretation> me : mSorts.entrySet()) // mf.appendSortInterpretation(me.getValue(), me.getKey()); // // Only if we printed ";; Sort interpretations" we should print the // // delimiting comment ";; Function interpretations" // if (!mSorts.isEmpty()) // mf.appendComment("Function interpretations"); for (final Map.Entry<FunctionSymbol, FunctionValue> me : mFuncVals.entrySet()) { if (!me.getKey().isIntern()) { mf.appendValue(me.getKey(), me.getValue(), mTheory); } } return mf.finish(); } Theory getTheory() { return mTheory; } public boolean isPartialModel() { return mPartialModel; } public BoolSortInterpretation getBoolSortInterpretation() { return mBoolSort; } public NumericSortInterpretation getNumericSortInterpretation() { return mNumSorts; } public SortInterpretation provideSortInterpretation(Sort sort) { if (sort.isNumericSort()) { return mNumSorts; } if (sort == mTheory.getBooleanSort()) { return mBoolSort; } if (sort.isArraySort()) { ArraySortInterpretation array = mArraySorts.get(sort); if (array == null) { array = new ArraySortInterpretation( provideSortInterpretation(sort.getArguments()[0]), provideSortInterpretation(sort.getArguments()[1])); mArraySorts.put(sort, array); } return array; } SortInterpretation res = mSorts.get(sort); if (res == null) { res = new FiniteSortInterpretation(); mSorts.put(sort, res); } return res; } public FunctionValue getFunctionValue(FunctionSymbol fs) { return mFuncVals.get(fs); } public Term toModelTerm(int idx, Sort resultSort) { if (idx == -1) { return getUndefined(resultSort); } if (resultSort == mTheory.getBooleanSort()) { return mBoolSort.get(idx, resultSort, mTheory); } if (resultSort.isNumericSort()) { final Rational val = mNumSorts.get(idx); return val.toTerm(resultSort); } if (resultSort.isArraySort()) { ArraySortInterpretation array = mArraySorts.get(resultSort); if (array == null) { if (mPartialModel) { return getUndefined(resultSort); } array = new ArraySortInterpretation( provideSortInterpretation(resultSort.getArguments()[0]), provideSortInterpretation(resultSort.getArguments()[1])); mArraySorts.put(resultSort, array); } return array.get(idx, resultSort, mTheory); } SortInterpretation si = mSorts.get(resultSort); if (si == null) { if (mPartialModel) { return getUndefined(resultSort); } si = new FiniteSortInterpretation(); si.ensureCapacity(idx + 1); } return si.get(idx, resultSort, mTheory); } public ArraySortInterpretation getArrayInterpretation(Sort arraySort) { // FIXME might not exist return mArraySorts.get(arraySort); } }