Optimization 谷歌优化工具支持软约束吗?

Optimization 谷歌优化工具支持软约束吗?,optimization,constraints,optaplanner,constraint-programming,Optimization,Constraints,Optaplanner,Constraint Programming,我想知道是否有熟悉谷歌优化工具的人可以解决这个问题。我在看谷歌的员工日程安排和N-queens。这两个示例似乎都只在硬约束条件下运行优化器,例如,必须这样做,但似乎无法解决问题。这是首选,但不是必需的。是否支持软约束?还是目前唯一的软约束实现 我不反对optaplanner。学习足够的java和drools语法需要付出更多的努力 软约束的实现 正如Erwin所指出的,为了实现软约束,我们需要向模型中添加松弛变量,并将它们放入目标函数中。为此,我们为问题中的每个软约束变量再添加两个决策变量。这些决

我想知道是否有熟悉谷歌优化工具的人可以解决这个问题。我在看谷歌的员工日程安排和N-queens。这两个示例似乎都只在硬约束条件下运行优化器,例如,必须这样做,但似乎无法解决问题。这是首选,但不是必需的。是否支持软约束?还是目前唯一的软约束实现

我不反对optaplanner。学习足够的java和drools语法需要付出更多的努力

软约束的实现 正如Erwin所指出的,为了实现软约束,我们需要向模型中添加松弛变量,并将它们放入目标函数中。为此,我们为问题中的每个软约束变量再添加两个决策变量。这些决策变量代表我们感兴趣的变量中的松弛。然后,我们可以使用以下公式创建软约束:

x1 + x1_surplus - x1_deficit = goal
其中x1是我们的决策变量,x1_盈余和x1_赤字分别是我们的正松弛变量和负松弛变量,目标是我们针对决策变量x1设定的数字

一旦我们有了这个约束条件,我们必须添加一个目标,使总偏差百分比最小化,如下所示:

minimize:
    (1/goal) * x1_surplus + (1/goal) * x1_deficit
注:

我们使用百分比偏差,因为我们经常处理以不同单位测量的变量,例如下面示例中的千克与磅。如果我们不使用百分比偏差,变量中的松弛效应将是不平衡的

谷歌或工具中的示例 下面是Google或Tools中的一个基本工作示例。在这里,我们生产两种产品,A和B,每种产品我们都有一定数量的产品。我们还有一个与制造这些产品相关的成本,以及在这种情况下,我们希望在制造产品上花费+/-10000的金额目标

from ortools.linear_solver import pywraplp

solver = pywraplp.Solver("Soft Constraint Example", pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)

product_a = solver.IntVar(0, 10000, "Pounds of Product A:")
product_b = solver.IntVar(0, 10000, "Pounds of Product B:")

product_a_surplus = solver.IntVar(0, 100, "Product A Surplus:")
product_a_deficit = solver.IntVar(0, 100, "Product A Deficit:")

product_b_surplus = solver.IntVar(0, 100, "Product B Surplus:")
product_b_deficit = solver.IntVar(0, 100, "Product B Deficit:")

cost_surplus = solver.IntVar(0, 10000, "Cost Surplus:")
cost_deficit = solver.IntVar(0, 10000, "Cost Deficit:")

product_a_goal = solver.Add(product_a - product_a_surplus + product_a_deficit == 500)
product_b_goal = solver.Add(product_b - product_b_surplus + product_b_deficit == 250)

cost_goal = solver.Add(product_a * 100 + product_b * 200 - cost_surplus + cost_deficit == 75000)

solver.Minimize(
    (1/100) * product_a_surplus
    + (1/100) * product_a_deficit 
    + (1/200) * product_b_surplus 
    + (1/200) * product_b_deficit
    + (1/75000) * cost_surplus
    + (1/75000) * cost_deficit
)

status = solver.Solve()

print(status == solver.OPTIMAL)

final_cost = product_a.solution_value() * 100 + product_b.solution_value() * 200

print("Final Cost:", final_cost)

var = [product_a, product_b, product_a_surplus, product_a_deficit, 
       product_b_surplus, product_b_deficit,
       cost_surplus, cost_deficit]

for v in var:
    print(v.name(), v.solution_value())
软约束的实现 正如Erwin所指出的,为了实现软约束,我们需要向模型中添加松弛变量,并将它们放入目标函数中。为此,我们为问题中的每个软约束变量再添加两个决策变量。这些决策变量代表我们感兴趣的变量中的松弛。然后,我们可以使用以下公式创建软约束:

x1 + x1_surplus - x1_deficit = goal
其中x1是我们的决策变量,x1_盈余和x1_赤字分别是我们的正松弛变量和负松弛变量,目标是我们针对决策变量x1设定的数字

一旦我们有了这个约束条件,我们必须添加一个目标,使总偏差百分比最小化,如下所示:

minimize:
    (1/goal) * x1_surplus + (1/goal) * x1_deficit
注:

我们使用百分比偏差,因为我们经常处理以不同单位测量的变量,例如下面示例中的千克与磅。如果我们不使用百分比偏差,变量中的松弛效应将是不平衡的

谷歌或工具中的示例 下面是Google或Tools中的一个基本工作示例。在这里,我们生产两种产品,A和B,每种产品我们都有一定数量的产品。我们还有一个与制造这些产品相关的成本,以及在这种情况下,我们希望在制造产品上花费+/-10000的金额目标

from ortools.linear_solver import pywraplp

solver = pywraplp.Solver("Soft Constraint Example", pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)

product_a = solver.IntVar(0, 10000, "Pounds of Product A:")
product_b = solver.IntVar(0, 10000, "Pounds of Product B:")

product_a_surplus = solver.IntVar(0, 100, "Product A Surplus:")
product_a_deficit = solver.IntVar(0, 100, "Product A Deficit:")

product_b_surplus = solver.IntVar(0, 100, "Product B Surplus:")
product_b_deficit = solver.IntVar(0, 100, "Product B Deficit:")

cost_surplus = solver.IntVar(0, 10000, "Cost Surplus:")
cost_deficit = solver.IntVar(0, 10000, "Cost Deficit:")

product_a_goal = solver.Add(product_a - product_a_surplus + product_a_deficit == 500)
product_b_goal = solver.Add(product_b - product_b_surplus + product_b_deficit == 250)

cost_goal = solver.Add(product_a * 100 + product_b * 200 - cost_surplus + cost_deficit == 75000)

solver.Minimize(
    (1/100) * product_a_surplus
    + (1/100) * product_a_deficit 
    + (1/200) * product_b_surplus 
    + (1/200) * product_b_deficit
    + (1/75000) * cost_surplus
    + (1/75000) * cost_deficit
)

status = solver.Solve()

print(status == solver.OPTIMAL)

final_cost = product_a.solution_value() * 100 + product_b.solution_value() * 200

print("Final Cost:", final_cost)

var = [product_a, product_b, product_a_surplus, product_a_deficit, 
       product_b_surplus, product_b_deficit,
       cost_surplus, cost_deficit]

for v in var:
    print(v.name(), v.solution_value())
在OptaPlanner中,您不必再使用drools语法。您可以改为使用新的增量ConstraintStreams。ConstraintStreams快速且可扩展

下面是一个如何在您提出的NQueens问题上使用它们的示例:

protected Constraint horizontalConflict(ConstraintFactory factory) {
    // Select a queen
    return factory.from(Queen.class)
            // Select a different queen on the same row
            .join(Queen.class,
                    equal(Queen::getRowIndex),
                    lessThan(Queen::getId))
            // Tell OptaPlanner not to put 2 queens on the same row
            .penalize("Horizontal conflict", HardSoftScore.ONE_HARD);
}

// For reference, the model:
@PlanningEntity
class Queen {
     long id;
     int columnIndex;
     @PlanningVariable
     int rowIndex;
     ... // getters/setters
}
protected Constraint skillLacking(ConstraintFactory factory) {
    // Select a shift
    return factory.from(Shift.class)
            // The shift's employee doesn't have the required skill
            .filter(shift -> !shift.getEmployee().getSkillSet()
                    .contains(shift.getRequiredSkill())
            // Tell OptaPlanner to avoid that
            .penalize("Skill lacking", HardSoftScore.ONE_SOFT,
                    // Lose one soft point per minute of the shift
                    shift -> shift.getDurationInMinutes());
}

// For reference, the model:
@PlanningEntity
class Shift {
     Skill requiredSkill;
     LocalDateTime start;
     LocalDateTime end;
     @PlanningVariable
     Employee employee;
     ... // getters/setters
}
class Employee {
     String name;
     Set<Skill> skillSet;
     ... // getters/setters
}
同样,对于您询问的员工排班:

protected Constraint horizontalConflict(ConstraintFactory factory) {
    // Select a queen
    return factory.from(Queen.class)
            // Select a different queen on the same row
            .join(Queen.class,
                    equal(Queen::getRowIndex),
                    lessThan(Queen::getId))
            // Tell OptaPlanner not to put 2 queens on the same row
            .penalize("Horizontal conflict", HardSoftScore.ONE_HARD);
}

// For reference, the model:
@PlanningEntity
class Queen {
     long id;
     int columnIndex;
     @PlanningVariable
     int rowIndex;
     ... // getters/setters
}
protected Constraint skillLacking(ConstraintFactory factory) {
    // Select a shift
    return factory.from(Shift.class)
            // The shift's employee doesn't have the required skill
            .filter(shift -> !shift.getEmployee().getSkillSet()
                    .contains(shift.getRequiredSkill())
            // Tell OptaPlanner to avoid that
            .penalize("Skill lacking", HardSoftScore.ONE_SOFT,
                    // Lose one soft point per minute of the shift
                    shift -> shift.getDurationInMinutes());
}

// For reference, the model:
@PlanningEntity
class Shift {
     Skill requiredSkill;
     LocalDateTime start;
     LocalDateTime end;
     @PlanningVariable
     Employee employee;
     ... // getters/setters
}
class Employee {
     String name;
     Set<Skill> skillSet;
     ... // getters/setters
}
在OptaPlanner中,您不必再使用drools语法。您可以改为使用新的增量ConstraintStreams。ConstraintStreams快速且可扩展

下面是一个如何在您提出的NQueens问题上使用它们的示例:

protected Constraint horizontalConflict(ConstraintFactory factory) {
    // Select a queen
    return factory.from(Queen.class)
            // Select a different queen on the same row
            .join(Queen.class,
                    equal(Queen::getRowIndex),
                    lessThan(Queen::getId))
            // Tell OptaPlanner not to put 2 queens on the same row
            .penalize("Horizontal conflict", HardSoftScore.ONE_HARD);
}

// For reference, the model:
@PlanningEntity
class Queen {
     long id;
     int columnIndex;
     @PlanningVariable
     int rowIndex;
     ... // getters/setters
}
protected Constraint skillLacking(ConstraintFactory factory) {
    // Select a shift
    return factory.from(Shift.class)
            // The shift's employee doesn't have the required skill
            .filter(shift -> !shift.getEmployee().getSkillSet()
                    .contains(shift.getRequiredSkill())
            // Tell OptaPlanner to avoid that
            .penalize("Skill lacking", HardSoftScore.ONE_SOFT,
                    // Lose one soft point per minute of the shift
                    shift -> shift.getDurationInMinutes());
}

// For reference, the model:
@PlanningEntity
class Shift {
     Skill requiredSkill;
     LocalDateTime start;
     LocalDateTime end;
     @PlanningVariable
     Employee employee;
     ... // getters/setters
}
class Employee {
     String name;
     Set<Skill> skillSet;
     ... // getters/setters
}
同样,对于您询问的员工排班:

protected Constraint horizontalConflict(ConstraintFactory factory) {
    // Select a queen
    return factory.from(Queen.class)
            // Select a different queen on the same row
            .join(Queen.class,
                    equal(Queen::getRowIndex),
                    lessThan(Queen::getId))
            // Tell OptaPlanner not to put 2 queens on the same row
            .penalize("Horizontal conflict", HardSoftScore.ONE_HARD);
}

// For reference, the model:
@PlanningEntity
class Queen {
     long id;
     int columnIndex;
     @PlanningVariable
     int rowIndex;
     ... // getters/setters
}
protected Constraint skillLacking(ConstraintFactory factory) {
    // Select a shift
    return factory.from(Shift.class)
            // The shift's employee doesn't have the required skill
            .filter(shift -> !shift.getEmployee().getSkillSet()
                    .contains(shift.getRequiredSkill())
            // Tell OptaPlanner to avoid that
            .penalize("Skill lacking", HardSoftScore.ONE_SOFT,
                    // Lose one soft point per minute of the shift
                    shift -> shift.getDurationInMinutes());
}

// For reference, the model:
@PlanningEntity
class Shift {
     Skill requiredSkill;
     LocalDateTime start;
     LocalDateTime end;
     @PlanningVariable
     Employee employee;
     ... // getters/setters
}
class Employee {
     String name;
     Set<Skill> skillSet;
     ... // getters/setters
}

可以使用任何解算器实现软约束。只需使约束具有弹性,即添加宽松裤,并将其放入目标中,同时进行惩罚。我非常感谢您的回答。我一直在浏览Google或工具和示例。我看不出在目标函数参数中可以添加松弛/弹性。你知道这可能记录在哪里吗?这不是唯一的或工具,但更一般。LP手册可能会有所帮助。您可以使用任何解算器实现软约束。只需使约束具有弹性,即添加宽松裤,并将其放入目标中,同时进行惩罚。我非常感谢您的回答。我一直在浏览Google或工具和示例。我看不出在目标函数参数中可以添加松弛/弹性。你知道这可能记录在哪里吗?这不是唯一的或工具,但更一般。一本LP书可能会有所帮助。