%% Solve Optimization Problem in Parallel on Process-Based and Thread-Based Pool
% This example shows how to use a process-based and thread-based pool to solve an optimization problem in parallel. Thread-based pools are optimized for less data transfer, faster scheduling, and reduced memory usage, so they can result in a performance gain in your applications.
%% Problem Description
% The problem is to change the position and angle of a cannon to fire a projectile as far as possible beyond a wall. The cannon has a muzzle velocity of 300 m/s. The wall is 20 m high. If the cannon is too close to the wall, it fires at too steep an angle, and the projectile does not travel far enough. If the cannon is too far from the wall, the projectile does not travel far enough. For full problem details, see Optimize an ODE in Parallel or the latter part of the video Surrogate Optimization.
%% MATLAB Problem Formulation
% To solve the problem, call the patternsearch solver from Global Optimization Toolbox. The objective function is in the cannonobjective helper function, which calculates the distance the projectile lands beyond the wall for a given position and angle. The constraint is in the cannonconstraint helper function, which calculates whether the projectile hits the wall, or even reaches the wall before hitting the ground. The helper functions are in separate files that you can view when you run this example.
% Set the following inputs for the patternsearch solver. Note that, to use Parallel Computing Toolbox, you must set 'UseParallel' to true in the optimization options.

lb = [-200;0.05];
ub = [-1;pi/2-.05];
x0 = [-30,pi/3];
opts = optimoptions('patternsearch',...
    'UseCompletePoll', true, ...
    'Display','off',...
    'UseParallel',true);
% No linear constraints, so set these inputs to empty:
A = [];
b = [];
Aeq = [];
beq = [];

%
%% Solve on Process-Based Pool
% For comparison, solve the problem on a process-based parallel pool first.
% Start a parallel pool of process workers.

p = parpool('local');

% To reproduce the same computations later, seed the random generator with the default value.

rng default;

% Use a loop to solve the problem several times and average the results.

tProcesses = zeros(5,1);
for repetition = 1:numel(tProcesses)
    tic
    [xsolution,distance,eflag,outpt] = patternsearch(@cannonobjective,x0, ...
        A,b,Aeq,beq,lb,ub,@cannonconstraint,opts);
    tProcesses(repetition) = toc;
end
tProcesses = mean(tProcesses)

% To prepare for the comparison with a thread-based pool, delete the current parallel pool.

delete(p);

%
%% Solve on Thread-Based Pool
% Start a parallel pool of thread workers.

p = parpool('threads');

% Restore the random number generator to default settings and run the same code as before.

rng default
tThreads = zeros(5,1);
for repetition = 1:numel(tThreads)
    tic
    [xsolution,distance,eflag,outpt] = patternsearch(@cannonobjective,x0, ...
        A,b,Aeq,beq,lb,ub,@cannonconstraint,opts);
    tThreads(repetition) = toc;
end
tThreads = mean(tThreads)

% Compare the performance of thread workers and process workers.

fprintf('In this example, thread workers are %.2fx faster than process workers.\n', tProcesses/tThreads)

% Notice the performance gain due to the optimizations of the thread-based pool.
% When you are done with computations, delete the parallel pool.

delete(p);

% Copyright 2019 The MathWorks, Inc.