I think the problem you are asking looks something like the following... although there's not really too many inequality constraints in it -- just one. I'm not using millions of items... as that would take a lot of time, and probably a good bit of parameter tuning... but I used N=100 below.
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
And then in to run the script...
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]))
I've also commented out some use of parallel computing, but it's easy to uncomment.
I think you might have to work pretty hard tuning the solver to get it to find the global maximum for this particular problem. It also needs to have enough parallel elements... due to the large size of N.
However, if you wanted to use symbolic constraints as an input, you'd do it like this:
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)))
or, for the soft constraint (i.e. penalty):
penalty = my.symbolic.generate_penalty(my.symbolic.generate_conditions(eqn))