Package: wrapdisc
wrapdiscwrapdiscis a Python 3.10 package to wrap a discrete optimization objective such that it can be optimized by a continuous optimizer such as inscipy.optimize.
It maps the discrete variables into a continuous space, and uses an in-memory cache over the discrete space.
Both discrete and continuous variables are supported, and are motivated byRay Tune's search spaces.LimitationsThe use of an unbounded in-memory cache over the original objective function imposes a memory requirement.
If multiple workers are used, each worker has its own such cache, thereby using additional memory for each worker.
This cache prevents duplicated calls to the original objective function in a worker.The ability to support constraints such asscipy.optimize.NonlinearConstraintorscipy.optimize.LinearConstraintis unclear.
A constraint can however be modeled by returninginfupon its violation in the original objective function.LinksCaptionLinkRepohttps://github.com/impredicative/wrapdisc/Changeloghttps://github.com/impredicative/wrapdisc/releasesPackagehttps://pypi.org/project/wrapdisc/InstallationPython ≥3.10 is required. To install, run:pip install wrapdiscNo additional third-party packages are required or installed.VariablesThe following classes of variables are available:SpaceUsageDescriptionDecoderExamplesDiscreteChoiceVar(items)Nominal (unordered categorical)one-hot via max• fn(["USA", "Panama", "Cayman"])DiscreteGridVar(values)Ordinal (ordered categorical)round• fn([2, 4, 8, 16])• fn(["good", "better", "best"])DiscreteRandintVar(lower, upper)Integer fromlowertoupper, both inclusiveround• fn(0, 6)• fn(3, 9)• fn(-10, 10)DiscreteQrandintVar(lower, upper, q)Quantized integer fromlowertoupperin multiples ofqround to a multiple• fn(0, 12, 3)• fn(1, 10, 2)• fn(-10, 10, 4)ContinuousUniformVar(lower, upper)Float fromlowertoupperpassthrough• fn(0.0, 5.11)• fn(0.2, 4.6)• fn(-10.0, 10.0)ContinuousQuniformVar(lower, upper, q)Quantized float fromlowertoupperin multiples ofqround to a multiple• fn(0.0, 5.1, 0.3)• fn(-5.1, -0.2, 0.3)UsageExample:importoperatorfromtypingimportAnyimportscipy.optimizefromwrapdiscimportObjectivefromwrapdisc.varimportChoiceVar,GridVar,QrandintVar,QuniformVar,RandintVar,UniformVardefyour_mixed_optimization_objective(x:tuple,*args:Any)->float:returnfloat(sum(x_iifisinstance(x_i,(int,float))elselen(str(x_i))forx_iin(*x,*args)))wrapped_objective=Objective(your_mixed_optimization_objective,variables=[ChoiceVar(["foobar","baz"]),ChoiceVar([operator.index,abs,operator.invert]),GridVar([0.01,0.1,1,10,100]),GridVar(["good","better","best"]),RandintVar(-8,10),QrandintVar(1,10,2),UniformVar(1.2,3.4),QuniformVar(-11.1,9.99,0.22),],)bounds=wrapped_objective.boundsoptional_fixed_args=("arg1",2,3.0)optional_initial_decoded_guess=("foobar",operator.invert,10,"better",0,8,2.33,8.8)optional_initial_encoded_guess=wrapped_objective.encode(optional_initial_decoded_guess)result=scipy.optimize.differential_evolution(wrapped_objective,bounds=bounds,seed=0,args=optional_fixed_args,x0=optional_initial_encoded_guess)cache_usage=wrapped_objective.cache_infoencoded_solution=result.xdecoded_solution=wrapped_objective.decode(encoded_solution)assertresult.fun==wrapped_objective(encoded_solution,*optional_fixed_args)assertresult.fun==your_mixed_optimization_objective(decoded_solution,*optional_fixed_args)Output:>>>bounds((0.0,1.0),(0.0,1.0),(0.0,1.0),(0.0,1.0),(0.0,1.0),(-0.49999999999999994,4.499999999999999),(-0.49999999999999994,2.4999999999999996),(-8.499999999999998,10.499999999999998),(1.0000000000000002,10.999999999999998),(1.2,3.4),(-11.109999999999998,10.009999999999998))>>>resultfun:23.21jac:array([0.,0.,0.,0.,0.,0.,0.,0.,0.,1.00000009,0.])message:'Optimization terminated successfully.'nfev:7944nit:47success:Truex:array([0.22045614,0.95317493,0.22747255,0.53879713,0.18086281,0.222759,0.33591717,-8.29118977,1.77128301,1.2,-10.97230444])>>>decoded_solution('baz',<built-infunctionabs>,0.01,'good',-8,2,1.2,-11.0)>>>your_mixed_optimization_objective(decoded_solution,*optional_fixed_args)23.21>>>cache_usageCacheInfo(hits=146,misses=7798,maxsize=None,currsize=7798)