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

cdc.applic.dictionaries.impl.SectionAssertionsImpl Maven / Gradle / Ivy

The newest version!
package cdc.applic.dictionaries.impl;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cdc.applic.dictionaries.Constraint;
import cdc.applic.dictionaries.DictionaryMembership;
import cdc.applic.dictionaries.items.Assertion;
import cdc.applic.dictionaries.items.ConstraintAssertion;
import cdc.applic.dictionaries.items.ContextAssertion;
import cdc.applic.dictionaries.items.DItem;
import cdc.applic.dictionaries.items.LocalAssertion;
import cdc.applic.dictionaries.items.StandardAssertion;
import cdc.applic.dictionaries.visitors.AddMissingPrefixes;
import cdc.applic.expressions.Expression;
import cdc.applic.expressions.Expressions;
import cdc.graphs.core.GraphPath;
import cdc.tuples.Tuple2;
import cdc.util.debug.Printables;
import cdc.util.debug.Verbosity;
import cdc.util.function.IterableUtils;
import cdc.util.lang.Checks;

final class SectionAssertionsImpl implements SectionAssertions {
    private static final String ASSERTION = "assertion";
    private static final String CONSTRAINT = "constraint";
    private static final String CONTEXT = "context";
    private static final String EXPRESSION = "expression";

    private static final Expressions EXPR = Expressions.SHORT_NARROW_SIMPLIFY;

    private final AbstractDictionaryImpl dictionary;

    /** All local assertions: user-defined, constraint and context. */
    private final Set local = new HashSet<>();
    /** The local context assertion. */
    private ContextAssertionImpl localContext;
    /** The local constraint assertions indexed by their (constraint, params). */
    private final Map, ConstraintAssertion> localConstraint = new HashMap<>();

    /** All assertions: local and derived. */
    private final Set all = new HashSet<>();

    /** Derived Standard assertions, indexed by their source. */
    private final Map derivedStandard = new HashMap<>();
    /** Derived context assertions. */
    private final Set derivedContext = new HashSet<>();

    SectionAssertionsImpl(AbstractDictionaryImpl dictionary,
                          Expression context) {
        this.dictionary = dictionary;
        this.localContext = new ContextAssertionImpl(dictionary, context);
        // Avoid adding tautology
        if (!context.isTrue()) {
            this.all.add(this.localContext);
        }
    }

    /**
     * Collects and derives all assertions from parent dictionaries.
     * 

* This MUST be called when a dictionary is created. */ void build() { // There is no descendant at the time of call // This does not matter addDerivationsRec(); } void refreshDerivationsRec() { removeDerivationsRec(); addDerivationsRec(); } /** * Removes all derived assertions from this dictionary and all its descendants. */ private void removeDerivationsRec() { for (final AbstractDictionaryImpl descendant : dictionary.structure.getSortedDescendants(true)) { descendant.assertions.all.removeAll(descendant.assertions.derivedStandard.values()); descendant.assertions.all.removeAll(descendant.assertions.derivedContext); descendant.assertions.derivedStandard.clear(); descendant.assertions.derivedContext.clear(); descendant.newCachesSerial(false); } } /** * Adds all derived (standard and context) assertions to this dictionary and all its descendants. */ private void addDerivationsRec() { // Iterate on all descendants, including itself for (final AbstractDictionaryImpl descendant : dictionary.structure.getSortedDescendants(true)) { // Iterate on all ancestors of descendant. for (final AbstractDictionaryImpl ancestor : descendant.structure.getSortedAncestors(false)) { // Derive all standard assertions of ancestor for (final LocalAssertion assertion : ancestor.assertions.local) { if (assertion instanceof StandardAssertion) { descendant.assertions.addDerivedStandard((StandardAssertion) assertion, ancestor); } } } descendant.assertions.addDerivedContext(); descendant.newCachesSerial(false); } } /** * Computes the derived context assertion and adds it to this dictionary. */ private void addDerivedContext() { // Compute all paths from roots to this dictionary final List> paths = new ArrayList<>(); dictionary.structure.explorePathsFromRoots(paths::add); // disjunction of conjunctions from paths // C1C2.. + C1C3... + addDerivedContext(buildOr(paths)); // final int size = paths.size(); // final List> parentPaths = new ArrayList<>(); // for (final GraphPath path : paths) { // parentPaths.add(path.parent()); // } // // // for each pair of paths, declare an exclusion // // !C1C2... and !C1C3... and ... // // This can be done if paths share a common element that is not the last one // for (int i1 = 0; i1 < size - 1; i1++) { // final GraphPath parent1 = parentPaths.get(i1); // for (int i2 = i1 + 1; i2 < size; i2++) { // final GraphPath parent2 = parentPaths.get(i2); // if (parent1.hasCommonItemsWith(parent2)) { // addDerivedContext(buildNotAnd(paths.get(i1), paths.get(i2))); // } // } // } } /** * Creates a derived context assertion from an expression, and adds it to this dictionary. * * @param x The expression. */ private void addDerivedContext(Expression x) { // Avoid adding tautology if (!x.isTrue()) { final DerivedContextAssertionImpl assertion = new DerivedContextAssertionImpl(dictionary, x); derivedContext.add(assertion); all.add(assertion); } } /** * Returns the conjunction of contexts associated to a path of dictionaries. *

* All contexts except the last one are used. * * @param path The path of dictionaries. * @return The conjunction of contexts of dictionaries contained in {@code path}. */ private static Expression buildAnd(GraphPath path) { final List items = path.getItems(); Expression x = Expression.TRUE; for (final AbstractDictionaryImpl d : items.subList(0, items.size() - 1)) { x = EXPR.and(x, AddMissingPrefixes.execute(d.getContextExpression(), d)); } return x; } /** * Returns the disjunction of context expressions associated to each path. * * @param paths The dictionary paths. * @return The disjunction of context expressions associated to each element of {@code path}. */ private static Expression buildOr(List> paths) { if (paths.isEmpty()) { return Expression.TRUE; } else { Expression x = Expression.FALSE; for (final GraphPath path : paths) { x = Expressions.SHORT_NARROW_SIMPLIFY.or(x, buildAnd(path)); } return x; } } // private static Expression buildNotAnd(GraphPath path1, // GraphPath path2) { // final Expression x = EXPR.not(EXPR.and(buildAnd(path1), buildAnd(path2))); // return x; // } /** * Returns the precondition part corresponding to a path between an ancestor * of a dictionary and the dictionary. *

* All paths between an ancestor and a dictionary are explored, each producing a part * which are combined to produce the precondition. * * @param path The path. * @return An expression corresponding to {@code path}. */ private static Expression buildStandardPrecondition(GraphPath path) { Expression x = Expression.TRUE; final List items = path.getItems(); // Ignore last path item. It corresponds to the target dictionary for (final AbstractDictionaryImpl d : items.subList(0, items.size() - 1)) { x = EXPR.and(x, d.getContextExpression()); } return x; } /** * Returns the precondition to be used with standard assertions defined in an ancestor dictionary. *

* Derivation of standard assertion A define in {@code ancestor} produces * an assertion of the form: {@code precondition -> A}. *

* The precondition is computed from context expressions of all paths between {@code ancestor} * and this dictionary. * * @param ancestor The ancestor dictionary. * @return The standard precondition to be used with {@code ancestor}. */ private Expression getStandardPrecondition(AbstractDictionaryImpl ancestor) { final List xs = new ArrayList<>(); dictionary.structure.explorePathsFromAncestor(ancestor, p -> xs.add(buildStandardPrecondition(p))); Expression x = xs.isEmpty() ? Expression.TRUE : EXPR.or(xs); x = EXPR.and(getContextExpression(), x); return x; } /** * Adds a standard assertion to this dictionary and * recursively adds its derivation to descendants. * * @param assertion The local assertion. */ private void addStandardRec(StandardAssertion assertion) { Checks.isNotNull(assertion, ASSERTION); // Local processing addStandard(assertion); // Derivation for (final AbstractDictionaryImpl descendant : dictionary.structure.getSortedDescendants(false)) { descendant.assertions.addDerivedStandard(assertion, dictionary); } } /** * Adds a standard assertion to this dictionary. * * @param assertion The assertion. */ private void addStandard(StandardAssertion assertion) { local.add(assertion); all.add(assertion); if (assertion instanceof ConstraintAssertion) { final ConstraintAssertion ga = (ConstraintAssertion) assertion; localConstraint.put(Tuple2.of(ga.getConstraint(), ga.getParams()), ga); } dictionary.newCachesSerial(false); } /** * Computes the derived assertion corresponding to a source standard assertion, * and adds it to this dictionary. * * @param sourceAssertion The source standard assertion. * @param sourceDictionary The source dictionary. */ private void addDerivedStandard(StandardAssertion sourceAssertion, AbstractDictionaryImpl sourceDictionary) { Checks.isTrue(dictionary != sourceDictionary, "Can not created a standard derivation in same dictionary"); if (!derivedStandard.containsKey(sourceAssertion)) { final Expression derivedExpression = deriveStandard(sourceAssertion, sourceDictionary); final DerivedStandardAssertionImpl derivedAssertion = new DerivedStandardAssertionImpl(dictionary, sourceAssertion, sourceDictionary, derivedExpression); derivedStandard.put(sourceAssertion, derivedAssertion); all.add(derivedAssertion); dictionary.newCachesSerial(false); } } /** * Derives a standard assertion. * * @param sourceAssertion The source assertion to derive. * @param sourceDictionary The dictionary containing the source assertion. * @return The derivation of {@code sourceAssertion}. */ private Expression deriveStandard(StandardAssertion sourceAssertion, AbstractDictionaryImpl sourceDictionary) { final Expression precondition = getStandardPrecondition(sourceDictionary); final Expression prefixedSourceExpression = AddMissingPrefixes.execute(sourceAssertion.getExpression(), sourceDictionary); if (precondition.isTrue()) { return prefixedSourceExpression; } else { return EXPR.imp(precondition, prefixedSourceExpression); } } /** * Removes a standard assertion and recursively removes its derivations. * * @param assertion The assertion. */ private void removeStandardRec(StandardAssertion assertion) { Checks.isNotNull(assertion, ASSERTION); // Local processing removeStandard(assertion); // Derivation for (final AbstractDictionaryImpl descendant : dictionary.structure.getSortedDescendants(false)) { descendant.assertions.removeStandardDerivation(assertion); } } /** * Locally remove a standard assertion. * * @param assertion The assertion. */ private void removeStandard(StandardAssertion assertion) { final boolean removed = local.remove(assertion); Checks.assertTrue(removed, "Unknown assertion"); all.remove(assertion); if (assertion instanceof ConstraintAssertion) { final ConstraintAssertion ga = (ConstraintAssertion) assertion; final ConstraintAssertion r = localConstraint.remove(Tuple2.of(ga.getConstraint(), ga.getParams())); Checks.assertTrue(r != null, "Unknown generated assertion"); } dictionary.newCachesSerial(false); } /** * Locally removes the derivation of a standard assertion. * * @param sourceAssertion The source assertion. */ private void removeStandardDerivation(StandardAssertion sourceAssertion) { final DerivedStandardAssertionImpl removed = derivedStandard.remove(sourceAssertion); Checks.assertTrue(removed != null, "No associated derived assertion"); all.remove(removed); dictionary.newCachesSerial(false); } @Override public void setContextExpression(Expression context) { Checks.isNotNull(context, CONTEXT); Checks.isFalse(dictionary.getParents().isEmpty(), "Can not set context on root dictionary."); this.all.remove(this.localContext); this.localContext = new ContextAssertionImpl(dictionary, context); // Avoid adding tautology if (!context.isTrue()) { this.all.add(this.localContext); } removeDerivationsRec(); addDerivationsRec(); } @Override public Expression getContextExpression() { return localContext.getExpression(); } @Override public Iterable getAssertions(Class cls) { return IterableUtils.filterAndConvert(cls, all); } @Override public Set getAllAssertions() { return all; } @Override public DictionaryMembership getMembership(Assertion assertion) { Checks.isNotNull(assertion, ASSERTION); if (local.contains(assertion)) { return DictionaryMembership.LOCAL; } else if (all.contains(assertion)) { if (assertion instanceof ContextAssertion) { return DictionaryMembership.CONTEXT; } else { return DictionaryMembership.DERIVED; } } else { return DictionaryMembership.UNRELATED; } } @Override public void removeAssertion(StandardAssertion assertion) { Checks.isNotNull(assertion, ASSERTION); removeStandardRec(assertion); } @Override public UserDefinedAssertionImpl createAssertion(Expression expression) { Checks.isNotNull(expression, EXPRESSION); final UserDefinedAssertionImpl assertion = new UserDefinedAssertionImpl(dictionary, expression); addStandardRec(assertion); return assertion; } @Override public UserDefinedAssertionImpl createAssertion(String expression) { Checks.isNotNull(expression, EXPRESSION); return createAssertion(new Expression(expression)); } @Override public void removeRelatedAndDerivedAssertions(Constraint constraint) { Checks.isNotNull(constraint, CONSTRAINT); final List toRemove = new ArrayList<>(); for (final LocalAssertion assertion : local) { if (assertion instanceof ConstraintAssertion) { final ConstraintAssertion g = (ConstraintAssertion) assertion; if (g.getConstraint() == constraint) { toRemove.add(g); } } } for (final ConstraintAssertion assertion : toRemove) { removeAssertion(assertion); } } @Override public Iterable getRelatedAssertions(Constraint constraint) { Checks.isTrue(constraint.getOwner() == dictionary, "Dictionary mismatch"); final List result = new ArrayList<>(); for (final LocalAssertion assertion : getAssertions(LocalAssertion.class)) { if (assertion instanceof ConstraintAssertion) { result.add((ConstraintAssertion) assertion); } } return result; } @Override public ConstraintAssertion getRelatedAssertion(Constraint constraint, String params) { Checks.isTrue(constraint.getOwner() == dictionary, "Dictionary mismatch"); return this.localConstraint.get(Tuple2.of(constraint, params)); } @Override public ConstraintAssertion createAssertion(Constraint constraint, String params, Expression expression) { Checks.isNotNull(constraint, CONSTRAINT); Checks.isNotNull(expression, EXPRESSION); Checks.isTrue(constraint.getOwner() == dictionary, "Non local constraint"); final ConstraintAssertionImpl assertion = new ConstraintAssertionImpl(constraint, params, expression); addStandardRec(assertion); return assertion; } @Override public void printAssertions(PrintStream out, int level, Verbosity verbosity) { // Assertions Printables.indent(out, level); out.println("Assertions (" + getAllAssertions().size() + ")"); if (verbosity != Verbosity.ESSENTIAL) { for (final Assertion assertion : IterableUtils.toSortedList(getAllAssertions(), DItem.COMPARATOR)) { Printables.indent(out, level + 1); out.println(getMembership(assertion) + " " + assertion + " " + assertion.getKind()); } } } }