/** * Copyright (c) 2012-2016 Marsha Chechik, Alessio Di Sandro, Michalis Famelis, * Rick Salay. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Alessio Di Sandro - Implementation. */ package edu.toronto.cs.se.modelepedia.z3.mavo; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.IStatus; import org.eclipse.jdt.annotation.NonNull; import com.microsoft.z3.Expr; import com.microsoft.z3.FuncDecl; import com.microsoft.z3.FuncInterp; import com.microsoft.z3.FuncInterp.Entry; import com.microsoft.z3.Model; import com.microsoft.z3.Sort; import com.microsoft.z3.Z3Exception; import edu.toronto.cs.se.mavo.MAVOElement; import edu.toronto.cs.se.mmint.MMINTException; import edu.toronto.cs.se.modelepedia.z3.Z3Model; import edu.toronto.cs.se.modelepedia.z3.Z3Utils; public class Z3MAVOModelParser { private String smtEncoding; private String smtEncodingUri; private Map<Integer, String> smtEncodingNodes; private Map<Integer, String> smtEncodingEdges; private Map<Integer, String> smtEncodingElems; private String smtMacros; private Map<String, MAVOElement> mavoModelObjs; private boolean isMayOnly; public Z3MAVOModelParser(@NonNull String smtEncoding, @NonNull String smtEncodingUri, @NonNull Map<Integer, String> smtEncodingNodes, @NonNull Map<Integer, String> smtEncodingEdges, @NonNull String smtMacros, @NonNull Map<String, MAVOElement> mavoModelObjs, boolean isMayOnly) { this.smtEncoding = smtEncoding; this.smtEncodingUri = smtEncodingUri; this.smtEncodingNodes = smtEncodingNodes; this.smtEncodingEdges = smtEncodingEdges; smtEncodingElems = new HashMap<>(); smtEncodingElems.putAll(smtEncodingNodes); smtEncodingElems.putAll(smtEncodingEdges); this.smtMacros = smtMacros; this.mavoModelObjs = mavoModelObjs; this.isMayOnly = isMayOnly; } public @NonNull String getSMTLIBEncoding() { return smtEncoding; } public @NonNull String getSMTLIBEncodingUri() { return smtEncodingUri; } public @NonNull String getSMTLIBMacros() { return smtMacros; } private @NonNull Map<String, Set<String>> getZ3MAVOModelObjs(@NonNull Model z3InternalModel, @NonNull String z3FunctionName, @NonNull Map<Integer, String> smtEncodingCurrentElems) { Map<String, Set<String>> z3ModelObjs = new HashMap<>(); try { for (FuncDecl decl : z3InternalModel.getFuncDecls()) { // filter function String declName = decl.getName().toString(); int subfuncIndex = declName.indexOf(Z3Utils.Z3_MODEL_SEPARATOR); if (subfuncIndex != -1) { declName = declName.substring(0, subfuncIndex); } if (!z3FunctionName.equals(declName)) { continue; } FuncInterp interp = z3InternalModel.getFuncInterp(decl); Boolean elseValue = (interp.getElse().toString().equals("true") || interp.getElse().toString().equals("false")) ? Boolean.valueOf(interp.getElse().toString()) : null; if (elseValue == null) { // function that calls another function continue; } // parse entries if (elseValue) { // entries are false, else is true (includes all true function) if (isMayOnly) { Map<String, Set<String>> funcZ3ModelObjs = new HashMap<>(); for (Map.Entry<Integer, String> smtEncodingElem : smtEncodingCurrentElems.entrySet()) { Set<String> formulaVars = new HashSet<>(1); formulaVars.add(smtEncodingElem.getValue()); funcZ3ModelObjs.put(smtEncodingElem.getKey().toString(), formulaVars); } // remove false entries for (Entry entry : interp.getEntries()) { funcZ3ModelObjs.remove(entry.getArgs()[0].toString()); } // add remaining z3ModelObjs.putAll(funcZ3ModelObjs); } else { // create cartesian product of universeIds and integerIds Sort sort = decl.getDomain()[1]; Set<String> z3UniverseIds = new HashSet<>(); for (Expr z3UniverseId : z3InternalModel.getSortUniverse(sort)) { z3UniverseIds.add(z3UniverseId.toString()); } Set<Integer> z3IntegerIds = new HashSet<>(); for (Map.Entry<Integer, String> smtEncodingElem : smtEncodingCurrentElems.entrySet()) { MAVOElement mavoModelObj = mavoModelObjs.get(smtEncodingElem.getValue()); if (!mavoModelObj.eClass().getName().equals(sort.toString())) { continue; } z3IntegerIds.add(smtEncodingElem.getKey()); } Map<String, Set<Integer>> funcZ3ModelObjs = new HashMap<>(); for (String z3UniverseId : z3UniverseIds) { funcZ3ModelObjs.put(z3UniverseId, new HashSet<>(z3IntegerIds)); } // remove false entries for (Entry entry : interp.getEntries()) { funcZ3ModelObjs.get(entry.getArgs()[1].toString()).remove(Integer.valueOf(entry.getArgs()[0].toString())); } // add remaining for (Map.Entry<String, Set<Integer>> funcZ3ModelObj : funcZ3ModelObjs.entrySet()) { Set<String> formulaVars = new HashSet<>(); z3ModelObjs.put(funcZ3ModelObj.getKey(), formulaVars); for (Integer z3IntegerId : funcZ3ModelObj.getValue()) { formulaVars.add(smtEncodingCurrentElems.get(z3IntegerId)); } } } } else { // entries are true, else is false (includes all false function) for (Entry entry : interp.getEntries()) { int z3IdIndex = (isMayOnly) ? 0 : 1; String z3Id = entry.getArgs()[z3IdIndex].toString(); Set<String> formulaVars = z3ModelObjs.get(z3Id); if (formulaVars == null) { formulaVars = new HashSet<>(); z3ModelObjs.put(z3Id, formulaVars); } Integer z3IntegerId = new Integer(entry.getArgs()[0].toString()); formulaVars.add(smtEncodingCurrentElems.get(z3IntegerId)); } } } } catch (Z3Exception e) { MMINTException.print(IStatus.WARNING, "Can't parse Z3 model elements, returning elements so far (possibly none)", e); } return z3ModelObjs; } public @NonNull Map<String, Set<String>> getZ3MAVOModelNodes(@NonNull Z3Model z3Model) { return getZ3MAVOModelObjs(z3Model.getZ3InternalModel(), Z3Utils.SMTLIB_NODE, smtEncodingNodes); } public @NonNull Map<String, Set<String>> getZ3MAVOModelEdges(@NonNull Z3Model z3Model) { return getZ3MAVOModelObjs(z3Model.getZ3InternalModel(), Z3Utils.SMTLIB_EDGE, smtEncodingEdges); } /** * Gets a map from Z3 model objects (a simple Z3 integer id for may only, a * Z3 universe id for full mavo) to their formula variable (multiple formula * variables in case of merged Var model objects), for elements of a Z3 * model that represents a MAVO model concretization: * M: 1 Z3 integerId/universeId to 1 formula var, or nothing * S: x Z3 universeIds to 1 formula var * V: 1 Z3 universeId to x formula vars * * @param z3Model * The Z3 model that represents a MAVO model concretization. * @return The Z3 model objects to formula variables map. */ public @NonNull Map<String, Set<String>> getZ3MAVOModelObjects(@NonNull Z3Model z3Model) { Map<String, Set<String>> z3ModelObjs = new HashMap<>(); z3ModelObjs.putAll(getZ3MAVOModelObjs(z3Model.getZ3InternalModel(), Z3Utils.SMTLIB_NODE, smtEncodingNodes)); z3ModelObjs.putAll(getZ3MAVOModelObjs(z3Model.getZ3InternalModel(), Z3Utils.SMTLIB_EDGE, smtEncodingEdges)); return z3ModelObjs; } public boolean isMayOnly() { return isMayOnly; } public boolean isAnnotated() { return mavoModelObjs.values().stream() .anyMatch(mavoModelObj -> mavoModelObj.isMay() || mavoModelObj.isSet() || mavoModelObj.isVar()); } }