001package de.monochromata.anaphors.cog;
002
003import static java.util.Arrays.asList;
004import static java.util.stream.Collectors.toList;
005import static java.util.stream.Stream.empty;
006
007import java.util.Collections;
008import java.util.List;
009import java.util.stream.Stream;
010
011import de.monochromata.anaphors.ast.ASTBasedAnaphorResolution;
012import de.monochromata.anaphors.ast.ASTBasedAnaphora;
013import de.monochromata.anaphors.ast.relatedexp.RelatedExpression;
014import de.monochromata.anaphors.ast.spi.TransformationsSpi;
015import de.monochromata.anaphors.cog.memory.Chunk;
016import de.monochromata.anaphors.cog.memory.Memory;
017import de.monochromata.anaphors.cog.spi.CogSpi;
018import de.monochromata.anaphors.cog.transform.AddParameterToCallChain;
019import de.monochromata.anaphors.cog.transform.CheckResult;
020import de.monochromata.anaphors.cog.transform.NoPreparationRequired;
021import de.monochromata.anaphors.cog.transform.PreparatoryTransformation;
022
023/**
024 * Resolve the referents of anaphors based on a cognitive model.
025 *
026 * @param <N>  The node type in the AST
027 * @param <E>  The expression type
028 * @param <T>  The type type
029 * @param <B>  The binding type
030 * @param <TB> The type binding type
031 * @param <S>  The scope type (optional)
032 * @param <I>  The type used to represent identifiers
033 * @param <QI> The type used to represent qualified identifiers
034 * @param <R>  The sub-type of related expression to use
035 * @param <A>  The sub-type of AST-based anaphora to use
036 */
037public class ActivationBasedAnaphorResolution<N, E, T, B, TB extends B, S, I, QI, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>> {
038
039    private final List<PreparatoryTransformation<N, E, T, B, TB, S, I, QI, R, A>> preparatoryTransformations;
040    private final ASTBasedAnaphorResolution<N, E, T, B, TB, S, I, QI, R, A> delegate;
041
042    /**
043     * Used in contract testing.
044     */
045    @SuppressWarnings("unused")
046    protected ActivationBasedAnaphorResolution() {
047        delegate = null;
048        preparatoryTransformations = null;
049    }
050
051    public ActivationBasedAnaphorResolution(final ASTBasedAnaphorResolution<N, E, T, B, TB, S, I, QI, R, A> delegate,
052            final TransformationsSpi<N, E, T, B, TB, S, I, QI, R, A> transformationsSpi) {
053        this.delegate = delegate;
054        this.preparatoryTransformations = asList(new NoPreparationRequired<>(transformationsSpi),
055                new AddParameterToCallChain<>(transformationsSpi));
056    }
057
058    /**
059     * Perform anaphora resolution on the AST implementation configured via the
060     * service provider interfaces.
061     * <p>
062     * TODO: Evaluate whether anaphora relations can be transformed into AST-based
063     * anaphora relations
064     * <p>
065     * TODO: Provide means to transform these anaphora relations into AST-based
066     * anaphora relations by performing complex AST manipulations / refactorings
067     * like introducing parameters to multiple methods ...
068     * <ol>
069     * <li>Find ways to create Anaphora relations
070     * <li>This might include a preparation step that performs complex AST
071     * transformations that prepare the referentialization of the anaphor
072     * </ol>
073     *
074     * @param anaphor                  The anaphor that is to be (re-)resolved.
075     * @param definiteExpression       The expression that may function as anaphor
076     *                                 in the anaphora relation to be generated by
077     *                                 this method. If the anaphora relation is to
078     *                                 be re-resolved, this can be a non-trivial
079     *                                 expression. If the anaphora relation is to be
080     *                                 resolved for the first time, this is
081     *                                 typically a simple name and might as well be
082     *                                 called a definite expression at this point.
083     * @param scope                    May be null if not required by the AST
084     *                                 implementation configured via the service
085     *                                 provider interfaces.
086     * @param timestamp                the point in time at which the memory access
087     *                                 occurs (in the format returned by
088     *                                 {@link System#currentTimeMillis()}
089     * @param numberOfChunksToConsider The maximum number of chunks to consider as
090     *                                 potential related expressions.
091     * @return TODO: Rework: A list of anaphors that the given definite expression
092     *         can function as. The list is empty is the anaphor could not be
093     *         resolved and will contain more than one element if the anaphor is
094     *         ambiguous.
095     */
096    public List<Resolution<N, E, T, B, TB, S, I, QI, R, A>> resolveAnaphor(final String anaphor,
097            final E definiteExpression, final S scope, final long timestamp, final int numberOfChunksToConsider) {
098        final Memory<N> memory = CogSpi.getMemory();
099        if (memory == null) {
100            return Collections.emptyList();
101        }
102        return memory.getChunks(timestamp, numberOfChunksToConsider).stream()
103                .flatMap(chunk -> resolve(chunk, anaphor, definiteExpression, scope)).collect(toList());
104    }
105
106    protected Stream<Resolution<N, E, T, B, TB, S, I, QI, R, A>> resolve(final Chunk<N> chunk, final String anaphor,
107            final E definiteExpression, final S scope) {
108        for (final PreparatoryTransformation<N, E, T, B, TB, S, I, QI, R, A> preparatoryTransformation : preparatoryTransformations) {
109            final CheckResult<N, E, S> result = preparatoryTransformation.canPerform(chunk, definiteExpression, scope);
110            if (result.canPerformTransformation()) {
111                @SuppressWarnings("unchecked")
112                final R potentialRelatedExpression = delegate.getRelatedExpression(result.getChunk().getRepresented());
113                if (potentialRelatedExpression != null) {
114                    // TODO: Die Prüfung, ob AST-basierte Anaphern anwendbar
115                    // sind, muss anhand des Chunks als potential related
116                    // expression erfolgen und darf dann nicht reachability
117                    // involvieren ...
118                    return delegate.resolveAnaphor(potentialRelatedExpression, anaphor, definiteExpression, scope)
119                            .stream().map(anaphora -> createResolution(result, preparatoryTransformation, anaphora));
120                }
121            }
122        }
123        return empty();
124    }
125
126    protected Resolution<N, E, T, B, TB, S, I, QI, R, A> createResolution(final CheckResult<N, E, S> checkResult,
127            final PreparatoryTransformation<N, E, T, B, TB, S, I, QI, R, A> preparatoryTransformation,
128            final A preliminaryAnaphora) {
129        return new DefaultResolution<>(checkResult, preparatoryTransformation, preliminaryAnaphora);
130    }
131
132}