OptaPlanner 中的自定义 "sumDouble()" 函数用于约束

Custom "sumDouble()" function in OptaPlanner for constraints

我需要一个求和功能,它可以对我的 ConstraintProviding 功能的双精度值求和。当前 OptaPlanner 提供 sum() 和 sumBigDecimal() 功能,其中第一个仅对整数值求和,第二个 BigDecimal 值。因此,我开始使用手册第 6.4.5.3 章中描述的组合方法。用于实现我自己的功能(不想覆盖原来的功能)。

从那里派生并从 OptaPlanner 源代码本身的 ConstraintCollector.java class 中实现求和功能,我最终得到以下代码:

    public static <A> UniConstraintCollector<A, ?, Double> sumDouble(ToDoubleFunction<A> groupValueMapping) {
            return compose((resultContainer, a) -> {
                        double value = groupValueMapping.applyAsDouble(a);
                        resultContainer[0] += value;
                        return () -> resultContainer[0] -= value;
                    },
                    resultContainer -> resultContainer[0]);
        }

在我的“OwnConstraintProvider”中 class。但这行不通。错误是:

    java: method compose in interface java.lang.module.ModuleFinder cannot be applied to given types;
  required: java.lang.module.ModuleFinder[]
  found: (resultCon[...]ue; },(resultCon[...]er[0]
  reason: varargs mismatch; java.lang.module.ModuleFinder is not a functional interface
      multiple non-overriding abstract methods found in interface java.lang.module.ModuleFinder

我知道输入A和结果之间必须有一个更清晰的关系和计算方法。

坦率地说,我最近才开始认真地 Java 编程。所以我无法弄清楚在那种情况下我错在哪里。在当前使用的版本 (8.19.0) 的手册中,第 6.4.5.1.3 章中提到了“用于汇总自定义类型的通用 sum() 变体”。但我对这方面的细节一无所知。

谁能给我一些提示。

提前致谢!

您是否考虑过使用不同的类型,例如long,以表示您需要在约束中 sum() 的值?

使用 floating-point numbers in the score calculation is generally not recommended 因为它可能会导致分数损坏。

首先,拉多万的回答是完全正确的。事实上,潜在的分数损坏是未提供 sumDouble() 的原因。相反,我们提供 sumBigDecimal(),它不会遇到同样的问题。但是,它会在性能方面受到影响。首选解决方案是使用 sum()sumLong(),必要时使用 fixed-point 算法。

也就是说,实现 sumDouble() 相对简单,不需要组合来实现:

public static <A> UniConstraintCollector<A, ?, Double> sum(ToDoubleFunction<? super A> groupValueMapping) {
    return new DefaultUniConstraintCollector<>(
        () -> new double[1],
        (resultContainer, a) -> {
            int value = groupValueMapping.applyAsDouble(a);
            resultContainer[0] += value;
            return () -> resultContainer[0] -= value;
        },
        resultContainer -> resultContainer[0]);
}

现在,DefaultUniConstraintCollector 不是 public 类型。但是您可以使用匿名 class 代替:

public static <A> UniConstraintCollector<A, ?, Integer> sum(ToDoubleFunction<? super A> groupValueMapping) {
    return new UniConstraintCollector<A, double[], Double>() {
        @Override
        public Supplier<double[]> supplier() {
            return () -> new double[1];
        }

        @Override
        public BiFunction<double[], A, Runnable> accumulator() {
            return (resultContainer, a) -> {
                double value = groupValueMapping.applyAsDouble(a);
                resultContainer[0] += value;
                return () -> resultContainer[0] -= value;
            };
        }
        
        @Override
        public Function<double[], Double> finisher() {
            return resultContainer -> resultContainer[0];
        }
    }
}

使用它需要您自担风险,并确保您 check for score corruptions,最好是在一个很长的求解器中 运行。