All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cdc.applic.expressions.ast.visitors.MergeSets Maven / Gradle / Ivy

The newest version!
package cdc.applic.expressions.ast.visitors;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cdc.applic.expressions.ast.AbstractBinaryNode;
import cdc.applic.expressions.ast.AbstractNaryNode;
import cdc.applic.expressions.ast.AbstractSetNode;
import cdc.applic.expressions.ast.InNode;
import cdc.applic.expressions.ast.NaryOrNode;
import cdc.applic.expressions.ast.Node;
import cdc.applic.expressions.ast.NotInNode;
import cdc.applic.expressions.ast.OrNode;
import cdc.applic.expressions.content.SItemSet;
import cdc.applic.expressions.literals.Name;
import cdc.util.lang.Checks;

/**
 * Converter that applies the following rewriting rules:
 * 
    *
  • π∈Ω1 ∨ π∈Ω2 ≡ π ∈ (Ω1∪Ω2) *
  • π∈Ω1 ∨ π∉Ω2 ≡ π ∉ (Ω21) *
  • π∉Ω1 ∨ π∈Ω2 ≡ π ∉ (Ω12) *
  • π∉Ω1 ∨ π∉Ω2 ≡ π ∉ (Ω1∩Ω2) *
  • π∈Ω1 ∧ π∈Ω2 ≡ π ∈ (Ω1∩Ω2) *
  • π∈Ω1 ∧ π∉Ω2 ≡ π ∈ (Ω12) *
  • π∉Ω1 ∧ π∈Ω2 ≡ π ∈ (Ω21) *
  • π∉Ω1 ∧ π∉Ω2 ≡ π ∉ (Ω1∪Ω2) *
* * Note: those rules avoid use of complement.
* WARNING: No handling of = or ≠ is done. One should use {@link ConvertEqualitiesToSingletons} before.
* WARNING: No ordering of nodes is done. One should use {@link ConvertToNary} before.
* * @author Damien Carbonne */ public final class MergeSets extends AbstractConverter { private static final MergeSets CONVERTER = new MergeSets(); private MergeSets() { } public static Node execute(Node node) { Checks.isNotNull(node, "node"); return node.accept(CONVERTER); } /** * If a Node is an AbstractSetNode, returns it name, {@code null} otherwise. * * @param node The node. * @return The name of {@code node} if it is an AbstractSetNode, {@code null} otherwise. */ private static Name getSetPropertyName(Node node) { if (node instanceof AbstractSetNode) { return ((AbstractSetNode) node).getName(); } else { return null; } } /** * Returns the merging of 2 nodes that relate to the same property. * * @param alpha The first node. * @param or If {@code true}, consider parent node is an OR, AND otherwise. * @param beta The second node. * @return The merging of {@code alpha} and {@code beta}. */ private static AbstractSetNode merge(AbstractSetNode alpha, boolean or, AbstractSetNode beta) { final boolean alphaIn = alpha instanceof InNode; final boolean betaIn = beta instanceof InNode; final SItemSet alphaSet = alpha.getSet(); final SItemSet betaSet = beta.getSet(); if (or) { if (alphaIn) { if (betaIn) { // in (alpha union beta) return new InNode(alpha.getName(), alphaSet.union(betaSet)); } else { // alpha union complement(beta) // Avoid computation of complement: // not in (beta - alpha) return new NotInNode(alpha.getName(), betaSet.remove(alphaSet)); } } else { if (betaIn) { // complement(alpha) union beta // Avoid computation of complement: // not in (alpha - beta) return new NotInNode(alpha.getName(), alphaSet.remove(betaSet)); } else { // complement(alpha) union complement(beta) // Avoid computation of complement: // not in (alpha intersection beta) return new NotInNode(alpha.getName(), alphaSet.intersection(betaSet)); } } } else { if (alphaIn) { if (betaIn) { // in (alpha intersection beta) return new InNode(alpha.getName(), alphaSet.intersection(betaSet)); } else { // alpha intersection complement(beta) // Avoid computation of complement: // in (alpha - beta) return new InNode(alpha.getName(), alphaSet.remove(betaSet)); } } else { if (betaIn) { // complement(alpha) intersection beta // Avoid computation of complement: // in (beta - alpha) return new InNode(alpha.getName(), betaSet.remove(alphaSet)); } else { // complement(alpha) intersection complement(beta) // not in (alpha union beta) return new NotInNode(alpha.getName(), alphaSet.union(betaSet)); } } } } private static Node merge(List alphas, boolean or) { AbstractSetNode result = alphas.get(0); for (int index = 1; index < alphas.size(); index++) { result = merge(result, or, alphas.get(index)); } return result; } @Override public Node visitBinary(AbstractBinaryNode node) { final Node alpha = node.getAlpha().accept(this); final Node beta = node.getBeta().accept(this); final Name alphaName = getSetPropertyName(alpha); final Name betaName = getSetPropertyName(beta); if (alphaName != null && alphaName.equals(betaName)) { return merge((AbstractSetNode) alpha, node instanceof OrNode, (AbstractSetNode) beta); } else { return node.create(alpha, beta); } } @Override public Node visitNary(AbstractNaryNode node) { // List of all converted children final List children = new ArrayList<>(); // Sets of nodes that can be merged final Map> mergeable = new HashMap<>(); // Fill children and mergeable for (final Node child : node.getChildren()) { final Node alpha = child.accept(this); children.add(alpha); final Name alphaName = getSetPropertyName(alpha); if (alphaName != null) { final List set = mergeable.computeIfAbsent(alphaName, (k) -> new ArrayList<>()); set.add((AbstractSetNode) alpha); } } // Replace in children all nodes with same property by a merged equivalent for (final List set : mergeable.values()) { if (set.size() > 1) { // Merge content of set final Node merged = merge(set, node instanceof NaryOrNode); // Remove content of set from children children.removeAll(set); // Add the merged node to children children.add(merged); } } return node.create(children); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy