/** * 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.operator.henshin; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.henshin.interpreter.EGraph; import org.eclipse.emf.henshin.interpreter.Engine; import org.eclipse.emf.henshin.interpreter.Match; import org.eclipse.emf.henshin.interpreter.RuleApplication; import org.eclipse.emf.henshin.interpreter.impl.EGraphImpl; import org.eclipse.emf.henshin.interpreter.impl.EngineImpl; import org.eclipse.emf.henshin.interpreter.impl.RuleApplicationImpl; import org.eclipse.emf.henshin.interpreter.util.InterpreterUtil; import org.eclipse.emf.henshin.model.Module; import org.eclipse.emf.henshin.model.Node; import org.eclipse.emf.henshin.model.Rule; import org.eclipse.emf.henshin.model.resource.HenshinResourceSet; import org.eclipse.emf.henshin.trace.Trace; import edu.toronto.cs.se.mavo.MAVOElement; import edu.toronto.cs.se.mmint.MMINTException; import edu.toronto.cs.se.mmint.MIDTypeHierarchy; import edu.toronto.cs.se.mmint.MIDTypeRegistry; import edu.toronto.cs.se.mmint.mid.GenericElement; import edu.toronto.cs.se.mmint.mid.MID; import edu.toronto.cs.se.mmint.mid.Model; import edu.toronto.cs.se.mmint.mid.relationship.BinaryModelRel; import edu.toronto.cs.se.mmint.mid.utils.FileUtils; import edu.toronto.cs.se.mmint.mid.utils.MIDOperatorIOUtils; import edu.toronto.cs.se.modelepedia.z3.Z3IncrementalSolver; import edu.toronto.cs.se.modelepedia.z3.Z3Utils; public class MAVOHenshinTransformation extends LiftingHenshinTransformation { private static final String A_MODELOBJECT_SMTENCODING_PREFIX = "a"; private static final String SMTLIB_APPLICABILITY_PREAMBLE = "(declare-fun fN (Int) Bool) (declare-fun fC (Int) Bool) (declare-fun fD (Int) Bool) (declare-fun fA (Int) Bool) (declare-fun fDo (Int) Bool) (declare-fun fAo (Int) Bool) (declare-fun fY (Int) Bool) (assert (forall ((i Int)) (= (fY i) (and (not (fN i)) (fC i) (fD i))))) (declare-fun fX (Int) Bool) (assert (forall ((i Int)) (= (fX i) (ite (= i 0)"; private static final String SMTLIB_APPLICABILITY_POSTAMBLE = "(or (and (fX (- i 1)) (not (fY i)) (not (fAo i))) (and (and (fX (- i 1)) (fY i)) (not (fDo i)) (fA i)))))))"; private static final String SMTLIB_APPLICABILITY_FUN_D_OR = SMTLIB_APPLICABILITY_FUN + "Do "; private static final String SMTLIB_APPLICABILITY_FUN_A_OR = SMTLIB_APPLICABILITY_FUN + "Ao "; @Override protected void transformModelObjAWhenLifted(MAVOElement modelObjA) { modelObjA.setMay(true); } @Override protected void transformModelObjA(MAVOElement modelObjA) { modelObjA.setFormulaVariable(A_MODELOBJECT_SMTENCODING_PREFIX + modelObjACounter); } private void createZ3ApplyFormulaConstant(Set<MAVOElement> mavoModelObjs) { for (MAVOElement mavoModelObj : mavoModelObjs) { if (smtEncodingVariables.contains(mavoModelObj.getFormulaVariable())) { continue; } smtEncoding.append(Z3Utils.constant(mavoModelObj.getFormulaVariable(), Z3Utils.SMTLIB_TYPE_BOOL)); } } private void createZ3ApplyFormulaConstants() { Set<MAVOElement> uniqueMayModelObjsN = new HashSet<MAVOElement>(); for (Set<MAVOElement> mayModelObjsN : modelObjsNBar) { uniqueMayModelObjsN.addAll(mayModelObjsN); } createZ3ApplyFormulaConstant(uniqueMayModelObjsN); createZ3ApplyFormulaConstant(modelObjsC); createZ3ApplyFormulaConstant(modelObjsD); } @Override protected void createZ3ApplyFormula() { createZ3ApplyFormulaConstants(); createZ3ApplyFormulaMatchSetNIteration(); createZ3ApplyFormulaMatchSetIteration(modelObjsC, SMTLIB_APPLICABILITY_FUN_C, Z3Utils.SMTLIB_AND, Z3Utils.SMTLIB_TRUE); createZ3ApplyFormulaMatchSetIteration(modelObjsD, SMTLIB_APPLICABILITY_FUN_D, Z3Utils.SMTLIB_AND, Z3Utils.SMTLIB_TRUE); createZ3ApplyFormulaMatchSetIteration(modelObjsD, SMTLIB_APPLICABILITY_FUN_D_OR, Z3Utils.SMTLIB_OR, Z3Utils.SMTLIB_FALSE); } @Override protected void updateLiterals() { // do nothing } @Override protected void getMatchedModelObjs(Match match, Set<Node> nodes, Set<MAVOElement> modelObjs, Set<MAVOElement> allModelObjs) { for (Node node : nodes) { EObject nodeTarget = match.getNodeTarget(node); if (nodeTarget instanceof MAVOElement) { allModelObjs.add((MAVOElement) nodeTarget); if (((MAVOElement) nodeTarget).isMay()) { modelObjs.add((MAVOElement) nodeTarget); } } } } private TransformationApplicabilityCondition checkApplicabilityConditions(Rule rule, Engine engine, EGraph graph, Z3IncrementalSolver z3IncSolver, int checkpointA) { for (int i = 0; i < rule.getLhs().getNACs().size(); i++) { // one Nac at a time Rule ruleCopyN = EcoreUtil.copy(rule); Set<Node> nodesN = new LinkedHashSet<Node>(), nodesC = new LinkedHashSet<Node>(), nodesD = new LinkedHashSet<Node>(); List<Match> matchesN = findNMatches(ruleCopyN, engine, graph, i, nodesC, nodesD, nodesN); matchesN: for (int j = 0; j < matchesN.size(); j++) { modelObjsNBar.clear(); modelObjsC.clear(); modelObjsD.clear(); modelObjsCDN.clear(); Match matchNj = matchesN.get(j); boolean isLiftedMatchNBar = addNBarModelObjs(matchNj, nodesN); if (!isLiftedMatchNBar) { continue; } getMatchedModelObjs(matchNj, nodesC, modelObjsC, modelObjsCDN); getMatchedModelObjs(matchNj, nodesD, modelObjsD, modelObjsCDN); for (int k = 0; k < matchesN.size(); k++) { // same Nac for NBar if (j == k) { continue; } Match matchNk = matchesN.get(k); if (!areMatchesOverlapping(matchNj, matchNk, nodesC, nodesC, nodesD, nodesD)) { continue; } isLiftedMatchNBar = addNBarModelObjs(matchNk, nodesN); if (!isLiftedMatchNBar) { continue matchesN; } } for (int l = 0; l < rule.getLhs().getNACs().size(); l++) { // other Nacs for NBar if (l == i) { continue; } Set<Node> nodesNl = new LinkedHashSet<Node>(), nodesCl = new LinkedHashSet<Node>(), nodesDl = new LinkedHashSet<Node>(); List<Match> matchesNl = findNMatches(EcoreUtil.copy(rule), engine, graph, l, nodesCl, nodesDl, nodesNl); for (int m = 0; m < matchesNl.size(); m++) { Match matchNm = matchesNl.get(m); if (!areMatchesOverlapping(matchNj, matchNm, nodesC, nodesCl, nodesD, nodesDl)) { continue; } isLiftedMatchNBar = addNBarModelObjs(matchNm, nodesNl); if (!isLiftedMatchNBar) { continue matchesN; } } } // check apply formula if (checkZ3ApplicabilityFormula(z3IncSolver, checkpointA)) { return new TransformationApplicabilityCondition(ruleCopyN, matchNj, true); // <NBar,C,D> may match } } } // no Nac matched Rule ruleCopy = EcoreUtil.copy(rule); Set<Node> nodesC = new HashSet<Node>(), nodesD = new HashSet<Node>(); getCDNodes(ruleCopy, nodesC, nodesD); boolean isLiftedMatch = false; List<Match> matches = InterpreterUtil.findAllMatches(engine, ruleCopy, graph, null); for (int i = 0; i < matches.size(); i++) { modelObjsNBar.clear(); modelObjsC.clear(); modelObjsD.clear(); modelObjsCDN.clear(); Match match = matches.get(i); getMatchedModelObjs(match, nodesC, modelObjsC, modelObjsCDN); getMatchedModelObjs(match, nodesD, modelObjsD, modelObjsCDN); isLiftedMatch |= (modelObjsC.size() > 0); isLiftedMatch |= (modelObjsD.size() > 0); if (isLiftedMatch) { // check apply formula if (checkZ3ApplicabilityFormula(z3IncSolver, checkpointA)) { return new TransformationApplicabilityCondition(ruleCopy, match, true); // <C,D> may match } } else { return new TransformationApplicabilityCondition(ruleCopy, match, false); // <C,D> classical match } } return null; // no matches } @Override protected int matchAndTransformLifting(Rule rule, Engine engine, EGraph graph, Z3IncrementalSolver z3IncSolver, int checkpointA) { RuleApplication application = new RuleApplicationImpl(engine); TransformationApplicabilityCondition condition; while ((condition = checkApplicabilityConditions(rule, engine, graph, z3IncSolver, checkpointA)) != null) { application.setRule(condition.getMatchedRule()); application.setEGraph(graph); // transform modelObjsA.clear(); transformLifting(application, condition.getMatch(), condition.isLiftedMatch()); if (condition.isLiftedMatch()) { // update encoding checkpointA = smtEncoding.length(); createZ3ApplyFormulaConstant(modelObjsA); createZ3ApplyFormulaMatchSetIteration(modelObjsA, SMTLIB_APPLICABILITY_FUN_A, Z3Utils.SMTLIB_AND, Z3Utils.SMTLIB_TRUE); createZ3ApplyFormulaMatchSetIteration(modelObjsA, SMTLIB_APPLICABILITY_FUN_A_OR, Z3Utils.SMTLIB_OR, Z3Utils.SMTLIB_FALSE); ruleApplicationsLifting++; updateChains(); // update set of constants for (Set<MAVOElement> mayModelObjsN : modelObjsNBar) { for (MAVOElement mayModelObjN : mayModelObjsN) { smtEncodingVariables.add(mayModelObjN.getFormulaVariable()); } } for (MAVOElement mayModelObjC : modelObjsC) { smtEncodingVariables.add(mayModelObjC.getFormulaVariable()); } for (MAVOElement mayModelObjD : modelObjsD) { smtEncodingVariables.add(mayModelObjD.getFormulaVariable()); } for (MAVOElement mayModelObjA : modelObjsA) { smtEncodingVariables.add(mayModelObjA.getFormulaVariable()); } } else { ruleApplicationsNotLifting++; } } return checkpointA; } @Override public Map<String, Model> run( Map<String, Model> inputsByName, Map<String, GenericElement> genericsByName, Map<String, MID> outputMIDsByName) throws Exception { // input Model origModel = inputsByName.get(IN_MODEL); super.init(); super.initSMTEncoding(SMTLIB_APPLICABILITY_PREAMBLE, SMTLIB_APPLICABILITY_POSTAMBLE); // do transformations String fullUri = FileUtils.prependWorkspacePathToUri(FileUtils.replaceLastSegmentInUri(origModel.getUri(), "")); HenshinResourceSet hResourceSet = new HenshinResourceSet(fullUri); Module hModule = hResourceSet.getModule(transformationModule, false); Engine hEngine = new EngineImpl(); hEngine.getOptions().put(Engine.OPTION_SORT_VARIABLES, false); EGraph hGraph = new EGraphImpl(hResourceSet.getResource(FileUtils.getLastSegmentFromUri(origModel.getUri()))); if (timeClassicalEnabled) { doTransformationClassical(hModule, hEngine, hGraph); hResourceSet = new HenshinResourceSet(fullUri); hModule = hResourceSet.getModule(transformationModule, false); hEngine = new EngineImpl(); hEngine.getOptions().put(Engine.OPTION_SORT_VARIABLES, false); hGraph = new EGraphImpl(hResourceSet.getResource(FileUtils.getLastSegmentFromUri(origModel.getUri()))); } doTransformationLifting(hModule, hEngine, hGraph); if (transformedConstraintEnabled) { transformedConstraint = smtEncoding.toString(); } // output EObject transformedRootModelObj = null; for (EObject hRoot : hGraph.getRoots()) { if (hRoot instanceof Trace) { continue; } transformedRootModelObj = hRoot; } if (transformedRootModelObj == null) { throw new MMINTException("Can't retrieve transformed root model object"); } Model transformedModelType = MIDTypeRegistry.getType( transformedRootModelObj.eClass().getEPackage().getNsURI()); String transformedMIDModelUri = FileUtils.getUniqueUri( FileUtils.replaceFileExtensionInUri( FileUtils.addFileNameSuffixInUri(origModel.getUri(), TRANSFORMED_MODEL_SUFFIX), transformedModelType.getFileExtension()), true, false); FileUtils.writeModelFile(transformedRootModelObj, transformedMIDModelUri, true); Model transformedModel = transformedModelType.createInstanceAndEditor( transformedMIDModelUri, outputMIDsByName.get(OUT_MODEL)); BinaryModelRel traceRel = MIDTypeHierarchy.getRootModelRelType().createBinaryInstanceAndEndpoints( null, origModel, transformedModel, outputMIDsByName.get(OUT_MODELREL)); traceRel.setName(OUT_MODELREL); Map<String, Model> outputsByName = new HashMap<>(); outputsByName.put(OUT_MODEL, transformedModel); outputsByName.put(OUT_MODELREL, traceRel); Properties outputProperties = new Properties(); writeProperties(outputProperties); MIDOperatorIOUtils.writePropertiesFile( outputProperties, this, origModel, getInputSubdir(), MIDOperatorIOUtils.OUTPUT_PROPERTIES_SUFFIX ); return outputsByName; } }