code: @Override
      public Evaluation evaluate(SolutionType solution) {
          if(penalizingConstraints.isEmpty()){
              // CASE 1: no penalizing constraints
              return objective.evaluate(solution, data);
          } else {
              // CASE 2 (default): aggregate evaluation and penalties
              Evaluation eval = objective.evaluate(solution, data);
              // initialize penalized evaluation object
              PenalizedEvaluation penEval = new PenalizedEvaluation(eval, isMinimizing());
              // add penalties
              penalizingConstraints.forEach(pc -> penEval.addPenalizingValidation(pc, pc.validate(solution, data)));
              // return aggregated evaluation
              return penEval;
          }
      }
docs: Evaluates a solution by taking into account both the evaluation calculated by the objective function and the
  penalizing constraints (if any). Penalties are assigned for any violated penalizing constraint, which are
  subtracted from the evaluation in case of maximization, and added to it in case of minimization.
  <p>
  If there are no penalizing constraints, this method returns the evaluation object obtained from applying
  the objective function to the given solution. If one or more penalizing constraints have been specified,
  a penalized evaluation is constructed taking into account both the main objective function evaluation
  and assigned penalties.
  
  @param solution solution to be evaluated
  @return aggregated evaluation taking into account both the objective function and penalizing constraints