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

io.github.oliviercailloux.grade.GradeAggregator Maven / Gradle / Ivy

The newest version!
package io.github.oliviercailloux.grade;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Verify.verify;
import static io.github.oliviercailloux.grade.MarkAggregator.checkCanAggregate;

import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import io.github.oliviercailloux.grade.IGrade.CriteriaPath;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 

* A tree of MarkAggregator instances. Has information about how to aggregate some mark trees. The * other ones are said to have an incompatible structure. Compatibility depends only on the * structure of the mark tree (i.e., the criteria paths), not on the marks it contains; except that * for parametric weighters, the weighting marks may not be negative. *

*

* A grade aggregator at a given node accepts some sets of criteria and rejects others. The * compatible trees are those such that, for each node, the set of child criteria at that node is * accepted. *

*

* A grade aggregator is static (at a given node) iff it is bound to a static weighting mark * aggregator at that node; dynamic otherwise. *

*

* A grade aggregator also has sub-aggregators, associated each to a criterion, the set of which is * called its sub-criteria. A static grade aggregator sub-criteria equals the set of criteria known * to its mark aggregator. A dynamic grade aggregator sub-criteria is the set of all possible * criteria. *

*

* A grade aggregator is trivial iff it is bound to a void mark aggregator, which implies that it is * static, and that it has no sub-aggregators. *

*

* Grade aggregators reject, at a given level, the sets of criteria rejected by their underlying * mark aggregators (for example, a static grade aggregator rejects every criteria unknown to its * static mark aggregator; a dynamic grade aggregator bound to a ParametricWeighter rejects sets of * unsuitable size or content…). *

*

* TODO distinguish two sorts of static weights. Consider this grade. *

    *
  • Capping at 2022-03-04T07:50:09Z — Weighted sum: 20 / 20 *
      *
    • user.name — 2 / 2
    • *
    • Grade — Weighted sum: 18 / 18 *
        *
      • First commit — Weighted sum: 9 / 9
      • *
      • Second commit — Weighted sum: 9 / 9
      • *
      *
    • *
    *
  • *
* Here we want to keep the two levels of weighter so that if the main Grade is a simple mark, it is * still aggregated correctly; but in general, we want to display the static weighter flat, i.e., * with three criteria instead of one and then two. */ public class GradeAggregator { @SuppressWarnings("unused") private static final Logger LOGGER = LoggerFactory.getLogger(GradeAggregator.class); public static final WeightingGradeAggregator TRIVIAL = WeightingGradeAggregator.trivial(); public static final WeightingGradeAggregator ABSOLUTE = WeightingGradeAggregator.ABSOLUTE_WEIGHTING; public static final GradeAggregator MIN = new GradeAggregator(MinAggregator.INSTANCE, ImmutableMap.of(), WeightingGradeAggregator.trivial()); public static final GradeAggregator MAX = new GradeAggregator(MaxAggregator.INSTANCE, ImmutableMap.of(), WeightingGradeAggregator.trivial()); public static GradeAggregator min(GradeAggregator defaultSubAggregator) { return new GradeAggregator(MinAggregator.INSTANCE, ImmutableMap.of(), defaultSubAggregator); } public static GradeAggregator max(Map subs) { return new GradeAggregator(MaxAggregator.INSTANCE, subs, TRIVIAL); } public static GradeAggregator max(Map subs, GradeAggregator defaultSubAggregator) { return new GradeAggregator(MaxAggregator.INSTANCE, subs, defaultSubAggregator); } public static GradeAggregator max(GradeAggregator defaultSubAggregator) { return new GradeAggregator(MaxAggregator.INSTANCE, ImmutableMap.of(), defaultSubAggregator); } public static GradeAggregator owa(List weights) { return new GradeAggregator(OwaAggregator.given(weights), ImmutableMap.of(), TRIVIAL); } public static GradeAggregator owa(List weights, Map subs) { return new GradeAggregator(OwaAggregator.given(weights), subs, TRIVIAL); } public static GradeAggregator absolute(Map subs, GradeAggregator defaultSubAggregator) { return new GradeAggregator(AbsoluteAggregator.INSTANCE, subs, defaultSubAggregator); } public static GradeAggregator absolute(GradeAggregator defaultSubAggregator) { return new GradeAggregator(AbsoluteAggregator.INSTANCE, ImmutableMap.of(), defaultSubAggregator); } public static GradeAggregator parametric(Criterion multiplied, Criterion weighting, Map subs) { return new GradeAggregator(ParametricWeighter.given(multiplied, weighting), subs, TRIVIAL); } public static GradeAggregator parametric(Criterion multiplied, Criterion weighting, Map subs, GradeAggregator defaultSubAggregator) { return new GradeAggregator(ParametricWeighter.given(multiplied, weighting), subs, defaultSubAggregator); } public static GradeAggregator parametric(Criterion multiplied, Criterion weighting, GradeAggregator multipliedAggregator) { return new GradeAggregator(ParametricWeighter.given(multiplied, weighting), ImmutableMap.of(multiplied, multipliedAggregator), TRIVIAL); } public static GradeAggregator parametric(Criterion multiplied, Criterion weighting, GradeAggregator multipliedAggregator, GradeAggregator otherAggregator) { checkNotNull(otherAggregator); return new GradeAggregator(ParametricWeighter.given(multiplied, weighting), ImmutableMap.of(multiplied, multipliedAggregator), otherAggregator); } public static GradeAggregator staticAggregator(Map weights, Map subs) { return new GradeAggregator(new StaticWeighter(weights), subs, TRIVIAL); } public static GradeAggregator staticAggregator(Map weights, Map subs, GradeAggregator defaultSub) { return new GradeAggregator(new StaticWeighter(weights), subs, defaultSub); } public static GradeAggregator given(MarkAggregator markAggregator, Map subs, GradeAggregator defaultSubAggregator) { return new GradeAggregator(markAggregator, subs, defaultSubAggregator); } private final MarkAggregator markAggregator; /** * Every key must be part of some set of criteria accepted by the mark aggregator. No value equal * to the default one. */ private final ImmutableMap subs; /** * {@code null} iff this instance is trivial */ private final GradeAggregator defaultSubAggregator; protected GradeAggregator(MarkAggregator markAggregator, Map subs, GradeAggregator defaultSubAggregator) { LOGGER.debug("Init given {}, {} and default {}.", markAggregator, subs, defaultSubAggregator); this.markAggregator = checkNotNull(markAggregator); this.subs = ImmutableMap.copyOf(Maps.filterValues(subs, a -> !a.equals(defaultSubAggregator))); this.defaultSubAggregator = defaultSubAggregator; checkArgument((defaultSubAggregator == null) == (markAggregator instanceof VoidAggregator), (defaultSubAggregator == null)); if (markAggregator instanceof StaticWeighter) { final StaticWeighter staticWeighter = (StaticWeighter) markAggregator; checkArgument(staticWeighter.weights().keySet().containsAll(subs.keySet())); } } public MarkAggregator getMarkAggregator() { return markAggregator; } /** * This method is guaranteed to return an aggregator if this aggregator would accept the criterion * when it is associated to a simple mark (the converse may not hold). * * @throws AggregatorException iff this aggregator rejects this criterion systematically (meaning, * whatever set it is part of); equivalently, iff this aggregator is a static aggregator * and the criterion is unknown to its static weighter; implying that for trivial * aggregators, his method throws whatever its argument. */ public GradeAggregator getGradeAggregator(Criterion criterion) throws AggregatorException { checkNotNull(criterion); if (markAggregator instanceof StaticWeighter staticWeighter) { checkCanAggregate(staticWeighter.weights().containsKey(criterion), "In %s, unknown criterion %s among %s", toString(), criterion.getName(), staticWeighter.weights()); } verify(defaultSubAggregator != null); return subs.getOrDefault(criterion, defaultSubAggregator); } public GradeAggregator getGradeAggregator(CriteriaPath path) { if (path.isRoot()) { return this; } return getGradeAggregator(path.getHead()).getGradeAggregator(path.withoutHead()); } /** * @return the non-default sub-aggregators. */ public ImmutableMap getSpecialSubAggregators() { return subs; } public GradeAggregator getDefaultSubAggregator() { return Optional.ofNullable(defaultSubAggregator).orElse(TRIVIAL); } /** * Returns {@code true} iff the given object is an aggregator that accepts the same trees and * aggregates them all in the same way as this object. */ @Override public boolean equals(Object o2) { if (!(o2 instanceof GradeAggregator)) { return false; } final GradeAggregator t2 = (GradeAggregator) o2; return markAggregator.equals(t2.markAggregator) && subs.equals(t2.subs) && Objects.equals(defaultSubAggregator, t2.defaultSubAggregator); } @Override public int hashCode() { return Objects.hash(markAggregator, subs, defaultSubAggregator); } @Override public String toString() { return MoreObjects.toStringHelper(this).add("Mark aggregator", markAggregator).add("Subs", subs) .add("default", defaultSubAggregator).toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy