【问题标题】:Is there any way to improve speed of or-tools?有什么方法可以提高 or-tools 的速度吗?
【发布时间】:2020-11-18 22:02:46
【问题描述】:

我正在尝试使用 or-tools 来解决 MIP 问题。它可以在较小的 Number 和 Range 下运行得非常快,您可以将它们视为变量的数量和约束的数量。但对于较大的值,它运行速度较慢,有时甚至无法得到可行的结果。如果 Number= 1,000,000 和 Range = 10,000,还有其他方法可以提高速度吗?

问题描述

变量:x,r, #x=#r=Number

对象:最小化 (sum(r))

受制于: (1) r 为 0 或 1。

(2) x 是整数。

(3) x

(4) 对于桶中的任何唯一项,sum(x[buckets==item]) 落在 [count(item)*0.9,count(item)*1.1]

(5) 如果 x >0

,x 可能有一个下界
from __future__ import print_function
from ortools.sat.python import cp_model
import numpy as np
import pandas as pd

np.random.seed(1)


def set_up_buckets(Number,Range,mu=0,sigma=1):
    buckets = (np.random.normal(0, 1, Number)*Range).astype(int)
    print("number of buckets:",len(np.unique(buckets)))
    return buckets

model = cp_model.CpModel()
Number = 1000000
Range = 10000
Infinity = int(Number/10)
buckets = set_up_buckets(Number,Range)

def reduce_intervals(buckets,Range,sigma_cnt,mu=0,sigma=1):
    upper = (mu+sigma*sigma_cnt)*Range
    lower = (mu-sigma*sigma_cnt)*Range
    buckets_reduced = buckets[(buckets<=upper)&(buckets>=lower)]
    return buckets_reduced

buckets_reduced = reduce_intervals(buckets,Range,2)

def set_up_variables(Number):
    x,r = [],[]
    for i in range(Number):
        x.append(model.NewIntVar(0, Infinity, 'x{}'.format(i+1)))
        r.append(model.NewBoolVar('r{}'.format(i+1)))  
    return np.array(x),np.array(r)

x,r = set_up_variables(Number)

%%time
def set_up_constraints(Number,unique_buckets):
    M = Number
    x_lower_bound = int(Number/10000)
#     x_upper_bound = int(Number/10)
    print("add attributes constraints")
    for i in unique_buckets:
        xs = x[buckets==i]
        model.Add(sum(xs) <= int(1.1*len(xs)))
        model.Add(sum(xs) >= int(0.9 * len(xs)))

    print("add x&r constraints")    
    for i in range(Number):
        model.Add(x[i] <= M*r[i])
        model.Add(x_lower_bound - x[i] <= M*(1-r[i]))
    
    model.Minimize(sum(r))
    return model

model = set_up_constraints(Number,np.unique(buckets_reduced))


def solve_model(model,max_seconds = 60*60):
    solver = cp_model.CpSolver()
    solver.parameters.log_search_progress = True
    solver.parameters.num_search_workers = 8
    solver.parameters.max_time_in_seconds = max_seconds
    status = solver.Solve(model)
    return solver,status

solver,status = solve_model(model)

【问题讨论】:

  • 你可以试试num_search_workers = 8。根据 OR-Tools 的开发人员 (Laurent Perron) 的说法,最佳多样性,因此 CP-SAT 的稳健性和性能受到 8 个线程的影响。根据我有限的经验,这是真的。请参阅此答案的 cmets:or.stackexchange.com/a/4126/2477。如果减少大 M 的值有帮助,也可以尝试 - 这将取决于特定的实例(数据)。
  • 1 小时后,您还没有建立模型 :-) 因此,此时搜索参数无关紧要。

标签: optimization mathematical-optimization or-tools mixed-integer-programming integer-programming


【解决方案1】:

set_up_constraints 方法是灾难性的,您正在以密集的方式扫描 O(Number ^ 2) 元素以构建非常稀疏的线性不等式。

您可以尝试不同的代码,例如下面的代码不会创建大多数 x[i] * 0,但仍然很慢。

for i in unique_buckets:
    xs = [x[j] for j in range(len(x)) if buckets[j] == i]
    model.Add(sum(xs) <= int(1.1*len(xs)))
    model.Add(sum(xs) >= int(0.9 * len(xs)))

不管怎样,暂时来说,性能问题来自你的代码,而不是or-tools。

【讨论】:

  • 谢谢劳伦特。我将此代码更改为 numpy 数组。现在可以在 2 分钟内设置 Number= 1,000,000 和 Range = 10,000 的约束。
  • 嗨 Laurent,现在它可以在 2 分钟内设置约束,但它会消耗大量内存。有没有其他方法可以提高性能?如您所见,我正在尝试测试 Ortools 的限制,因此我模拟了这些数据。因此,我们可以为最优或可行的解决方案添加尽可能多的约束。
猜你喜欢
  • 2011-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-05
  • 1970-01-01
相关资源
最近更新 更多