/** * 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.icmt15.operator; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Random; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.EContentsEList; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.jdt.annotation.NonNull; import edu.toronto.cs.se.mmint.MMINT; import edu.toronto.cs.se.mmint.MMINTException; 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.operator.impl.RandomOperatorImpl; 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.Z3Utils; //TODO MMINT[OPERATOR] Move other paper experiments to examples public class ICMT15 extends RandomOperatorImpl { // input-output private final static @NonNull String IN_MODEL = "model"; private final static @NonNull String OUT_MODEL = "biggerModel"; private final static @NonNull String PROPERTY_IN_MODELMULTIPLIER = "modelMultiplier"; private final static @NonNull String PROPERTY_IN_VARIABLESMULTIPLIER = "variablesMultiplier"; private static final @NonNull String PROPERTY_IN_IDATTRIBUTE = "idAttribute"; private static final @NonNull String PROPERTY_IN_CONSTRAINT = "constraint"; private static final @NonNull String PROPERTY_IN_VARIABLES = "variables"; private static final @NonNull String PROPERTY_IN_CLAUSESTOVARIABLESRATIO = "clausesToVariablesRatio"; private static final @NonNull String PROPERTY_IN_PRESENCECONDITIONSTOMODELSIZERATIO = "presenceConditionsToModelSizeRatio"; // constants private final static @NonNull String CSV_SEPARATOR = ";"; private final static @NonNull String MODEL_GENERATED_SUFFIX = "_generated"; private final static double EASY_PRESENCECONDITION_PERCENTAGE = 0.8; private final static double HARD_PRESENCECONDITION_PERCENTAGE = 0.2; private final static int VARIABLES_PER_CLAUSE = 2; // input private int modelMultiplier; private int variablesMultiplier; private String idAttribute; private String constraint; private List<String> variables; private double clausesToVariablesRatio; private double presenceConditionsToModelSizeRatio; // output private List<String> outputVariables; private String outputConstraint; @Override public void readInputProperties(Properties inputProperties) throws MMINTException { super.readInputProperties(inputProperties); modelMultiplier = MIDOperatorIOUtils.getIntProperty(inputProperties, PROPERTY_IN_MODELMULTIPLIER); variablesMultiplier = MIDOperatorIOUtils.getIntProperty(inputProperties, PROPERTY_IN_VARIABLESMULTIPLIER); idAttribute = MIDOperatorIOUtils.getStringProperty(inputProperties, PROPERTY_IN_IDATTRIBUTE); constraint = MIDOperatorIOUtils.getStringProperty(inputProperties, PROPERTY_IN_CONSTRAINT); variables = MIDOperatorIOUtils.getStringPropertyList(inputProperties, PROPERTY_IN_VARIABLES); clausesToVariablesRatio = MIDOperatorIOUtils.getDoubleProperty(inputProperties, PROPERTY_IN_CLAUSESTOVARIABLESRATIO); presenceConditionsToModelSizeRatio = MIDOperatorIOUtils.getDoubleProperty(inputProperties, PROPERTY_IN_PRESENCECONDITIONSTOMODELSIZERATIO); } private void init() { // output outputConstraint = ""; outputVariables = new ArrayList<>(); for (int i = 0; i < Math.pow(2, variablesMultiplier-1); i++) { String tempConstraint = constraint; for (int j = 0; j < variables.size(); j++) { String variable = variables.get(j); String outputVariable = variable + "_" + i; outputVariables.add(outputVariable); tempConstraint = tempConstraint.replace(variable, outputVariable); } outputConstraint += tempConstraint; } } private String getModelObjectEncoding(@NonNull EObject modelObj) throws MMINTException { return modelObj.eClass().getName() + CSV_SEPARATOR + FileUtils.getModelObjectFeature(modelObj, idAttribute) + CSV_SEPARATOR; } private String getModelReferenceEncoding(@NonNull EObject srcModelObj, @NonNull EObject tgtModelObj, @NonNull EStructuralFeature reference) throws MMINTException { return reference.getName() + CSV_SEPARATOR + getModelObjectEncoding(srcModelObj) + getModelObjectEncoding(tgtModelObj); } private List<String> generateModelEncodings(@NonNull EObject inputRootModelObj) { List<String> modelEncodings = new ArrayList<>(); TreeIterator<EObject> iter = inputRootModelObj.eAllContents(); while (iter.hasNext()) { EObject modelObj = iter.next(); try { modelEncodings.add(getModelObjectEncoding(modelObj)); EContentsEList.FeatureIterator<EObject> crossIter = (EContentsEList.FeatureIterator<EObject>) modelObj.eCrossReferences().iterator(); while (crossIter.hasNext()) { modelEncodings.add(getModelReferenceEncoding(modelObj, crossIter.next(), crossIter.feature())); } } catch (MMINTException e) { continue; } } return modelEncodings; } private int getNumClauses() { double numClauses = (clausesToVariablesRatio * (double) outputVariables.size() - EASY_PRESENCECONDITION_PERCENTAGE) / HARD_PRESENCECONDITION_PERCENTAGE; return (int) Math.max(0, Math.round(numClauses)); } private void changeCopyIds(@NonNull EObject rootModelObjCopy, @NonNull String sliceIdSuffix) throws Exception { TreeIterator<EObject> iter = rootModelObjCopy.eAllContents(); while (iter.hasNext()) { EObject modelObjCopy = iter.next(); String id = null, newId = null; try { id = (String) FileUtils.getModelObjectFeature(modelObjCopy, idAttribute); if (id != null) { newId = id + sliceIdSuffix; FileUtils.setModelObjectFeature(modelObjCopy, idAttribute, newId); } } catch (MMINTException e) { // ignore and continue continue; } } } private @NonNull String generatePresenceCondition(@NonNull List<String> outputModelEncodings, int numClauses) { Random random = this.getState(); int i = random.nextInt(outputModelEncodings.size()); String outputModelEncoding = outputModelEncodings.remove(i); String presenceCondition = ""; if (numClauses == 1) { i = random.nextInt(outputVariables.size()); presenceCondition = outputVariables.get(i); } else { for (int j = 0; j < numClauses-1; j++) { List<String> clause = new ArrayList<>(); for (int k = 0; k < VARIABLES_PER_CLAUSE; k++) { i = random.nextInt(outputVariables.size()); String variable = outputVariables.get(i); if (clause.contains(variable)) { k--; continue; } clause.add(variable); } presenceCondition += Z3Utils.or(String.join(" ", clause)); } presenceCondition = Z3Utils.and(presenceCondition); } return outputModelEncoding + presenceCondition; } @Override public Map<String, Model> run( Map<String, Model> inputsByName, Map<String, GenericElement> genericsByName, Map<String, MID> outputMIDsByName) throws Exception { // input Model inputModel = inputsByName.get(IN_MODEL); MID instanceMID = outputMIDsByName.get(OUT_MODEL); this.init(); // generate output model EObject inputRootModelObj = inputModel.getEMFInstanceRoot(); EObject outputRootModelObj = inputRootModelObj.eClass().getEPackage().getEFactoryInstance().create(inputRootModelObj.eClass()); String presenceConditions = Z3Utils.or(outputConstraint) + "\n"; for (int i = 0; i < Math.pow(2, modelMultiplier-1); i++) { EObject inputRootModelObjCopy = EcoreUtil.copy(inputRootModelObj); changeCopyIds(inputRootModelObjCopy, "_" + i); for (EReference containmentFeature : inputRootModelObjCopy.eClass().getEAllContainments()) { @SuppressWarnings("unchecked") EList<EObject> inputModelObjsCopy = (EList<EObject>) FileUtils.getModelObjectFeature(inputRootModelObjCopy, containmentFeature.getName()); @SuppressWarnings("unchecked") EList<EObject> outputModelObjs = (EList<EObject>) FileUtils.getModelObjectFeature(outputRootModelObj, containmentFeature.getName()); outputModelObjs.addAll(inputModelObjsCopy); } } // generate presence conditions List<String> outputModelEncodings = generateModelEncodings(outputRootModelObj); int numPresenceConditions = (int) (outputModelEncodings.size() * presenceConditionsToModelSizeRatio); int numClauses = getNumClauses(); for (int i = 0; i < (numPresenceConditions * EASY_PRESENCECONDITION_PERCENTAGE); i++) { presenceConditions += generatePresenceCondition(outputModelEncodings, 1) + "\n"; } if (numClauses > 0) { for (int i = 0; i < (numPresenceConditions * HARD_PRESENCECONDITION_PERCENTAGE); i++) { presenceConditions += generatePresenceCondition(outputModelEncodings, numClauses) + "\n"; } } for (String outputModelEncoding : outputModelEncodings) { presenceConditions += outputModelEncoding + Z3Utils.SMTLIB_TRUE.trim() + "\n"; } // output String uri = (getInputSubdir() != null) ? FileUtils.replaceLastSegmentInUri( inputModel.getUri(), getInputSubdir() + MMINT.URI_SEPARATOR + FileUtils.getLastSegmentFromUri(inputModel.getUri()) ) : inputModel.getUri(); String outputModelUri = FileUtils.getUniqueUri(FileUtils.addFileNameSuffixInUri(uri, MODEL_GENERATED_SUFFIX), true, false); FileUtils.writeModelFile(outputRootModelObj, outputModelUri, true); Model outputModel = inputModel.getMetatype().createInstanceAndEditor(outputModelUri, instanceMID); FileUtils.createTextFile(FileUtils.replaceFileExtensionInUri(outputModelUri, "csv"), presenceConditions, true); Map<String, Model> outputsByName = new HashMap<>(); outputsByName.put(OUT_MODEL, outputModel); return outputsByName; } }