From 9adbb3d49899a87b3026c11cb4ba3ff77f4fb75b Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sat, 19 Aug 2023 02:31:57 +0200 Subject: chore: import VIATRA source Make our modifications more maintainable by editing the source code directly instead of using reflection. --- .../runtime/rete/recipes/GenerateReteRecipes.mwe2 | 25 ++ .../rete/recipes/helper/RecipeRecognizer.java | 204 +++++++++++ .../runtime/rete/recipes/helper/RecipesHelper.java | 81 +++++ .../src/main/resources/model/recipes.ecore | 400 +++++++++++++++++++++ .../src/main/resources/model/recipes.ecore.license | 4 + .../src/main/resources/model/rete-recipes.genmodel | 171 +++++++++ .../resources/model/rete-recipes.genmodel.license | 4 + 7 files changed, 889 insertions(+) create mode 100644 subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/GenerateReteRecipes.mwe2 create mode 100644 subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/helper/RecipeRecognizer.java create mode 100644 subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/helper/RecipesHelper.java create mode 100644 subprojects/viatra-runtime-rete-recipes/src/main/resources/model/recipes.ecore create mode 100644 subprojects/viatra-runtime-rete-recipes/src/main/resources/model/recipes.ecore.license create mode 100644 subprojects/viatra-runtime-rete-recipes/src/main/resources/model/rete-recipes.genmodel create mode 100644 subprojects/viatra-runtime-rete-recipes/src/main/resources/model/rete-recipes.genmodel.license (limited to 'subprojects/viatra-runtime-rete-recipes/src') diff --git a/subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/GenerateReteRecipes.mwe2 b/subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/GenerateReteRecipes.mwe2 new file mode 100644 index 00000000..424cc9f5 --- /dev/null +++ b/subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/GenerateReteRecipes.mwe2 @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +module tools.refinery.viatra.runtime.rete.recipes.GenerateReteRecipes + +Workflow { + bean = org.eclipse.emf.mwe.utils.StandaloneSetup { + projectMapping = { + projectName = "tools.refinery.refinery-viatra-runtime-rete-recipes" + path = "." + } + } + + component = org.eclipse.emf.mwe.utils.DirectoryCleaner { + directory = "src/main/emf-gen" + } + + component = org.eclipse.emf.mwe2.ecore.EcoreGenerator { + generateCustomClasses = false + genModel = "platform:/resource/tools.refinery.refinery-viatra-runtime-rete-recipes/src/main/resources/model/rete-recipes.genmodel" + srcPath = "platform:/resource/tools.refinery.refinery-viatra-runtime-rete-recipes/src/main/emf-gen" + } +} diff --git a/subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/helper/RecipeRecognizer.java b/subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/helper/RecipeRecognizer.java new file mode 100644 index 00000000..2c252593 --- /dev/null +++ b/subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/helper/RecipeRecognizer.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2010-2016, Gabor Bergmann, Istvan Rath and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.viatra.runtime.rete.recipes.helper; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.EcoreUtil; +import tools.refinery.viatra.runtime.matchers.context.IQueryRuntimeContext; +import tools.refinery.viatra.runtime.rete.recipes.RecipesPackage; +import tools.refinery.viatra.runtime.rete.recipes.ReteNodeRecipe; + +import java.util.*; + +/** + * Stores a set of known canonical recipes, each representing a disjoint equivalence class of recipes, modulo + * {@link #isEquivalentRecipe(ReteNodeRecipe, ReteNodeRecipe)}. + * + * @author Gabor Bergmann + * @since 1.3 + * + */ +public class RecipeRecognizer { + private static long nextRecipeEquivalenceClassID = 0; + + /** + * if EcoreUtil.equals(recipe1, recipe2), only one of them will be included here + */ + Map> canonicalRecipesByClass = new HashMap<>(); + Map canonicalRecipeByEquivalenceClassID = new HashMap<>(); + + private IQueryRuntimeContext runtimeContext; + + /** + * @param can be null; if provided, further equivalences can be detected based on {@link IQueryRuntimeContext#wrapElement(Object)} + * @since 1.6 + */ + public RecipeRecognizer(IQueryRuntimeContext runtimeContext) { + this.runtimeContext = runtimeContext; + } + public RecipeRecognizer() { + this(null); + } + + /** + * Recognizes when an equivalent canonical recipe is already known. + * + * @return an equivalent canonical recipe, or the null if no known equivalent found + */ + public ReteNodeRecipe peekCanonicalRecipe(final ReteNodeRecipe recipe) { + // equivalence class already known + for (Long classID : recipe.getEquivalenceClassIDs()) { + ReteNodeRecipe knownRecipe = canonicalRecipeByEquivalenceClassID.get(classID); + if (knownRecipe != null) + return knownRecipe; + } + + // equivalence class not known, but maybe equivalent recipe still + // available + Collection sameClassRecipes = getSameClassCanonicalRecipes(recipe); + for (ReteNodeRecipe knownRecipe : sameClassRecipes) { + if (isEquivalentRecipe(recipe, knownRecipe)) { + // FOUND EQUIVALENT RECIPE + recipe.getEquivalenceClassIDs().add(knownRecipe.getEquivalenceClassIDs().get(0)); + return knownRecipe; + } + } + + return null; + } + + /** + * This recipe will be remembered as a canonical recipe. Method maintains both internal data structures and the + * equivalence class attribute of the recipe. PRECONDITION: {@link #peekCanonicalRecipe(ReteNodeRecipe)} must return + * null or the recipe itself + */ + public void makeCanonical(final ReteNodeRecipe recipe) { + // this is a canonical recipe, chosen representative of its new + // equivalence class + if (recipe.getEquivalenceClassIDs().isEmpty()) { + recipe.getEquivalenceClassIDs().add(nextRecipeEquivalenceClassID++); + } + for (Long classID : recipe.getEquivalenceClassIDs()) { + canonicalRecipeByEquivalenceClassID.put(classID, recipe); + } + getSameClassCanonicalRecipes(recipe).add(recipe); + } + + /** + * Ensures that there is an equivalent canonical recipe; if none is known yet, this recipe will be remembered as + * canonical. + * + * @return an equivalent canonical recipe; the argument recipe itself (which is made canonical) if no known + * equivalent found + */ + public ReteNodeRecipe canonicalizeRecipe(final ReteNodeRecipe recipe) { + ReteNodeRecipe knownRecipe = peekCanonicalRecipe(recipe); + if (knownRecipe == null) { + knownRecipe = recipe; + makeCanonical(recipe); + } + return knownRecipe; + } + + /** + * @return true iff recipe is a canonical recipe + */ + public boolean isKnownCanonicalRecipe(final ReteNodeRecipe recipe) { + if (recipe.getEquivalenceClassIDs().isEmpty()) { + return false; + } + ReteNodeRecipe knownRecipe = canonicalRecipeByEquivalenceClassID.get(recipe.getEquivalenceClassIDs().get(0)); + return recipe == knownRecipe; + } + + private Set getSameClassCanonicalRecipes(final ReteNodeRecipe recipe) { + Set sameClassRecipes = canonicalRecipesByClass.get(recipe.eClass()); + if (sameClassRecipes == null) { + sameClassRecipes = new HashSet<>(); + canonicalRecipesByClass.put(recipe.eClass(), sameClassRecipes); + } + return sameClassRecipes; + } + + private boolean isEquivalentRecipe(ReteNodeRecipe recipe, ReteNodeRecipe knownRecipe) { + return new EqualityHelper(runtimeContext).equals(recipe, knownRecipe); + } + + // TODO reuse in more cases later, e.g. switching join node parents, etc. + private static class EqualityHelper extends EcoreUtil.EqualityHelper { + + + + + private static final long serialVersionUID = -8841971394686015188L; + + private static final EAttribute RETE_NODE_RECIPE_EQUIVALENCE_CLASS_IDS = + RecipesPackage.eINSTANCE.getReteNodeRecipe_EquivalenceClassIDs(); + private static final EAttribute CONSTANT_RECIPE_CONSTANT_VALUES = + RecipesPackage.eINSTANCE.getConstantRecipe_ConstantValues(); + private static final EAttribute DISCRIMINATOR_BUCKET_RECIPE_BUCKET_KEY = + RecipesPackage.eINSTANCE.getDiscriminatorBucketRecipe_BucketKey(); + + private IQueryRuntimeContext runtimeContext; + + public EqualityHelper(IQueryRuntimeContext runtimeContext) { + this.runtimeContext = runtimeContext; + } + + @Override + protected boolean haveEqualFeature(EObject eObject1, EObject eObject2, EStructuralFeature feature) { + // ignore differences in this attribute, as it may only be assigned + // after the equivalence check + if (RETE_NODE_RECIPE_EQUIVALENCE_CLASS_IDS.equals(feature)) + return true; + + if (runtimeContext != null) { + // constant values + if (/*CONSTANT_RECIPE_CONSTANT_VALUES.equals(feature) ||*/ DISCRIMINATOR_BUCKET_RECIPE_BUCKET_KEY.equals(feature)) { + // use runtime context to map to canonical wrapped form + // this is costly for constant recipes (TODO improve this), but essential for discriminator buckets + + Object val1 = eObject1.eGet(feature); + Object val2 = eObject2.eGet(feature); + + if (val1 != null && val2 != null) { + return runtimeContext.wrapElement(val1).equals(runtimeContext.wrapElement(val2)); + } else { + return val1 == null && val2 == null; + } + + } + } + + // fallback to general comparison + return super.haveEqualFeature(eObject1, eObject2, feature); + } + + @Override + public boolean equals(EObject eObject1, EObject eObject2) { + // short-circuit if already known to be equivalent + if (eObject1 instanceof ReteNodeRecipe) { + if (eObject2 instanceof ReteNodeRecipe) { + EList eqClassIDs1 = ((ReteNodeRecipe) eObject1).getEquivalenceClassIDs(); + EList eqClassIDs2 = ((ReteNodeRecipe) eObject2).getEquivalenceClassIDs(); + + if (!Collections.disjoint(eqClassIDs1, eqClassIDs2)) + return true; + } + } + + // fallback to general comparison + return super.equals(eObject1, eObject2); + } + } +} diff --git a/subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/helper/RecipesHelper.java b/subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/helper/RecipesHelper.java new file mode 100644 index 00000000..3070fcf5 --- /dev/null +++ b/subprojects/viatra-runtime-rete-recipes/src/main/java/tools/refinery/viatra/runtime/rete/recipes/helper/RecipesHelper.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2004-2014 Gabor Bergmann and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.viatra.runtime.rete.recipes.helper; + +import org.eclipse.emf.common.util.EList; +import tools.refinery.viatra.runtime.rete.recipes.*; + +import java.util.Collection; + +/** + * Static helper class for easy construction of recipes. + * + * @author Bergmann Gabor + */ +public class RecipesHelper { + private static final RecipesFactory FACTORY = RecipesFactory.eINSTANCE; + + private RecipesHelper() {/* Utility class constructor */} + + /** + * @since 2.0 + */ + public static Mask mask(final int sourceArity, final Collection sourceIndices) { + Mask mask = RecipesHelper.FACTORY.createMask(); + mask.setSourceArity(sourceArity); + mask.getSourceIndices().addAll(sourceIndices); + return mask; + } + + public static Mask mask(final int sourceArity, final int... sourceIndices) { + Mask mask = RecipesHelper.FACTORY.createMask(); + mask.setSourceArity(sourceArity); + final EList maskIndeces = mask.getSourceIndices(); + for (int index : sourceIndices) { + maskIndeces.add(index); + } + return mask; + } + + public static ProjectionIndexerRecipe projectionIndexerRecipe(final ReteNodeRecipe parent, final Mask mask) { + ProjectionIndexerRecipe recipe = RecipesHelper.FACTORY.createProjectionIndexerRecipe(); + recipe.setParent(parent); + recipe.setMask(mask); + return recipe; + } + + public static ExpressionDefinition expressionDefinition(final Object evaluator) { + ExpressionDefinition definition = RecipesHelper.FACTORY.createExpressionDefinition(); + definition.setEvaluator(evaluator); + return definition; + } + + public static InputRecipe inputRecipe(final Object inputKey, final String inputKeyID, final int arity) { + InputRecipe recipe = RecipesHelper.FACTORY.createInputRecipe(); + recipe.setInputKey(inputKey); + recipe.setKeyArity(arity); + recipe.setKeyID(inputKeyID); + recipe.setTraceInfo(inputKeyID); + return recipe; + } + + /** + * Mask can be null in case no tuple reordering or trimming is needed + */ + public static InputFilterRecipe inputFilterRecipe(final ReteNodeRecipe parent, final Object inputKey, + final String inputKeyID, final Mask mask) { + InputFilterRecipe it = RecipesHelper.FACTORY.createInputFilterRecipe(); + it.setParent(parent); + it.setInputKey(inputKey); + it.setKeyID(inputKeyID); + it.setTraceInfo(inputKeyID); + it.setMask(mask); + return it; + } +} diff --git a/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/recipes.ecore b/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/recipes.ecore new file mode 100644 index 00000000..4eda701e --- /dev/null +++ b/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/recipes.ecore @@ -0,0 +1,400 @@ + + + + +
+ + + + + +
+ + + +
+
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + + + + + + +
+ + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + + + + + +
+ + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + + + + + + + + + +
+ + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + + + +
+ + + + +
+ + + +
+ + + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + + + + + +
+ + + + + + + + + +
+ + + +
+ + + + + + +
+ + + +
+ + + + + + + + + + +
+ + + + + +
+ + + +
+ + + + + + diff --git a/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/recipes.ecore.license b/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/recipes.ecore.license new file mode 100644 index 00000000..03d1d42b --- /dev/null +++ b/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/recipes.ecore.license @@ -0,0 +1,4 @@ +Copyright (c) 2004-2014 Gabor Bergmann and Daniel Varro +Copyright (c) 2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 diff --git a/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/rete-recipes.genmodel b/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/rete-recipes.genmodel new file mode 100644 index 00000000..6b44fde6 --- /dev/null +++ b/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/rete-recipes.genmodel @@ -0,0 +1,171 @@ + + + + +
+ +
+ + + +
+ +
+ + recipes.ecore + org.eclipse.xtext.xbase.lib + org.eclipse.emf.ecore.xcore.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/rete-recipes.genmodel.license b/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/rete-recipes.genmodel.license new file mode 100644 index 00000000..03d1d42b --- /dev/null +++ b/subprojects/viatra-runtime-rete-recipes/src/main/resources/model/rete-recipes.genmodel.license @@ -0,0 +1,4 @@ +Copyright (c) 2004-2014 Gabor Bergmann and Daniel Varro +Copyright (c) 2023 The Refinery Authors + +SPDX-License-Identifier: EPL-2.0 -- cgit v1.2.3-54-g00ecf