Record Class ScoreAnalysis<Score_ extends Score<Score_>>

java.lang.Object
java.lang.Record
ai.timefold.solver.core.api.score.analysis.ScoreAnalysis<Score_>
Type Parameters:
Score_ -
Record Components:
score - Score of the solution being analyzed.
constraintMap - for each constraint identified by its Constraint.getConstraintRef(), the ConstraintAnalysis that describes the impact of that constraint on the overall score.

Zero-weight constraints are never included, they are excluded from score calculation in the first place. Otherwise constraints are always included, even if they have no matches, unless the score analysis represents a diff between two other analyses.

In the case of a diff:

  • If the constraint weight diff is non-zero, or if the score diff for the constraint is non-zero, the constraint diff will be included.
  • Otherwise if constraint matching is disabled (ScoreAnalysisFetchPolicy.FETCH_SHALLOW) or if only match counts are available (ScoreAnalysisFetchPolicy.FETCH_MATCH_COUNT), constraint diff will only be included if it has a non-zero match count diff.
  • Otherwise (when constraint matching is fully enabled with ScoreAnalysisFetchPolicy.FETCH_ALL) the constraint diff will not be included if the diff of its constraint matches is empty. (In other words: when diffing, the analysis for a particular constraint won't be available if we can guarantee that the constraint matches are identical in both analyses.)

Entries in the map have a stable iteration order; items are ordered first by ConstraintAnalysis.weight(), then by ConstraintAnalysis.constraintRef().

isSolutionInitialized - Whether the solution was fully initialized at the time of analysis.

public record ScoreAnalysis<Score_ extends Score<Score_>>(@NonNull Score_ extends Score<Score_> score, @NonNull Map<ConstraintRef,ConstraintAnalysis<Score_ extends Score<Score_>>> constraintMap, boolean isSolutionInitialized) extends Record
Represents the breakdown of a Score into individual ConstraintAnalysis instances, one for each constraint. Compared to ScoreExplanation, this is JSON-friendly and faster to generate.

In order to be fully serializable to JSON, MatchAnalysis instances must be serializable to JSON and that requires any implementations of ConstraintJustification to be serializable to JSON. This is the responsibility of the user.

For deserialization from JSON, the user needs to provide the deserializer themselves. This is due to the fact that, once the ScoreAnalysis is received over the wire, we no longer know which Score type or ConstraintJustification type was used. The user has all of that information in their domain model, and so they are the correct party to provide the deserializer.

Note: the constructors of this record are off-limits. We ask users to use exclusively SolutionManager.analyze(Object) to obtain instances of this record.

  • Constructor Details

  • Method Details

    • getConstraintAnalysis

      public @Nullable ConstraintAnalysis<Score_> getConstraintAnalysis(@NonNull ConstraintRef constraintRef)
      Performs a lookup on constraintMap(). Equivalent to constraintMap().get(constraintRef).
      Returns:
      null if no constraint matches of such constraint are present
    • getConstraintAnalysis

      @Deprecated(forRemoval=true, since="1.13.0") public @Nullable ConstraintAnalysis<Score_> getConstraintAnalysis(@NonNull String constraintPackage, @NonNull String constraintName)
      Deprecated, for removal: This API element is subject to removal in a future version.
      As defined by getConstraintAnalysis(ConstraintRef) where the arguments are first composed into a singular constraint ID.
      Returns:
      null if no constraint matches of such constraint are present
    • getConstraintAnalysis

      public @Nullable ConstraintAnalysis<Score_> getConstraintAnalysis(@NonNull String constraintName)
      Returns:
      null if no constraint matches of such constraint are present
      Throws:
      IllegalStateException - if multiple constraints with the same name are present, which is possible if they are in different constraint packages. Constraint packages are deprecated, we recommend avoiding them and instead naming constraints uniquely. If you must use constraint packages, see getConstraintAnalysis(String, String) (also deprecated) and reach out to us to discuss your use case.
    • diff

      public @NonNull ScoreAnalysis<Score_> diff(@NonNull ScoreAnalysis<Score_> other)
      Compare this ScoreAnalysis to another ScoreAnalysis and retrieve the difference between them. The comparison is in the direction of this - other.

      Example: if this has a score of 100 and other has a score of 90, the returned score will be 10. If this and other were inverted, the score would have been -10. The same applies to all other properties of ScoreAnalysis.

      In order to properly diff MatchAnalysis against each other, we rely on the user implementing ConstraintJustification equality correctly. In other words, the diff will consider two justifications equal if the user says they are equal, and it expects the hash code to be consistent with equals.

      If one ScoreAnalysis provides MatchAnalysis and the other doesn't, exception is thrown. Such ScoreAnalysis instances are mutually incompatible.

      If this came from a fully initialized solution, isSolutionInitialized will be true. False otherwise.

    • constraintAnalyses

      public Collection<ConstraintAnalysis<Score_>> constraintAnalyses()
      Returns individual ConstraintAnalysis instances that make up this ScoreAnalysis.
      Returns:
      equivalent to constraintMap().values()
    • summarize

      public @NonNull String summarize()
      Returns a diagnostic text that explains the solution through the ConstraintAnalysis API to identify which constraints cause that score quality. The string is built fresh every time the method is called.

      In case of an infeasible solution, this can help diagnose the cause of that.

      Do not parse the return value, its format may change without warning. Instead, provide this information in a UI or a service, use constraintAnalyses() and convert those into a domain-specific API.

    • toString

      public String toString()
      Returns a string representation of this record class. The representation contains the name of the class, followed by the name and value of each of the record components.
      Specified by:
      toString in class Record
      Returns:
      a string representation of this object
    • hashCode

      public final int hashCode()
      Returns a hash code value for this object. The value is derived from the hash code of each of the record components.
      Specified by:
      hashCode in class Record
      Returns:
      a hash code value for this object
    • equals

      public final boolean equals(Object o)
      Indicates whether some other object is "equal to" this one. The objects are equal if the other object is of the same class and if all the record components are equal. Reference components are compared with Objects::equals(Object,Object); primitive components are compared with '=='.
      Specified by:
      equals in class Record
      Parameters:
      o - the object with which to compare
      Returns:
      true if this object is the same as the o argument; false otherwise.
    • score

      public @NonNull Score_ score()
      Returns the value of the score record component.
      Returns:
      the value of the score record component
    • constraintMap

      public @NonNull Map<ConstraintRef,ConstraintAnalysis<Score_>> constraintMap()
      Returns the value of the constraintMap record component.
      Returns:
      the value of the constraintMap record component
    • isSolutionInitialized

      public boolean isSolutionInitialized()
      Returns the value of the isSolutionInitialized record component.
      Returns:
      the value of the isSolutionInitialized record component