如何在Mystic中应用不平等约束

时间:2019-12-04 12:20:55

标签: python-3.x optimization non-convex mystic

我正在尝试使用Mystic将不平等约束下的目标最大化,但是正在努力寻找如何应用惩罚约束的方法。问题是非凸性的,涉及最大化只有一个变量(x)的目标。我正在尝试Mystic,因为我听说它对大规模优化非常有帮助,并且x是一个包含数百万个项目(大小为N)的一维数组。

存在三个数字a,b和c的一维数组,每个数组都具有N个值(a和b中的值在0-1之间)。 x中的每个项目都将大于> = 0

def objective(x, a, b, c):   # maximise
    d = 1 / (1 + np.exp(-a * (x)))
    return np.sum(d * (b * c - x))

def constraint(x, f=1000):   # must be >=0
    return f - x.sum()

bounds = [(0, None)]

我已经看到了使用generate_penaltygenerate_constraint函数的示例,并认为我可以使用以下内容来实现约束,但未成功:

equations = """
1000 - np.sum(x) >= 0
"""

通常,任何有关如何应用惩罚约束的建议或通常使用Mystic的建议都将受到赞赏。 Github上有很多示例,但是很难看出其中哪个是合适的。我已经使用SLSQP使用Scipy Minimum实现了一个解决方案,但是在所需规模​​下它太慢了。

1 个答案:

答案 0 :(得分:0)

我认为您要提出的问题看起来类似于以下内容……尽管其中实际上并没有太多的不平等约束,而仅仅是一个。我没有使用数百万个项目...这将花费大量时间,并且可能需要进行大量参数调整...但是我在下面使用了N = 100。

import numpy as np
import mystic as my
N = 100 #1000 # N=len(x)
M = 1e10 # max of c_i
K = 1000 # max of sum(x)
Q = 4 # 40 # npop = N*Q
G = 200 # gtol

# arrays of fixed values
a = np.random.rand(N)
b = np.random.rand(N)
c = np.random.rand(N) * M

# build objective
def cost_factory(a, b, c, max=False):
    i = -1 if max else 1
    def cost(x):
        d = 1. / (1 + np.exp(-a * x))
        return i * np.sum(d * (b * c - x))
    return cost

objective = cost_factory(a, b, c, max=True)
bounds = [(0., K)] * N

def penalty_norm(x): # < 0
    return np.sum(x) - K

# build penalty: sum(x) <= K
@my.penalty.linear_inequality(penalty_norm, k=1e12)
def penalty(x):
    return 0.0

# uncomment if want hard constraint of sum(x) == K
#@my.constraints.normalized(mass=1000)
def constraints(x):
    return x

然后运行脚本...

if __name__ == '__main__':
    mon = my.monitors.VerboseMonitor(10)
    #from pathos.pools import ThreadPool as Pool
    #from pathos.pools import ProcessPool as Pool
    #p = Pool()
    #Powell = my.solvers.PowellDirectionalSolver

    # use class-based solver interface
    """
    solver = my.solvers.DifferentialEvolutionSolver2(len(bounds), N*Q)
    solver.SetGenerationMonitor(mon)
    solver.SetPenalty(penalty)
    solver.SetConstraints(constraints)
    solver.SetStrictRanges(*my.tools.unpair(bounds))
    solver.SetRandomInitialPoints(*my.tools.unpair(bounds))
    solver.SetTermination(my.termination.ChangeOverGeneration(1e-8,G))
    solver.Solve(objective, CrossProbability=.9, ScalingFactor=.8)
    result = [solver.bestSolution]
    print('cost: %s' % solver.bestEnergy)
    """

    # use one-line interface
    result = my.solvers.diffev2(objective, x0=bounds, bounds=bounds, penalty=penalty, constraints=constraints, npop=N*Q, ftol=1e-8, gtol=G, disp=True, full_output=True, cross=.9, scale=.8, itermon=mon)#, map=p.map)

    # use ensemble of fast local solvers
    #result = my.solvers.lattice(objective, len(bounds), N*Q, bounds=bounds, penalty=penalty, constraints=constraints, ftol=1e-8, gtol=G, disp=True, full_output=True, itermon=mon)#, map=p.map)#, solver=Powell)

    #p.close(); p.join(); p.clear()
    print(np.sum(result[0]))

我也评论了并行计算的一些用法,但是很容易取消注释。

我认为您可能必须非常努力地调整求解器,才能找到该特定问题的全局最大值。由于N的大小,它还需要有足够的并行元素。

但是,如果您想使用符号约束作为输入,则可以这样做:

eqn = ' + '.join("x{i}".format(i=i) for i in range(N)) + ' <= {K}'.format(K=K)
constraint = my.symbolic.generate_constraint(my.symbolic.generate_solvers(my.symbolic.simplify(eqn)))

或者,对于软约束(即惩罚):

penalty = my.symbolic.generate_penalty(my.symbolic.generate_conditions(eqn))