anchor.diff:  [[constraintStreamsImplementations]]
   == Variant implementation types
   
  -Constraint streams come in two flavours, a default implementation using Drools under the hood and a pure Java-based
  -implementation called _Bavet_. Drools-based implementation is more feature-complete.
  -
  -Bavet is an experimental implementation focusing on raw speed, which often significantly outperforms the Drools
  -implementation, or even Drools itself.
  -However, it lacks features.
  +Constraint streams come in two flavors, a default implementation using Drools under the hood and a pure Java-based
  +implementation called _Bavet_.
  +The Drools-based implementation is more feature-complete.
  +Both of these variants implement the same `ConstraintProvider` API.
  +No Java code changes are necessary to switch between the two.
  +
  +Bavet is an experimental implementation that focuses on raw speed and provides superior performance.
  +However, it lacks features and therefore many of the <<examplesOverview,examples>> are not supported.
   To try it out, implement the `ConstraintProvider` interface and use the following in your solver config:
   
   [source,xml,options="nowrap"]
  
positive.code:     }
  ----
  
  image::ConstraintStreams/constraintStreamGroupBy.png[align="center"]
  
  There are several collectors available out of the box. You can also provide your own collectors by implementing the
  `org.optaplanner.core.api.score.stream.uni.UniConstraintCollector` interface, or its `Bi...`, `Tri...` counterparts.
  
  [collectorsOutOfTheBox]
  === Out-of-the-box Collectors
  
  The following section focuses on the collector implementations provided out of the box. This section only describes the
  `int`-based variants of the collectors in detail. Many of the collectors also provide variants for other applicable
  
negative.code: ----
  
  
  [[constraintStreamsCardinality]]
  == Constraint stream cardinality
  
  Constraint stream cardinality is a measure of how many objects a single constraint match consists of.
  The simplest constraint stream has a cardinality of 1, meaning each constraint match only consists of 1 object.
  Therefore, it is called a `UniConstraintStream`:
  
  [source,java,options="nowrap"]
  ----
      private Constraint doNotAssignAnn(ConstraintFactory factory) {
          return factory.from(Shift.class) // Returns UniStream<Shift>.
                  ...
      }
  ----
  
  Some constraint stream <<constraintStreamsBuildingBlocks, building blocks>> can increase stream cardinality, such as
  <<constraintStreamsJoin,join>> or <<constraintStreamsGroupingAndCollectors,groupBy>>:
  
  [source,java,options="nowrap"]
  ----
      private Constraint doNotAssignAnn(ConstraintFactory factory) {
          return factory.from(Shift.class) // Returns Uni<Shift>.
                  .join(Employee.class)    // Returns Bi<Shift, Employee>.
                  .join(DayOff.class)      // Returns Tri<Shift, Employee, DayOff>.
                  .join(Country.class)     // Returns Quad<Shift, Employee, DayOff, Country>.
                  ...
      }
  ----
  
  The latter can also decrease stream cardinality:
  
  [source,java,options="nowrap"]
  ----
      private Constraint doNotAssignAnn(ConstraintFactory factory) {
          return factory.from(Shift.class) // Returns UniStream<Shift>.
                  .join(Employee.class) // Returns BiStream<Shift, Employee>.
                  .groupBy((shift, employee) -> employee) // Returns UniStream<Employee>.
                  ...
      }
  ----
  
  The following constraint stream cardinalities are currently supported:
  
  |===
  |Cardinality|Prefix|Defining interface
  |1          |   Uni|`UniConstraintStream<A>`
  |2          |    Bi|`BiConstraintStream<A, B>`
  |3          |   Tri|`TriConstraintStream<A, B, C>`
  |4          |  Quad|`QuadConstraintStream<A, B, C, D>`
  |===
  
  
  [[constraintStreamsBuildingBlocks]]
  == Building blocks
  
  Constraint streams are chains of different operations, called building blocks.
  Each constraint stream starts with a `from(...)` building block and is terminated by either a penalty or a reward.
  The following example shows the simplest possible constraint stream:
  
  [source,java,options="nowrap"]
  ----
      private Constraint penalizeInitializedShifts(ConstraintFactory factory) {
          return factory.from(Shift.class)
                  .penalize("Initialized shift", HardSoftScore.ONE_SOFT);
      }
  ----
  
  This constraint stream iterates over all known and initialized instances of `Shift`.
  To include uninitialized instances, replace the `from()` building block with `fromUnfiltered()`:
  
  [source,java,options="nowrap"]
  ----
      private Constraint penalizeAllShifts(ConstraintFactory factory) {
          return factory.fromUnfiltered(Shift.class)
                  .penalize("A shift", HardSoftScore.ONE_SOFT);
      }
  ----
  
  
  [[constraintStreamsPenaltiesRewards]]
  === Penalties and rewards
  
  The purpose of constraint streams is to build up a <<whatIsAScore,score>> for a <<planningProblemAndPlanningSolution,solution>>.
  To do this, every constraint stream must be terminated by a call to either a `penalize()` or a `reward()`
  building block.
  The `penalize()` building block makes the score worse and the `reward()` building block improves the score.
  Penalties and rewards have several components:
  
  - Constraint package is the Java package that contains the constraint.
  The default value is the package that contains the `ConstraintProvider` implementation or the value from
  <<constraintConfiguration,constraint configuration>>, if implemented.
  - Constraint name is the human readable descriptive name for the constraint, which
  (together with the constraint package) must be unique within the entire `ConstraintProvider` implementation.
  - Constraint weight is a constant score value indicating how much every breach of the constraint affects the score.
  Valid examples include `SimpleScore.ONE`, `HardSoftScore.ONE_HARD` and `HardMediumSoftScore.of(1, 2, 3)`.
  - Constraint match weigher is an optional function indicating how many times the constraint weight should be applied in
  the score.
  The penalty or reward score impact is the constraint weight multiplied by the match weight.
  The default value is `1`.
  
  The ConstraintStreams API supports many different types of penalties.
  Browse the API in your IDE for the full list of method overloads.
  Here are some examples:
  
  - Simple penalty (`penalize("Constraint name", SimpleScore.ONE)`) makes the score worse by `1` per every match in the
  constraint stream.
  The score type must be the same type as used on the `@PlanningScore` annotated member on the planning solution.
  - Dynamic penalty (`penalize("Constraint name", SimpleScore.ONE, Shift::getHours)`) makes the score worse by the number
  of hours in every matching `Shift` in the constraint stream.
  This is an example of using a constraint match weigher.
  - Configurable penalty (`penalizeConfigurable("Constraint name")`) makes the score worse using constraint weights
  defined in <<constraintConfiguration,constraint configuration>>.
  - Configurable dynamic penalty(`penalizeConfigurable("Constraint name", Shift::getHours)`) makes the score worse using
  constraint weights defined in <<constraintConfiguration,constraint configuration>>, multiplied by the number of hours in
  every matching `Shift` in the constraint stream.
  
  By replacing the keyword `penalize` by `reward` in the name of these building blocks, you will get operations that
  affect score in the opposite direction.
  
  
  [[constraintStreamsFilter]]
  === Filtering
  
  Filtering enables you to reduce the number of constraint matches in your stream.
  It first enumerate all constraint matches and then applies a predicate to filter some matches out.
  The predicate is a function that only returns `true` if the match is to continue in the stream.
  The following constraint stream removes all of Beth's shifts from all `Shift` matches:
  
  [source,java,options="nowrap"]
  ----
      private Constraint penalizeAnnShifts(ConstraintFactory factory) {
          return factory.from(Shift.class)
                  .filter(shift -> shift.getEmployeeName().equals("Ann"))
                  .penalize("Ann's shift", SimpleScore.ONE);
      }
  ----
  
  The following example retrieves a list of shifts where an employee has asked for a day off from a bi-constraint match
  of `Shift`and `DayOff`:
  
  [source,java,options="nowrap"]
  ----
      private Constraint penalizeShiftsOnOffDays(ConstraintFactory factory) {
          return factory.from(Shift.class)
                  .join(DayOff.class)
                  .filter((shift, dayOff) -> shift.date == dayOff.date && shift.employee == dayOff.employee)
                  .penalize("Shift on an off-day", SimpleScore.ONE);
      }
  ----
  
  The following figure illustrates both these examples:
  
  image::ConstraintStreams/constraintStreamFilter.png[align="center"]
  
  [NOTE]
  ====
  For performance reasons, using the <<constraintStreamsJoin,join>> building block with the appropriate `Joiner`s is
  preferrable when possible.
  Using a `Joiner` creates only the constraint matches that are necessary, while filtered join creates all possible
  constraint matches and only then filters some of them out.
  ====
  
  The following functions are required for filtering constraint streams of different cardinality:
  
  |===
  |Cardinality|Filtering Predicate
  |1          |`java.util.function.Predicate<A>`
  |2          |`java.util.function.BiPredicate<A, B>`
  |3          |`org.optaplanner.core.api.function.TriPredicate<A, B, C>`
  |4          |`org.optaplanner.core.api.function.QuadPredicate<A, B, C, D>`
  |===
  
  
  [[constraintStreamsJoin]]
  === Joining
  
  Joining is a way to increase <<constraintStreamsCardinality,stream cardinality>> and it is similar to the inner join
  operation in SQL. As the following figure illustrates, a join creates a cartesian product of the streams being joined:
  
  image::ConstraintStreams/constraintStreamJoinWithoutJoiners.png[align="center"]
  
  Doing this is inefficient because the resulting stream might contain constraint matches that are of no interest to your
  constraint.
  Use `Joiner` to restrict your joins only to the matches you are actually interested in, as illustrated in the following
  figure:
  
  image::ConstraintStreams/constraintStreamJoinWithJoiners.png[align="center"]
  
  The following `Joiner` types are supported:
  
  - `equalTo` for joining constraint matches where they `equals()` one another.
  - `greaterThan`, `greaterThanOrEqual`, `lessThan` and `lessThanOrEqual` for joining `Comparable` constraint matches per
  the prescribed ordering.
  
  For a full list of all supported `Joiner` implementations and their various overloads, refer to the
  `org.optaplanner.core.api.score.stream.Joiners` class.
  
  
  [[constraintStreamsGroupingAndCollectors]]
  === Grouping and collectors
  
  Grouping collects items in a stream according to user-provider criteria (also called "group key"), similar to what a
  `GROUP BY` SQL clause does. Additionally, some grouping operations also accept one or more `Collector` instances, which
  provide various aggregation functions. The following figure illustrates a simple `groupBy()` operation:
  
  image::ConstraintStreams/constraintStreamGroupBy.png[align="center"]
  
  For example, the following code snippet first groups all processes by the computer they run on, sums up all the power
  required by the processes on that computer using the `ConstraintCollectors.sum(...)` collector, and finally penalizes
  