Package: pyoptquest
Getting Started With PyOptQuestOptQuest is a simulation optimization engine built on a truly unique set of powerful algorithms and sophisticated analysis techniques including metaheuristics optimization, evolutionary algorithms, tabu search and scatter search, to name a few. We provide two interfaces to the OptQuest Engine which is written in Java.  1) Thepyoptquestmodule provides wrappers around the Java classes so the full functionality of OptQuest can be accessed as if it were being called from a Java application.  2) TheOptQuestOptimizerPython class is a wrapper around the OptQuest engine JAR, providing a Python interface to the engine.Note that an OptQuest license is necessary in order to use the OptQuestEngine. Inquire at our website to get a trial license if you need one:https://www.opttek.com/products/optquest/Installing PyOptQuestThe easiest way to install PyOptQuest is to use thepippackage manager> pip install pyoptquestThis will install all of the dependencies (except Java), including pyjnius which is used to communicate with Java. You will need to install your own copy of Java version 17. We use a Java Native Interface (JNI) bridge to the Java Virtual Machine (JVM) to map Python functions to the Java library.  The hardest part of setting up PyOptQuest is getting your Python environment to connect with your installation of Java.  Make sure that you have the Java directories on the path and that your Python environment can reach Java.In the examples directory, we provide a test Python script that tests the Python-Java interface without any dependencies on OptQuest.  If this works, you can be sure that your Python environment can see you Java installationexamples> python hello.py
Hello World!Java-like InterfaceWith this interface, you will program in Python following the exact same patterns and exact same class names as you would in Java. That is, you can follow the OptQuest java documentation as written:https://www.opttek.com/doc/v811engine/OptQuest_Engine_Documentation/OptQuest.htm.This interface is perfect for the OptQuest expert who want the same Java patterns available in Python and needs full control over all of the optimization parameters.ExamplesIn the examples directory, we provide a few Java-like examples written in Python.  Since this interface maps 1:1 with the Java interface, it’s best to use the detailed documentation from our website linked above.Example NameDescriptionexample_simple.pyA very simple example that shows how to set up an optimization in Python and call the Java optimization.example_solver.pyAn example uses a string expression that’s evaluated in Java rather than a Python function for the objective.example_frontier.pyAn example of a two-objective optimization.example_parallel.pyAn example of running multiple evaluators in parallel.  With the Java-like interface, you need to manage the messaging between threads for parallel execution.  The Pythonic interface is able to manage that for you, and is a much simpler way to get parallel evaluations.example_replication.pyAn example of a stochastic optimization where OptQuest will manage replications of the same solution.example_replicaton_with_confidence.pyAn advanced example of stochastic optimization where OptQuest checks the confidence interval of the solution to dynamically control the replications.Pythonic InterfaceThe pythonic interface is designed to seamlessly plug into Simon Blanke'sGradient Free Optimizers, but does not require the Gradient Free Optimizer code to work.Minimal ExampleHere is an example usingOptQuestOptimizerto minimize $x^2$ over the search space $x \in [-10,10]$.frompyoptquestimportOptQuestOptimizer# define the input(s)search_space={'x':{'type':'continuous','min':-10,'max':10}}# define the objective(s)objectives={'y':{'type':'min','expression':'x * x'}}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,license_id=999999999,optquest_jar=r'../OptQuest.jar')opt.search(n_iter=10)# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:best score: 0.0
best parameters: {'x': 0.0}
Optimization time: 0.045327186584472656The first step in designing an optimization is to define thesearch_space. Thesearch_spaceis a dictionary of variable names mapped to their properties. In the example, we simply define a continuous variable that can take on values between -10 and 10. You can view all supported variable types and their properties in theSupported Variable Typessection.At least one objective must be defined and given an optimizationtype. An objective can be of the typemin(minimize) ormax(maximize). The'expression'property indicates that the objective will be represented by a simple mathematical expression provided by the user as a string. In this case, the expression isx * xor $x^2$.Once a search space and objective have been defined it is possible to run a minimal optimization. Note that the license ID and OptQuest JAR file path must be provided when creating the optimization. Finally, callsearch()with a specified number of iterations (n_iter) on the optimizer object (opt) and the optimization will begin.The output shows thatOptQuestOptimizerfound the best solution. The optimal value and solution can be obtained from the optimizer object after the optimization by callingbest_score()andbest_para().Example with Simulation EvaluatorOptQuestOptimizeris tailored toward optimizing simulated problems rather than purely mathematical ones.When designing an optimization, we are not limited to specifying simple mathematical objectives; we can provide a custom evaluator callback function that uses inputs given byOptQuestOptimizerand returns output values. The output values can then be used by objectives. For example, the custom evaluator could call an external process to start a simulation with the provided input values. The sole purpose of output values is to have a means of collecting information from the evaluator. Inputs are passed to the evaluator, and outputs are collected from it. Note that this is a distinct type of evaluator from constraint and objective evaluators, which return a boolean value or single numerical value, respectively.Here is an example using an evaluator function namedsimulation; a small modification on the previous example:frompyoptquestimportOptQuestOptimizerdefsimulation(inputs):# get inputs from OptQuestOptimizerx=inputs['x']# run the "simulation"y=x**2# create dict to hold return values from the simulationoutputs={'y':y}returnoutputs# define the input(s)search_space={'x':{'type':'continuous','min':-10,'max':10}}# specify the output(s) of the simulation evaluator (the output(s) of the simulation() function)output_space=['y']# define the objective(s)objectives={'obj':{'type':'min','expression':'y'}# minimize the output "y"}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,evaluator=simulation,output_space=output_space,license_id=999999999,optquest_jar=r'../OptQuest.jar')opt.search(n_iter=10)# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:best score: 0.0
best parameters: {'x': 0.0, 'y': 0.0}
Optimization time: 0.0624852180480957The result is the same as the previous examples, but we used a user-supplied evaluator callback function to generate an outputywhich was then used by the objectiveobj.Example with Objective EvaluatorObjectives are not limited to being string expressions and can be defined with a function evaluator that takesinputsand optionallyoutputsas parameters. The example below shows an objective evaluator callback function that only takesinputsas a parameter:frompyoptquestimportOptQuestOptimizer# function to evaluate the objectivedefobjective_evaluator(inputs):x=inputs['x']returnx**2# define the input(s)search_space={'x':{'type':'continuous','min':-10,'max':10}}# define the objective(s)objectives={'y':{'type':'min','evaluator':objective_evaluator}# specify the evaluator}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,license_id=999999999,optquest_jar=r'../OptQuest.jar')opt.search(n_iter=10)# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:best score: 0.0
best parameters: {'x': 0.0}
Optimization time: 0.09617185592651367The result is the same as the previous examples, but we used a user-supplied objective evaluator function instead of a simple mathematical string expression.The difference between an objective evaluator callback function and an an evaluator callback function is that the objective evaluator can only return a single value that can't be used by other objectives while an evaluator can return multiple outputs that can be used by multiple objectives.Constraints ExampleConsider theMinimal Examplewhere we are trying to minimize the objectivey=$x^2$ for $x\in[-10,10]$. $x$ is constrained to be on the interval $[-10,10]$, but we can specify more complex constraints. Let's add the constraint that the objectivey$=x^2$ must be above the line $0.1x+1$. The problem now looks like this:Here is how this problem can be solved usingOptQuestOptimizer:frompyoptquestimportOptQuestOptimizer# define the input(s)search_space={'x':{'type':'continuous','min':-10,'max':10}}# define the objective(s)objectives={'y':{'type':'min','expression':'x * x'}}constraints={'my_constraint':{'expression':'x * x >= 0.1 * x + 1'}}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,constraints=constraints,license_id=999999999,optquest_jar=r'../OptQuest.jar')opt.search(n_iter=100)# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:best score: 0.9164935413654939
best parameters: {'x': -0.9573366917472107}
Optimization time: 0.13147902488708496We can also see all the solutions that were evaluated:# print all solutionsprint('all solutions:')print(opt.search_data)Output:all solutions:
    iteration  replication  feasible           y          x
0           1            1     False    0.000000   0.000000
1           2            1      True  100.000000 -10.000000
2           3            1      True  100.000000  10.000000
3           4            1      True   25.000000  -5.000000
4           5            1      True   25.000000   5.000000
..        ...          ...       ...         ...        ...
95         96            1      True   20.200825  -4.494533
96         97            1      True   49.104083  -7.007431
97         98            1      True   50.107366   7.078656
98         99            1      True   89.333619   9.451646
99        100            1     False    0.013505   0.116211

[100 rows x 5 columns]Notice the third column which indicates whether a solution was in the feasible region or not.Multiple constraints can be defined inconstraints, but they must all have unique names. A constraint can also be
the result of a callback function that returns a boolean instead of a string expression. Here is an example of a
problem with an evaluated constraint:frompyoptquestimportOptQuestOptimizerdefdomain_constraint(inputs):x=inputs['x']returnabs(x)>=1# define the input(s)search_space={'x':{'type':'continuous','min':-10,'max':10}}# define the objective(s)objectives={'y':{'type':'min','expression':'x * x'}}constraints={'domain':{'evaluator':domain_constraint},}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,constraints=constraints,license_id=999999999,optquest_jar=r'../OptQuest.jar')opt.search(n_iter=300)# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:best score: 1.0
best parameters: {'x': 1.0}
Optimization time: 0.2471938133239746The optimal solutions are at $x=1$ and $x=-1$.Parallel Evaluation ExampleParallelization is easy when using the optimizer. Simply pass the number of parallel executions you'd like to run toOptQuestOptimizer.search(), specify the number ofparallel_evaluatorsi.e. processes you'd like to have running, and that's it.If we want to parallelize theMinimal Examplewe can simply change the line:opt.search(n_iter=10)# non-parallel executionto:opt.search(n_iter=100,parallel_evaluators=2)# parallel executionRemember, while Python supports threads and parallel execution semantics, Python code itself does not run concurrently. So parallel evaluation will only be a time-saver if you spawn external processes, like long-running simulations.Here is a made up example of a problem that benefits from parallelization:importtimefrompyoptquestimportOptQuestOptimizer# represents a large simulation running for one seconddefsleep_evaluator(inputs):time.sleep(1)return{}# define the input(s)search_space={'x':{'type':'continuous','min':-10,'max':10}}# define the objective(s)objectives={'y':{'type':'min','expression':'pow(x - pi, 2)'}}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,evaluator=sleep_evaluator,license_id=999999999,optquest_jar=r'../OptQuest.jar')opt.search(n_iter=100,parallel_evaluators=20)# increasing parallel_evaluators will decrease the optimization time# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:best score: 6.007550195017685e-07
best parameters: {'x': 3.1408175697107796}
Optimization time: 5.143232583999634Since thesleep_evaluatorfunction executes for one second and we do 100 iterations, 20 at a time, the simulation takes about five seconds to execute (1 second * 100 iterations / 20 in parallel.)Replications ExampleReplications are extra evaluations executed on the same input(s) for the purpose of accounting for variability in simulations. It is recommended to useparallel evaluatorswhen running replications on large simulations.OptQuestOptimizerhas support for replications of an evaluation for a given set of inputs, but it does not provide any sort of random seed.The user can set a fixed number of replications to be executed, or a variable number of executions. To set a variable number of replications, a minimum and maximum number of replications is specified.OptQuestOptimizerwill execute the minimum number of replications and then continue running replications until each objective has reached 95% confidence or the maximum number of replications have been executed.To set a fixed number of replications, simply callOptQuestOptimizer.search()like this:opt.search(n_iter=10,replications=20)# run 20 replicationsTo set a variable number of replications, pass a tuple toOptQuestOptimizer.search()containing the minimum and maximum number of replications, respectively:opt.search(n_iter=10,replications=(5,20))# run between 5 and 20 replicationsHere is an example of an optimization with variable replications (note the use of astatus monitorto track the progress):importrandomfrompyoptquestimportOptQuestOptimizer# optional function for tracking the status of the optimization, called every iteration/replicationdefstatus_monitor(inputs,outputs,objectives,iteration,replication):print(f'--executing{iteration}, replication{replication}')# return a random number close to 1 so that a random number of replications are called for by OptQuestdefobjective_evaluator(dec_var_values,output_values):return1+(random.random()-0.5)*0.2# define the input(s)search_space={'x':{'type':'continuous','min':-10,'max':10}}# define the objective(s)objectives={'y':{'type':'min','evaluator':objective_evaluator}}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,status_monitor=status_monitor,license_id=999999999,optquest_jar=r'../OptQuest.jar')opt.search(n_iter=2,replications=(5,20))# opt.search(n_iter=10, replications=20)  # fixed replicationsprint()# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:--executing 1, replication 1
--executing 1, replication 2
--executing 1, replication 3
--executing 1, replication 4
--executing 1, replication 5
--executing 1, replication 6
--executing 1, replication 7
--executing 1, replication 8
--executing 1, replication 9
--executing 2, replication 1
--executing 2, replication 2
--executing 2, replication 3
--executing 2, replication 4
--executing 2, replication 5
--executing 2, replication 6
--executing 2, replication 7

best score: 1.0059779289574402
best parameters: {'x': 0.0}
Optimization time: 0.06905317306518555Notice that for the first iteration of inputs, confidence was met after nine replications. For the second iteration of inputs it only took seven replications before confidence was met.Advanced Variable ReplicationsWhen using variable replications OptQuest will continue to execute replications until it executes the max replications or until confidence is met for all objectives. By default, confidence is met when, over all executed replications, the objective value is within 5% of the mean 95% of the time.However, some objectives don't require the same amount confidence that others do. You have the ability to change the confidence parameters for each objective when defining them.Below is an example of an objective defined with user-specified confidence parameters:importrandomfrompyoptquestimportOptQuestOptimizer# optional function for tracking the status of the optimization, called every iteration/replicationdefstatus_monitor(inputs,outputs,objectives,iteration,replication):print(f'--executing{iteration}, replication{replication}')# return a random number close to 1 so that a random number of replications are called for by OptQuestdefobjective_evaluator(dec_var_values,output_values):return1+(random.random()-0.5)*0.2# define the input(s)search_space={'x':{'type':'continuous','min':-10,'max':10}}# define the objective(s)objectives={'y':{'type':'min','evaluator':objective_evaluator,'confidence':5,'error':0.04}# confidence 5 means 99% confidence interval}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,status_monitor=status_monitor,license_id=999999999,optquest_jar=r'../OptQuest.jar')opt.search(n_iter=2,replications=(5,20))print()# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:--executing 1, replication 1
--executing 1, replication 2
--executing 1, replication 3
--executing 1, replication 4
--executing 1, replication 5
--executing 1, replication 6
--executing 1, replication 7
--executing 1, replication 8
--executing 1, replication 9
--executing 1, replication 10
--executing 2, replication 1
--executing 2, replication 2
--executing 2, replication 3
--executing 2, replication 4
--executing 2, replication 5
--executing 2, replication 6
--executing 2, replication 7
--executing 2, replication 8
--executing 2, replication 9
--executing 2, replication 10
--executing 2, replication 11
--executing 2, replication 12
--executing 2, replication 13
--executing 2, replication 14
--executing 2, replication 15
--executing 2, replication 16

best score: 0.9853533444387222
best parameters: {'x': -10.0}
Optimization time: 0.04686570167541504We setconfidenceto5anderrorto0.04; we tightened the confidence required on this objective. Confidence 5 means we want a 99% confidence interval, and an error of 0.04 means that the grouping around the mean has a tolerance of 4%. For this objective confidence will be met when the objective value is within 4% of the mean 99% of the time.In the previous example only 9 and 7 replications were run before confidence was met. In this example 10 and 16 replications were run before confidence was met because there was tighter tolerance on the objective and more replications were needed in order to reach that tolerance.Multi-Objective ExampleOptQuestOptimizercan optimize for multiple objectives. For example, consider a problem where you're solving for $x$ and you want to minimizeobjective_1$=(x+1)^2$ and also minimizeobjective_2$=(x-1)^2$. The minima are $x=-1$ and $x=1$, respectively. However, there is no single best solution $x$ for both objectives. The idea of an optimal solution is replaced by a Pareto efficient set; a set of optimal solutions which are better than all other solutions, but not necessarily better than each other.Consider the following image of the problem:The two minima for the two objectives are marked with X's. Points in the Pareto efficient set are marked with green crosses. Note that the Pareto efficient set is infinite here and the marked points are just a finite sample of it.These Pareto efficient solutions represent the best solutions; notice that any point less than (left of)objective_1's minimum at $x=-1$ is worse than all Pareto efficient solutions for both objectives, and any point greater than (right of)objective_2's minimum at $x=1$ is also worse than all Pareto efficient solutions for both objectives. Points in the Pareto efficient set are not necessarily optimal for either individual objective, but they are a compromise between the two objectives.Here is an example demonstrating how to solve this problem usingOptQuestOptimizer:frommatplotlibimportpyplotaspltfrompyoptquestimportOptQuestOptimizer# define the input(s)search_space={'x':{'type':'continuous','min':-2,'max':2}}# define the objective(s)objectives={'objective_1':{'type':'min','expression':'pow(x + 1, 2)'},'objective_2':{'type':'min','expression':'pow(x - 1, 2)'}}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,license_id=999999999,optquest_jar=r'../OptQuest.jar')# do the optimizationopt.search(n_iter=10)# print resultsprint('Pareto front:')print(opt.best_score)print('Optimization time:',opt.optimization_time)Output:pareto frontier data:
   iteration  replication  objective_1  objective_2         x
0          1            1     1.000000     1.000000  0.000000
1          4            1     0.000160     4.050825 -1.012666
2          5            1     0.231362     2.307359 -0.518999
3          6            1     3.728985     0.004753  0.931058
4          8            1     0.255932     2.232344 -0.494103
5         10            1     2.198158     0.267683  0.482619
Optimization time: 0.05336761474609375An analyst making a decision about a multi-objective problem would probably benefit from seeing the objectives against each other to aid in making a decision. When plotting objectives against eachother, the Pareto efficient set is called thePareto frontier. Let's make this plot:# plot resultsfig,ax=plt.subplots()ax.set_title('objective_1 vs objective_2')ax.set_xlabel('objective_1')ax.set_ylabel('objective_2')opt.search_data.plot(x='objective_1',y='objective_2',style='s',color='pink',ax=ax)# all dataopt.best_score.plot(x='objective_1',y='objective_2',style='+',color='green',ax=ax)# Pareto frontierax.legend(['all data','pareto frontier'])# label points on the Pareto frontforidx,(x_coord,y_coord)inenumerate(zip(opt.best_score['objective_1'],opt.best_score['objective_2'])):x=round(opt.best_score["x"][idx],2)ax.annotate(text=str(f'$x={x}$'),xy=(x_coord+0.2,y_coord))plt.show()Output:This plot show us the tradeoffs between Pareto frontier solutions to our problem (the green crosses.) The solution at $x=0.0$ looks like a good compromise for both objectives. Picking a different solution such as $x=0.48$ minimizesobjective_2but increasesobjective_1even more so, and we're trying to minimize both objectives. However, depending on whatobjective_1andobjective_2represent, we may favor $x=0.48$. This is where the human factor comes in; with multiple objectives we cannot mathematically say that one solution on a Pareto frontier is better than another, the Pareto frontier is a tool representing optimal objective tradeoffs that a human analyst can use to help make a decision.Status MonitorThestatus_monitorcallback function is passed toOptQuestOptimizerand gets called after every time an iteration or replication has been evaluated. It's useful for tracking the status of the optimization while it's running.Here is an example usingstatus_monitorin theMinimal Example:frompyoptquestimportOptQuestOptimizer# optional function for tracking the status of the optimization (called every iteration)defstatus_monitor(inputs,outputs,objectives,iteration,replication):print(f'--status monitor says hello from iteration{iteration}with objective value{objectives["y"]}')# define the input(s)search_space={'x':{'type':'continuous','min':-10,'max':10}}# define the objective(s)objectives={'y':{'type':'min','expression':'x * x'}}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,status_monitor=status_monitor,license_id=999999999,optquest_jar=r'../OptQuest.jar')opt.search(n_iter=10)print()# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:--status monitor says hello from iteration 1 with objective value 0.0
--status monitor says hello from iteration 2 with objective value 100.0
--status monitor says hello from iteration 3 with objective value 100.0
--status monitor says hello from iteration 4 with objective value 25.63732245730393
--status monitor says hello from iteration 5 with objective value 21.671725343768035
--status monitor says hello from iteration 6 with objective value 55.06539502557916
--status monitor says hello from iteration 7 with objective value 6.103445395617211
--status monitor says hello from iteration 8 with objective value 57.78743065485578
--status monitor says hello from iteration 9 with objective value 5.823021408526737
--status monitor says hello from iteration 10 with objective value 36.80563848228416

best score: 0.0
best parameters: {'x': 0.0}
Optimization time: 0.0624849796295166Thestatus_monitorfunction must be able to receive the parametersinputs,outputs,objectives,iteration, andreplication; even if the it isn't using these parameters.Prematurely Stopping an OptimizationOptQuestOptimizeraccepts auser_stopcallback function that returns a boolean which tells it to continue or stop the optimization every iteration/replication. The function takes the same parameters as thestatus_monitorcallback. Below is an example of auser_stopfunction being used to stop the optimization at 5 iterations:frompyoptquestimportOptQuestOptimizer# optional function for tracking the status of the optimization (called every iteration)defstatus_monitor(inputs,outputs,objectives,iteration,replication):print(f'--status monitor says hello from iteration{iteration}with objective value{objectives["y"]}')# return True if the optimization should be stoppeddefuser_stop(inputs,outputs,objectives,iteration,replication):ifiteration>=5:print('-- STOPPING! --')returnTrueelse:returnFalse# define the input(s)search_space={'x':{'type':'continuous','min':-10,'max':10}}# define the objective(s)objectives={'y':{'type':'min','expression':'x * x'}}# define the optimizationopt=OptQuestOptimizer(search_space,objectives,status_monitor=status_monitor,user_stop=user_stop,license_id=999999999,optquest_jar=r'../OptQuest.jar')opt.search(n_iter=10)print()# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:--status monitor says hello from iteration 1 with objective value 0.0
--status monitor says hello from iteration 2 with objective value 100.0
--status monitor says hello from iteration 3 with objective value 100.0
--status monitor says hello from iteration 4 with objective value 25.63732245730393
--status monitor says hello from iteration 5 with objective value 21.671725343768035
-- STOPPING! --

best score: 0.0
best parameters: {'x': 0.0}
Optimization time: 0.03778338432312012Theuser_stopcallback function has access to the current solution being run and can also easily be configured to stop the optimization after a certain amount of time has passed or after some other event occurs.Gradient Free Optimizers SupportOptQuestOptimizeris compatible withGradient Free Optimizers (GFO). For example, the optimizer in theconvex_function.py democan easily be swapped toOptQuestOptimizer.HillClimbingOptimizerexample:importnumpyasnpfromgradient_free_optimizersimportHillClimbingOptimizerdefconvex_function(pos_new):score=-(pos_new["x1"]*pos_new["x1"]+pos_new["x2"]*pos_new["x2"])returnscoresearch_space={"x1":np.arange(-100,101,0.1),"x2":np.arange(-100,101,0.1),}opt=HillClimbingOptimizer(search_space)# using HillClimbingOptimizeropt.search(convex_function,n_iter=300000)Output:Results: 'convex_function'  
   Best score: -6.462348535570529e-23  
   Best parameter:
      'x1' : -5.6843418860808015e-12  
      'x2' : -5.6843418860808015e-12  
 
   Evaluation time   : 9.109798669815063 sec    [33.31 %]
   Optimization time : 18.237623929977417 sec    [66.69 %]
   Iteration time    : 27.34742259979248 sec    [10969.96 iter/sec]OptQuestOptimizerexample:importnumpyasnpfrompyoptquestimportOptQuestOptimizerdefconvex_function(pos_new):score=-(pos_new["x1"]*pos_new["x1"]+pos_new["x2"]*pos_new["x2"])returnscoresearch_space={"x1":np.arange(-100,101,0.1),"x2":np.arange(-100,101,0.1),}opt=OptQuestOptimizer(# using OptQuestOptimizersearch_space,license_id=999999999,optquest_jar=r'optquest.jar')opt.search(convex_function,n_iter=300000)# print resultsprint('best score:',opt.best_score)print('best parameters:',opt.best_para)print('Optimization time:',opt.optimization_time)Output:best score: -6.462348535570529e-23
best parameters: {'x1': -5.6843418860808015e-12, 'x2': -5.6843418860808015e-12}
Optimization time: 0.3541069030761719In the above example note that, like GFO,OptQuestOptimizerdoesn't need to be defined withobjectivesifOptQuestOptimizer.search()is passed an objective evaluator e.g.convex_function. If an objective is passed like this,OptQuestOptimizerwill maximize the objective.OptQuestOptimizerConstructor ParametersBelow is a description of each parameter that can be passed to theOptQuestOptimizerconstructor.search_space: Required parameter. The inputs/decision variables for the optimization. This should be adictof variable names mapped to dictionaries of their corresponding properties.objectives: Not required for the constructor. If no objective is supplied here than an objective evaluator must be passed toOptQuestOptimizer.search()later on. This should be adictof objective names mapped to dictoinaries of their corresponding properties.evaluator: Not required. A callback function which should take aninputparameter; adictof variable names and values. The function should then run the user logic e.g. perform a simulation, and then return anoutputdictof output names mapped to their values. The names (keys) in theoutputreturndictmust be those specified byoutput_space, described next.output_space: Sometimes required. Only used if the constructor'sevaluatorparameter is passed an evaluator callback function since it will generate outputs. This should be alistcontaining the names of all outputs that will be collected from the evaluator callback function.constraints: Not required. Provides a way to put constraints on the inputs and outputs of the problem. This should be adictmapping constraint names to dictionaries of their corresponding properties. See theconstraints examplefor more details.status_monitoranduser_stop: callback functions that must take the parametersinputs,outputs,objectives,iteration, andreplication. See the corresonding sections for more details on these callback functions:Status MonitorandPrematurely Stopping an Optimization.license_id: The ID number for your OptQuest license. The trial license is used in the provided examples. An optimization running with the trial license is limited to 7 variables and 500 iterations. The trial license ID number is999999999.OptQuestJar: A path to anOptQuest.jarfile of version 9.1.1.2 or higher.OptQuestOptimizer.search()ParametersBelow is a list of parameters that can be passed to theOptQuestOptimizer.search()function.objective_evaluator: If noobjectivesparameter is passed to theOptQuestOptimizerconstructor then this parameter must be passed to theOptQuestOptimizer.search()function as a callback function. The callback function must take aninputsparameter which expects adictmapping input variable names to their values and it can optionally take a second parameteroutputswhich maps output names to their values.n_iter: The number of iterations of unique input combinations to try.replications: The number of times to replicate an iteration of unique inputs. Replications are only useful when the user'sevaluatoris stochastic/non-deterministic and inputs need to be evaluated multiple times. The value for this parameter can be anintwhich specifies the number of replications that should be done for each iteration or the value can be atuplewhich specifies the minimum and maximum number of replications that will be done for each iteration e.g.(5, 20). SeeReplications Examplefor more details.parallel_evaluators: The maximum allowed number of concurrent calls to theevaluatorcallback function (which was passed to theOptQuestOptimizerconstructor.)  Theevaluatorfunction must be reentrant and if it uses shared state, it is responsible for managing the synchronization (e.g.,mutexes) as needed.suggested_runs: A dict containing solutions to evaluate as the first iterations. Seeoqo_example_suggested_runs.pyfor a demonstration.Supported Variable TypesContinuousA continuous variables is simply a real value, e.g.3.14159.Propertiesmin: the lower bound (inclusive) on the values the variable can take on.max: the upper bound (inclusive) on the values the variable can take on.DiscreteDiscrete variables are continuous variables that are constrained to values at step intervals, e.g.1.5, 3, 4.5, 6for a step size of1.5.Propertiesmin: Lower bound (inclusive) on the values the variable can take on. The variable can necessarily take on this value as well.max: Upper bound on the values the variable can take on. The variable can take on this value only ifmax-minis an integer multiple ofstep.step: The step size; the range of values the variable can take ismin,min+ 1*step,min+ 2*step,min+ 3*step, etc.IntegerAn integer variable can only take real integer values.Propertiesmin: the lower bound (inclusive) on the values the variable can take on.max: the upper bound (inclusive) on the values the variable can take on.BinaryCan only take on values 0 and 1.EnumerationAn enumeration variable is limited to taking on values from an enumerated list of values e.g.{7, 10, 25}.Propertiesvalues: the enumerated list of values the variable can take on. The format can be an iterable with numeric members, a comma delimited string of values, or a space delimited string of values.PermutationWhen you define a permutation type insearch_spacea permutation group is created. A permutation group contains multiple permutation variables. Each variable will be an integer value representing that variable's index within the group (starting at index 1.)Propertieselements: The argument for this property can either be an integer or a list of strings. An integer will specify the number of elements (permutation variables) the permutation group should have. If a list of strings is passed, then each string in the list becomes the name of a permutation variable in the group.Demonstration of Variable TypesHere's a cheat sheet demonstrating how each variable type can be defined:search_space={'continuous_var':{'type':'continuous','min':-5,'max':5},'discrete_var':{'type':'discrete','min':-1.5,'max':4.5,'step':1.5},'integer_var':{'type':'integer','min':-3,'max':3},'binary_var':{'type':'binary'},'enumeration_var1':{'type':'enumeration','values':[1,2,3]},'enumeration_var2':{'type':'enumeration','values':np.array([1,2,3])},'enumeration_var3':{'type':'enumeration','values':'1, 2, 3'},'permutation_grp_A':{'type':'permutation','elements':['one','two','three']},'permutation_grp_B':{'type':'permutation','elements':3}}Expression SyntaxExpressions can be used when defining objectives or constraints.When defining a constraint, the expression must contain a comparison operator. The supported comparison operators are=,<=, and>=.The following functions can be used when creating string expressions:FunctionSyntaxDescriptionminmin(x,y)Returns the smaller of two numbers.maxmax(x,y)Returns the larger of two numbers.sqrtsqrt(x)Returns the square root of a number.loglog(x)Returns the natural logarithm of a specified number.log10log10(x)Returns the base 10 logarithm of a specified number.powpow(x,yReturns a specified number raised to the specified power.expexp(x)Returns e raised to the specified powerabsabs(x)Returns the absolute value of a specified number.randrand()Returns a random number between 0 and 1, inclusive.fmodfmod(x,y)Returns the remainder of x / y.floorfloor(x)Returns the largest whole number less than or equal to the specified number.ceilceil(x)Returns the smallest whole number greater than or equal to the specified number.sinsin(x)Returns the sine of x, where x is an angle in radians.coscos(x)Returns the cosine of x, where x is an angle in radians.tantan(x)Returns the tangent of x, where x is an angle in radians.sinhsinh(x)Returns the hyperbolic sine of x, where x is an angle in radians.coshcosh(x)Returns the hyperbolic cosine of x, where x is an angle in radians.tanhtanh(x)Returns the hyperbolic tangent of x, an angle in radians.asinasin(x)Returns the arcsine of x in the range –π/2 to π/2.acosacos(x)Returns the arccosine of x in the range 0 to π.atanatan(x)Returns the arctangent of x in the range of –π/2 to π/2 radians.atan2atan2(x,y)Returns the arctangent of y/x in the range –π to π radians. If both parameters of atan2 are 0, the function returns 0.DtoRDtoR(x)Converts degrees to radians.RtoDRtoD(x)Converts radians to degrees.Additionally, the mathematical constantspiandeare valid expression syntax.ExamplesThe following examples are provided in the examples directory and most are used in this documentation.Example NameDescriptionoqo_example_parabola.pyThe simplest possible example of an optimization withOptQuestOptimizer.oqo_example_simulation.pySame asparabola_example.pybut demonstrates how an external simulation can be used.oqo_example_objective_evaluator.pyDemonstrates how to use an objective evaluator callback function.oqo_example_constraint.pyDemonstrates how to define a mathematical constraint.oqo_example_constraint_evaluator.pyDemonstrates how to define a constraint as a boolean callback function.oqo_example_parallel_evaluations.pyDemonstrates how to enable parallel evaluators.oqo_example_permutation.pyAn example permutation problem optimizing the order of transitions of production machines.oqo_example_replications.pyA simple demonstration using a fixed number of replications.oqo_example_replications_with_confidence.pyAn advanced demonstration using a variable number of replications and a custom objective confidence configuration.oqo_example_frontier.pyA demonstration of a problem with multiple objectives.oqo_example_status_monitor.pyDemonstration ofstatus_monitorcallback function usage for tracking the progress of an optimization.oqo_example_user_stop.pyDemonstration ofuser_stopcallback function usage for prematurely stopping an optimization that's in progress.oqo_example_suggested_runs.pyDemonstration of thesuggested_runsparameter in theOptQuestOptimizer.search()function.oqo_example_all_variables.pyShows how to define and use all the variable types supported by the OptQuestOptimizeroqo_example_gfo_convex.pyoqo_example_gfo_non_convex.pyExamples of passing an objective evaluator toOptQuestOptimizer.search()in GFO style.oqo_example_cell_tower_location.pyA simple example with a rectangular solution space.oqo_example_cell_tower_polygon_location.pyAn advanced example with a non-trivial polygon solution space. Requires theshapelypackage.oqo_example_radio_antenna.pyAn advanced example with a non-trivial polygon solution space, multiple constraints, and usage of manyOptQuestOptimizerfeatures. Requires theshapelypackage. This example does not work with the demo license supplied in the example.  You need to use your license.