cdc.applic.expressions.ast.visitors.MergeSets Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cdc-applic-expressions Show documentation
Show all versions of cdc-applic-expressions Show documentation
Applicabilities Expressions.
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 ≡ π ∉ (Ω2-Ω1)
*
- π∉Ω1 ∨ π∈Ω2 ≡ π ∉ (Ω1-Ω2)
*
- π∉Ω1 ∨ π∉Ω2 ≡ π ∉ (Ω1∩Ω2)
*
- π∈Ω1 ∧ π∈Ω2 ≡ π ∈ (Ω1∩Ω2)
*
- π∈Ω1 ∧ π∉Ω2 ≡ π ∈ (Ω1-Ω2)
*
- π∉Ω1 ∧ π∈Ω2 ≡ π ∈ (Ω2-Ω1)
*
- π∉Ω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