diff --git a/.gitignore b/.gitignore index a3e6daf37..9e66b6bb2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,11 @@ # Build dirs. -build* +*build* # Temp files. *~ *.bak .DS_Store +\.idea/ # .orig files from patch. *.orig @@ -24,4 +25,4 @@ doc/doxygen/xml/* doc/doxygen/Doxyfile doc/sphinx/conf.py -doc/sphinx/_build +doc/sphinx/_build \ No newline at end of file diff --git a/doc/sphinx/docs/cpp/cpp_docs.rst b/doc/sphinx/docs/cpp/cpp_docs.rst index e44a777af..e27af301d 100644 --- a/doc/sphinx/docs/cpp/cpp_docs.rst +++ b/doc/sphinx/docs/cpp/cpp_docs.rst @@ -1,3 +1,5 @@ +.. _cpp_api_documentation: + C++ API documentation ===================== diff --git a/doc/sphinx/docs/cpp/problems/hock_schittkowsky_71.rst b/doc/sphinx/docs/cpp/problems/hock_schittkowsky_71.rst index 3ba0c2dd7..cc49aa73e 100644 --- a/doc/sphinx/docs/cpp/problems/hock_schittkowsky_71.rst +++ b/doc/sphinx/docs/cpp/problems/hock_schittkowsky_71.rst @@ -1,3 +1,4 @@ +.. _hock_schittkowsky: Hock Schittkowsky No.71 ======================= diff --git a/doc/sphinx/docs/cpp/tutorials/cpp_tut.rst b/doc/sphinx/docs/cpp/tutorials/cpp_tut.rst index 03b18f3cb..76aa860d6 100644 --- a/doc/sphinx/docs/cpp/tutorials/cpp_tut.rst +++ b/doc/sphinx/docs/cpp/tutorials/cpp_tut.rst @@ -1,5 +1,37 @@ .. _tutorial: +Introduction +============ +pagmo is a C++ scientific library to *perform parallel optimizations*. +pagmo is **not** a framework for forecasting, clustering, predictions etc. + +Applicable optimization problems arise in most quantitative disciplines, such as: + +- computer science (e.g. mapping and scheduling for hard-real-time systems, scheduling in networking) +- engineering (e.g. ) +- finance (e.g. asset pricing, portfolio optimization) +- economics (e.g. utility maximization problem, expenditure minimization problem) +- operations research (e.g. Cutting stock problem, floorplanning, traveling salesman problem, staffing, job shop problem) +- physics (e.g. ) + + +Some problems are applicable to several of these domains, for example the more general bin packing problem is +applicable to computer science (scheduling in real-time systems and networks) and operations research +(staffing, job shop problems). +The general aim in all these fields is to minimize or maximize a given function, i.e. we need to find the inputs to a +function that result in the best output of the function. + +Ideally one always wants to find the optimal solution for a given problem. However, this is often not feasible as +the time required to solve optimization problems can grow exponentially with the size of the problem. +In order to tackle these challenges we use heuristics and metaheuristics that find approximate solutions. +Additionally, by using parallelism we can solve problems even faster or find better solutions. + +This is where pagmo comes in. It provides you with among others a collection of solvers and a framework to +solve optimization problems in parallel. This way you can for example test a set of solvers on your specific problem. +An overview of solvers and other capabilities can be found :ref:`here `. + +In this tutorial we explain the basics of pagmo and detail more advanced usecases. + C++ tutorial ============ @@ -7,12 +39,32 @@ C++ tutorial :maxdepth: 1 cpp_tut_preliminaries + + +First Problem +^^^^^^^^^^^^^ + +.. toctree:: + :maxdepth: 1 + cpp_tut_first_problem + cpp_tut_first_problem_solving + cpp_tut_first_problem_parallel + cpp_tut_next_steps + -Basics -^^^^^^ +Additional Problems +^^^^^^^^^^^^^^^^^^^ .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + + cpp_tut_bin_packing + +Advanced Topics +^^^^^^^^^^^^^^^ + +.. toctree:: + :maxdepth: 1 - evolving_a_population + cpp_tut_implement_optimizer \ No newline at end of file diff --git a/doc/sphinx/docs/cpp/tutorials/cpp_tut_bin_packing.rst b/doc/sphinx/docs/cpp/tutorials/cpp_tut_bin_packing.rst new file mode 100644 index 000000000..18c69bbd0 --- /dev/null +++ b/doc/sphinx/docs/cpp/tutorials/cpp_tut_bin_packing.rst @@ -0,0 +1,137 @@ +.. _cpp_tut_bin_packing: + +Bin Packing +=========== + +In the original bin packing problem (*bpp*) one has to *pack* items of different volume/size into a finite number of containers or bins. +The aim is to minimze the number of containers that have to be used. This is a NP-hard problem. + +Since then bin packing has been extended in many different ways: 2D bin packing, 3D bin packing, packing by weight or cost etc. +Problems similar to bin packing or application of bpp can be found in many different domains (computer science, logistic, job shop scheduling etc.). +Thus, it is still a very relevant problem with several new solvers being applied/tested/introduced every year +(Feng et al. "*An Enhanced Grasshopper Optimization Algorithm to the Bin Packing Problem*"; +Abdel-Basset et al. "*An improved nature inspired meta-heuristic algorithm for 1-D bin packing problem*"). + +Here we consider a 1D version of bin packing, where we have a set of objects that need to be packed into a set of bins. +All bins have the same size and the aim is to minimize the number of bins used. The different items can be of different size. +An example of items are shown in the figure below. The total size of all items is 18.5. + +.. image:: ../../images/bin_packing/bin_packing_items.png + +These items have to fit into into six containers. Each container is of size 7, i.e. there is enough space for all items. +A solution minimizing the number of used bins could look like this: + +.. image:: ../../images/bin_packing/bin_packing_solution.png + +Other solutions using the same number of bins is also possible. +For a small example the solution is trivial and can easily be made by hand. +Lets see how we can solve this problem using pagmo, so that we can also solve non-trivial versions of this problem. + +Problem Definition +------------------ + +For the bin packing problem we need to know 4 things. + +- How many bins are there? +- How large are the bins? +- How many items are there? +- How large are the items? + +The bounds and constraints are fairly straightforwards. All items have to be packed into one of the bins, i.e. between 0 and *max_bin_num - 1*. +The sum of the items in a bin cannot be larger than the size of the bins. + +Just like in the :ref:`First Problem` we have to implement 4 functions: + +- ``fitness()`` +- ``get_bounds()`` +- ``get_nic()`` +- ``get_nix()`` + +Lets start with the fitness function. As an input it receives a vector of possible item mappings, i.e. a possible solution. +For this solution it then computes the fitness, which in this case is the number of bins used. +The computed fitness value is then stored in a return vector. + +After the fitness value we need to compute if the constraints are met, i.e. is there enough space left in the bins. +For this we loop over all bins and all items and compute the usage of each bin. For each bin we add an entry to the +return vector which represents the inequality. Each inequality number has to be smaller or equal to 0. + +.. code-block:: c++ + + // Implementation of the objective function and all constraints + pagmo::vector_double fitness(const pagmo::vector_double &x_i) const { + // variables + double num_bins_used = 0; //how many bins are used + std::vector bin_used(num_bins, 0); + + // where x_i is the bin in which an item i is placed + // determine if a bin is used based on x_i + for (int i = 0; i < num_items; ++i) { + for (int j = 0; j < num_bins; ++j) { + if (x_i[i] == j){ + bin_used[j] = 1; + } + } + } + + // Objective function calculation; i.e. how many bins are used? We want to minimize this! + for(auto& y: bin_used){ + num_bins_used += y; + } + + // Make return vector and adding objective + pagmo::vector_double return_vector{num_bins_used}; + + // Adding inequalities to stick to the maximum size of the bin + for (int j = 0; j < num_bins; ++j) { + int temp_bin_occupation = 0; + for (int i = 0; i < num_items; ++i) { + if (x_i[i] == j){ + temp_bin_occupation += items[i] ; // <= 0 + } + } + return_vector.emplace_back(temp_bin_occupation - size_bins); + } + return return_vector; + } + +Besides the fitness and the constraints we need to make sure that the bounds are also correct. We do not want that the +genetic algorithm starts packing items into a non existent bins. Therefore, the ``get_bounds()`` function returns the +lower and upper bound for each item. In our case the lower bound is 0 (i.e. Bin 1) and the upper bound is number of bins - 1. + +.. code-block:: c++ + + // The lower and upper bounds are the bins in which an item can be placed. + std::pair get_bounds() const { + std::vector lower(num_items, 0); + std::vector upper(num_items, num_bins-1); + return {lower, upper}; + } + +The ``get_nix()`` function returns the integer dimension of the problem, i.e. the size of the solution. In this case its given by the number of items. + +.. code-block:: c++ + + // Integer dimension of the problem - i.e. into which bin each item is packed + pagmo::vector_double::size_type get_nix() const { + return pagmo::vector_double::size_type(num_items); + } + +Lastly, we need the number of inequalities, which is equal to the number of bins, as we need one inequality per bin. + +.. code-block:: c++ + + // Number of inequality constraints. + pagmo::vector_double::size_type get_nic() const { + return pagmo::vector_double::size_type(num_bins); + } + +We can again solve this problem with :ref:gaco or :ref:ihs. +Combining the problem definition plus soliving it with gaco or ihs results in the following code. + +.. literalinclude:: ../../../../../tutorials/problem_bin_packing.cpp + :caption: problem_bin_packing.cpp + :language: c++ + :linenos: + +Solving the problem with either ihs or gaco will result in a solution that occupies 3 bins, i.e. finding an optimal solution. + diff --git a/doc/sphinx/docs/cpp/tutorials/cpp_tut_first_problem.rst b/doc/sphinx/docs/cpp/tutorials/cpp_tut_first_problem.rst index 4f420364d..811b80ea0 100644 --- a/doc/sphinx/docs/cpp/tutorials/cpp_tut_first_problem.rst +++ b/doc/sphinx/docs/cpp/tutorials/cpp_tut_first_problem.rst @@ -1,16 +1,18 @@ -Writing your first optimisation problem +.. _cpp_tut_first_problem: + +Writing your first optimization problem ======================================= -A fundamental requirement of any optimisation -library is the ability to represent an optimisation +A fundamental requirement of any optimization +library is the ability to represent an optimization problem to be solved. In this section, our goal is to show how this is done in pagmo. A simple problem ---------------- -We will be considering the minimisation of -the multidimensional objective function +We will be considering the minimization of +the multidimensional objective function (:ref:`Hock Schittkowsky No.71 `) .. math:: @@ -31,7 +33,7 @@ and to the constraints 25 - x_1 x_2 x_3 x_4 &\le 0. \end{align} -In pagmo's taxonomy, this optimisation problem is +In pagmo's taxonomy, this optimization problem is * *continuous* (because :math:`x_{1,2,3,4}` are real variables), * *deterministic* (as neither the objectives nor the constraints depend @@ -56,7 +58,7 @@ the constraints at a later stage. The bare necessities -------------------- -In pagmo, an optimisation problem must provide +In pagmo, an optimization problem must provide at the very least an objective function and the box bounds. Let's see how this is done for our simple example problem: @@ -75,7 +77,7 @@ After the inclusion of the necessary header files, and a helpful using namespace pagmo; to reduce typing, we reach the definition -of our optimisation +of our optimization problem via a class called ``problem_v0``. As explained in the :ref:`section about type erasure `, this class does not need to derive from any base class. @@ -98,7 +100,7 @@ it is used to return not only the value of the objective function, but also of the constraints (thus in some sense it computes the overall "fitness" of the input decision vector). In this specific case, however, -our optimisation problem does not have constraints yet, +our optimization problem does not have constraints yet, and thus the ``fitness()`` implementation just returns a vector of size 1 whose only element is the value of the (single) objective function: @@ -130,7 +132,7 @@ via the sizes of the returned lower/upper bounds vectors Meet pagmo::problem ------------------- -After the definition of our optimisation problem, ``problem_v0``, +After the definition of our optimization problem, ``problem_v0``, we encounter the ``main()`` function. In the ``main()``, the first thing we do is to construct a :cpp:class:`pagmo::problem` from an instance of ``problem_v0``: @@ -140,12 +142,12 @@ instance of ``problem_v0``: problem p{problem_v0{}}; :cpp:class:`pagmo::problem` is pagmo's -:ref:`type-erased ` interface to optimisation +:ref:`type-erased ` interface to optimization problems. It is a generic container which can store internally -an instance of any class which "acts like" an optimisation problem, +an instance of any class which "acts like" an optimization problem, that is, any class which provides (at least) the two member functions described earlier (``fitness()`` and ``get_bounds()``). In the pagmo -jargon, we refer to classes which "act like" optimisation problems +jargon, we refer to classes which "act like" optimization problems as *user-defined problems*, or UDPs. In addition to storing a UDP (which, by itself, would not be @@ -201,11 +203,11 @@ summary that may look like this: Quite a mouthful! Do not worry about deciphering this output right now, as we will examine the more intricate -aspects of the definition of an optimisation problem in due time. +aspects of the definition of an optimization problem in due time. For now, let us just point out that, from our simple UDP definition, pagmo was able to infer -on its own various properties of the optimisation problem +on its own various properties of the optimization problem (e.g., the problem dimension, the number of objectives, the absence of constraints, etc.). pagmo is able to do this thanks to both introspection capabilities (based on template @@ -229,7 +231,7 @@ Let us see the code: :diff: ../../../../../tutorials/first_udp_ver0.cpp In order to specify the type and number of constraints in our -optimisation problem, we have to implement the two member +optimization problem, we have to implement the two member functions ``get_nec()``, which returns the number of equality constraints, and ``get_nic()``, which returns the number of inequality constraints: diff --git a/doc/sphinx/docs/cpp/tutorials/cpp_tut_first_problem_parallel.rst b/doc/sphinx/docs/cpp/tutorials/cpp_tut_first_problem_parallel.rst new file mode 100644 index 000000000..67d852ed6 --- /dev/null +++ b/doc/sphinx/docs/cpp/tutorials/cpp_tut_first_problem_parallel.rst @@ -0,0 +1,104 @@ +.. _cpp_tut_first_problem_parallel: + +Parallelizing your first UDP +============================ + +In the :ref:`definition section ` +we showed how a User Defined Problem is constructed. +In the :ref:`previous section ` +we showed how to solve this problem with two different optimizers. + +If you executed the example from the previous section, you probably noticed that this setup executes almost immediately +as the population and the number of generations is small. +However, finding good solutions to optimization problems can take a much larger population and higher number of generations +and hence significant amount of time. +Thus, parallelization of the optimization can be extremely important. + +In pagmo parallelization is achieved via :cpp:class:`pagmo::island` and :cpp:class:`pagmo::archipelago`. +**Islands** are used to asynchronously evolve populations. So one can launch multiple islands to evolve populations in parallel. +An **archipelago** is a collection of islands which we can use to evolve a population in parallel. + + +Archipelagos for Parallelization +-------------------------------- + +The difference between the sequential and parallel solutions are as follows. + + +.. literalinclude:: ../../../../../tutorials/first_udp_ver1_solve_parallel.cpp + :language: c++ + :diff: ../../../../../tutorials/first_udp_ver1_solve.cpp + +Thus, as in the previous sections we create the problem and create the algorithm to solve the problem. +However, instead of constructing a single population we construct a :cpp:class:`pagmo::archipelago`. +An archipelago is a collection of :cpp:class:`pagmo::island` objects, in this case the archipelago consists of *16 islands*. +Additional parameters required for constructing the islands is the problem (*prob*) and algorithm (*algo*) +along with the population size of each island (*1000*). + +.. code-block:: c++ + + archipelago archi{16, algo, p, 1000};; + +Next we call ``archi.evolve(1)``, this function call evolves the population of each island **once** for 1000 generations +(defined when setting up the algorithm). + +.. code-block:: c++ + + archi.evolve(1); + +As islands evolve asychronously we need to wait until all islands evolved. This can be done via ``archi.wait_check()``. + +.. code-block:: c++ + + archi.wait_check(); + + +After that we can print the performance of the champion solutions of each island. +This will print a total of 16 champion solutions as there are 16 islands. + +.. code-block:: c++ + + for (const auto &isl : archi) { + std::cout << isl.get_population().champion_f()[0] << '\n'; + } + +Topology +-------- + +When creating an archipelago the default is that the islands in the archipelago are not connect, +i.e. the population on each island evolves independently. +Creating dependencies between the islands is possible by changing the :cpp:class:`pagmo::topology` of the archipelago. +This allows individuals of the different populations to migrate to other islands and thus for the best individuals +across all populations to propagate their features throughout the global population. + +We can create a fully connected archipelago (every island is connected to all other islands) by introducing +the following changes: + +.. literalinclude:: ../../../../../tutorials/first_udp_ver1_solve_parallel_topology.cpp + :language: c++ + :diff: ../../../../../tutorials/first_udp_ver1_solve_parallel.cpp + +We construct a :cpp:class:`pagmo::fully_connected` topology. + +.. code-block:: c++ + + fully_connected topo{};; + +And when constructing the archipelago we simply pass the topology as the first parameter. + +.. code-block:: c++ + + archipelago archi{topo, 16, algo, prob, 1000}; + + +In the simple unconnected example we evolved the populations of each island once for 1000 generations. +However, the migration of individuals between islands only happens after each evolution, i.e. if we only evolve the populations once there is no migration. +Hence, in this case we evolve the populations 10 times for 100 generations each (i.e. migration happens 10 times). + +.. code-block:: c++ + + archi.evolve(10); + + + + diff --git a/doc/sphinx/docs/cpp/tutorials/cpp_tut_first_problem_solving.rst b/doc/sphinx/docs/cpp/tutorials/cpp_tut_first_problem_solving.rst new file mode 100644 index 000000000..7e39f433d --- /dev/null +++ b/doc/sphinx/docs/cpp/tutorials/cpp_tut_first_problem_solving.rst @@ -0,0 +1,99 @@ +.. _cpp_tut_first_problem_solve: + +Solving your first UDP +====================== + +Solving an optimization problem using an optimization algorithm is, in pagmo, +described as *evolving* a population. In the scientific literature, an +interesting +discussion has developed over the past decades on whether evolution is or not +a form of +optimization. In pagmo we take the opposite standpoint and we regard +optimization, +of all types, as a form of evolution. Regardless on whether you will +be using an SQP, +an interior point optimizer or an evolutionary strategy solver, in pagmo you +will always have to call a method called ``evolve()`` to improve over your +initial solutions, +i.e., your *population*. + +In this section we continue with the simple UDP +from the :ref:`previous section ` +and look at ways to minimize it. The following example shows the use with of an evolutionary algorithm. + +As previously defined the problem is +*continuous*, *deterministic*, *single objective* and *constrained*. +Looking at the :ref:`algorithms table ` +we can find multiple applicable optimization algorithms. + +From the :ref:`global optimization heuristics <_heuristic_global_optimization>` we could use +Extended Ant Colony Optimization (:cpp:class:`pagmo::gaco`) or +Improved Harmony Search (:cpp:class:`pagmo::ihs`). + +Ant Colony Optimization +----------------------- + +Lets see how we can optimize the problem from the :ref:`previous section `. +We import the necessary packages and define the problem (``problem_v1``), as in the previous section. + +.. literalinclude:: ../../../../../tutorials/first_udp_ver1_solve.cpp + :caption: first_udp_ver1_solve.cpp + :language: c++ + :linenos: + +In the ``main`` function we then specify the pagmo problem as was done before. + +.. code-block:: c++ + + problem prob{problem_v1{}}; + +The code after this is the part that we are interested in. +First we define the algorithm that we want to use for the optimization (:cpp:class:`pagmo::gaco`), +where *1000* is the number of generations. + +.. code-block:: c++ + + algorithm algo{gaco(1000)}; + +The next step is to initialie the population (i.e. a number of random solutions) for the problem. +This is done by passing the problem *prob* to the ``pop`` function together with the *population size*. + +.. code-block:: c++ + + population pop{prob, 100}; + +Third to actually evolve (i.e. optimize) the population +we pass the generated population (pop) to the ``algo.evolve`` function. + +.. note:: + + The population size for the Ant Colony Optimization has to be at + least as big as the number of solutions stored. + The number of solution is defined by the *ker* parameter of the + ``gaco`` function call and defaults to *63*. + + +.. code-block:: c++ + + pop = algo.evolve(pop); + +Lastly, we print the individuals from the last generation. + +.. code-block:: c++ + + std::cout << pop; + +This will also print the optimal solution (*Champion decision vector*) +as well as the results of the objective function and constraints (*Champion fitness*). + + +Improved Harmony Search +----------------------- + +Switching to an alternative optimiser is straightforward. +If we want to use the Improved Harmony Search instead of GACO, +we include the header and change the algorithm definition: + +.. code-block:: c++ + + algorithm algo{ish(1000)}; diff --git a/doc/sphinx/docs/cpp/tutorials/cpp_tut_implement_optimizer.rst b/doc/sphinx/docs/cpp/tutorials/cpp_tut_implement_optimizer.rst new file mode 100644 index 000000000..454edfad4 --- /dev/null +++ b/doc/sphinx/docs/cpp/tutorials/cpp_tut_implement_optimizer.rst @@ -0,0 +1,10 @@ +.. _cpp_tut_implement_optimizer: + +User defined optimizer +====================== + +In this example we demonstrate how to implement a new optimizer. +We implement the "*An Enhanced Grasshopper Optimization Algorithm to the Bin Packing Problem*" by Feng et al. +and will compare its performance against the pre-implemented gaco and ihs optimizers. + +For this purpose we will work with the *Bin packing problem* implemented :ref:`here`. \ No newline at end of file diff --git a/doc/sphinx/docs/cpp/tutorials/cpp_tut_next_steps.rst b/doc/sphinx/docs/cpp/tutorials/cpp_tut_next_steps.rst new file mode 100644 index 000000000..0527ebee8 --- /dev/null +++ b/doc/sphinx/docs/cpp/tutorials/cpp_tut_next_steps.rst @@ -0,0 +1,19 @@ +.. _cpp_tut_next_steps: + +Next Steps +========== + +Depending on what you want to achieve with pagmo there are different sections where you want to continue. +An overview of the documentation can be found :ref:`here `. +A good starting point is to read about the core classes this will help you to gain an overview of the library and its +possibilities (e.g. :cpp:class:`pagmo::problem`, :cpp:class:`pagmo::population`, +:cpp:class:`pagmo::island`, :cpp:class:`pagmo::archipelago`, :cpp:class:`pagmo::topology` etc.). + +If you are interested in applying pagmo to your own problem you can look at the additional user defined problems in +the tutorial section. +Additionally, you can look at the problems implemented within pagmo (in the *implemented problems* section of the +:ref:`documentation `. + +If you want to go deeper into pagmo and implement your optimizers, islands etc. you should look at the +:ref:`documentation ` or the advanced topics section of tutorials. + diff --git a/doc/sphinx/docs/images/bin_packing/.gitignore b/doc/sphinx/docs/images/bin_packing/.gitignore new file mode 100644 index 000000000..f632ac8c7 --- /dev/null +++ b/doc/sphinx/docs/images/bin_packing/.gitignore @@ -0,0 +1,5 @@ +*.aux +*.auxlock +*.log +*.gz +*.pdf \ No newline at end of file diff --git a/doc/sphinx/docs/images/bin_packing/bin_packing_items.png b/doc/sphinx/docs/images/bin_packing/bin_packing_items.png new file mode 100644 index 000000000..c16f0e569 Binary files /dev/null and b/doc/sphinx/docs/images/bin_packing/bin_packing_items.png differ diff --git a/doc/sphinx/docs/images/bin_packing/bin_packing_items.tex b/doc/sphinx/docs/images/bin_packing/bin_packing_items.tex new file mode 100644 index 000000000..54c7387bf --- /dev/null +++ b/doc/sphinx/docs/images/bin_packing/bin_packing_items.tex @@ -0,0 +1,56 @@ +\documentclass{standalone} +\usepackage[x11names]{xcolor} +\usepackage{tikz} +\usetikzlibrary{shapes,arrows,decorations.markings, arrows.meta} +\usetikzlibrary {positioning} +\usetikzlibrary{calc} +\usetikzlibrary{patterns} +\usepackage{enumitem} +\usepackage{helvet} +\usepackage[T1]{fontenc} + +%---------------------------------- Colors +\definecolor{color0}{RGB}{228,26,28} +\definecolor{color1}{RGB}{55,126,184} +\definecolor{color2}{RGB}{77,175,74} +\definecolor{color3}{RGB}{152,78,163} +\definecolor{color4}{RGB}{255,127,0} +\definecolor{color5}{RGB}{255,255,51} +\definecolor{color6}{RGB}{166,86,40} +\definecolor{color7}{RGB}{247,129,191} +\definecolor{color8}{RGB}{153,153,153} +\definecolor{color9}{RGB}{0,0,0} + +\tikzstyle{simpleNode} = [rectangle, draw, fill=color0, text width=2cm, text centered, minimum height=2cm] + +%---------------------------------------------------------------------------------- +\def \nodeDistance {2.8cm} + + +\begin{document} + \nopagecolor + + \begin{tikzpicture}[node distance = 2cm, auto,font=\sffamily\large] + + \node[simpleNode, minimum height=3cm, fill=color1](Item-A){Item: A\\Size: 3}; + + \node[simpleNode, minimum height=2cm, fill=color2]at([yshift=-1.5cm]Item-A.south)(Item-B){Item: B\\Size: 2}; + + \node[simpleNode, minimum height=5cm, fill=color3]at([xshift=1.5cm, yshift=0.5cm]Item-A.south east)(Item-C){Item: C\\Size: 5}; + + \node[simpleNode, minimum height=1cm, fill=color4]at([xshift=1.5cm, yshift=-0.5cm]Item-C.north east)(Item-D){Item: D\\Size: 1}; + + + \node[simpleNode, minimum height=4cm, fill=color5]at([yshift=-2.5cm]Item-D.south)(Item-E){Item: E\\Size: 4}; + + + \node[simpleNode, minimum height=1cm, fill=color5]at([xshift=1.5cm]Item-D.east)(Item-F){Item: F\\Size: 1}; + + \node[simpleNode, minimum height=1cm, fill=color6]at([yshift=-1cm]Item-F.south)(Item-G){Item: G\\Size: 1}; + + \node[simpleNode, minimum height=1cm, fill=color7]at([yshift=-1cm]Item-G.south)(Item-H){Item: H\\Size: 1}; + + \node[simpleNode, minimum height=1cm, fill=color8]at([yshift=-1cm]Item-H.south)(Item-I){Item: I\\Size: 1}; + + \end{tikzpicture} +\end{document} \ No newline at end of file diff --git a/doc/sphinx/docs/images/bin_packing/bin_packing_solution.png b/doc/sphinx/docs/images/bin_packing/bin_packing_solution.png new file mode 100644 index 000000000..12bf5cfb4 Binary files /dev/null and b/doc/sphinx/docs/images/bin_packing/bin_packing_solution.png differ diff --git a/doc/sphinx/docs/images/bin_packing/bin_packing_solution.tex b/doc/sphinx/docs/images/bin_packing/bin_packing_solution.tex new file mode 100644 index 000000000..e13f2e4f3 --- /dev/null +++ b/doc/sphinx/docs/images/bin_packing/bin_packing_solution.tex @@ -0,0 +1,79 @@ +\documentclass{standalone} +\usepackage[x11names]{xcolor} +\usepackage{tikz} +\usetikzlibrary{shapes,arrows,decorations.markings, arrows.meta} +\usetikzlibrary {positioning} +\usetikzlibrary{calc} +\usetikzlibrary{patterns} +\usepackage{enumitem} +\usepackage{helvet} +\usepackage[T1]{fontenc} + +%---------------------------------- Colors +\definecolor{color0}{RGB}{228,26,28} +\definecolor{color1}{RGB}{55,126,184} +\definecolor{color2}{RGB}{77,175,74} +\definecolor{color3}{RGB}{152,78,163} +\definecolor{color4}{RGB}{255,127,0} +\definecolor{color5}{RGB}{255,255,51} +\definecolor{color6}{RGB}{166,86,40} +\definecolor{color7}{RGB}{247,129,191} +\definecolor{color8}{RGB}{153,153,153} +\definecolor{color9}{RGB}{0,0,0} + +\tikzstyle{item} = [rectangle, draw, fill=color0, text width=2cm, text centered, minimum height=2cm] + +%---------------------------------------------------------------------------------- +\def \nodeDistance {2.8cm} + + +\begin{document} + \nopagecolor + + \begin{tikzpicture}[node distance = 2cm, auto,font=\sffamily\large] + + \node[item, minimum height=5cm, fill=color3](Item-C){Item: C\\Size: 5}; + \node[item, minimum height=2cm, fill=color2]at([yshift=-1cm]Item-C.south)(Item-B){Item: B\\Size: 2}; + + \node[item, minimum height=3cm, fill=color1]at([xshift=1.5cm, yshift=0.5cm]Item-B.east)(Item-A){Item: A\\Size: 3}; + \node[item, minimum height=4cm, fill=color5]at([yshift=2cm]Item-A.north)(Item-E){Item: E\\Size: 4}; + + + \node[item, minimum height=1cm, fill=color4]at([xshift=1.5cm, yshift=-0.98cm]Item-A.east)(Item-D){Item: D\\Size: 1}; + + + \node[item, minimum height=1cm, fill=color5]at([yshift=0.48cm]Item-D.north)(Item-F){Item: F\\Size: 1}; + + \node[item, minimum height=1cm, fill=color6]at([yshift=0.48cm]Item-F.north)(Item-G){Item: G\\Size: 1}; + + \node[item, minimum height=1cm, fill=color7]at([yshift=0.48cm]Item-G.north)(Item-H){Item: H\\Size: 1}; + + \node[item, minimum height=1cm, fill=color8]at([yshift=0.48cm]Item-H.north)(Item-I){Item: I\\Size: 1}; + + \node[item, minimum height=1cm, fill=white] at([yshift=-1cm]Item-B.south)(Bin1){Bin: 1\\Size: 7}; + \node[item, minimum height=1cm, fill=white] at([yshift=-1cm]Item-A.south)(Bin2){Bin: 2\\Size: 7}; + \node[item, minimum height=1cm, fill=white] at([yshift=-1cm]Item-D.south)(Bin3){Bin: 3\\Size: 7}; + \node[item, minimum height=1cm, fill=white] at([xshift=1.5cm]Bin3.east)(Bin4){Bin: 4\\Size: 7}; + \node[item, minimum height=1cm, fill=white] at([xshift=1.5cm]Bin4.east)(Bin5){Bin: 5\\Size: 7}; + \node[item, minimum height=1cm, fill=white] at([xshift=1.5cm]Bin5.east)(Bin6){Bin: 6\\Size: 7}; + + \draw[color=red,line width=1mm] (Item-B.south west) rectangle (Item-C.north east); + \draw[color=red,line width=1mm] (Item-A.south west) rectangle (Item-E.north east); + + \node[circle,inner sep=0pt,minimum size=0pt](B3) at ([yshift=7.02cm]Item-D.south east) {}; + \draw[color=red,line width=1mm] (Item-D.south west) rectangle (B3); + + \node[circle,inner sep=0pt,minimum size=0pt](B4-1) at ([yshift=0.48cm]Bin4.north west) {}; + \node[circle,inner sep=0pt,minimum size=0pt](B4-2) at ([xshift=2.24cm, yshift=7.5cm]Bin4.north west) {}; + \draw[color=red,line width=1mm] (B4-1.south west) rectangle (B4-2); + + \node[circle,inner sep=0pt,minimum size=0pt](B5-1) at ([yshift=0.48cm]Bin5.north west) {}; + \node[circle,inner sep=0pt,minimum size=0pt](B5-2) at ([xshift=2.24cm, yshift=7.5cm]Bin5.north west) {}; + \draw[color=red,line width=1mm] (B5-1.south west) rectangle (B5-2); + + \node[circle,inner sep=0pt,minimum size=0pt](B6-1) at ([yshift=0.48cm]Bin6.north west) {}; + \node[circle,inner sep=0pt,minimum size=0pt](B6-2) at ([xshift=2.24cm, yshift=7.5cm]Bin6.north west) {}; + \draw[color=red,line width=1mm] (B6-1.south west) rectangle (B6-2); + + \end{tikzpicture} +\end{document} \ No newline at end of file diff --git a/doc/sphinx/overview.rst b/doc/sphinx/overview.rst index ac0f53f7f..74debc310 100644 --- a/doc/sphinx/overview.rst +++ b/doc/sphinx/overview.rst @@ -1,3 +1,5 @@ +.. _capabilities: + Capabilities ============ @@ -33,11 +35,18 @@ Overview clusters, GPUs, SIMD vectorization, etc.). * A library of ready-to-use optimisation problems for algorithmic testing and performance evaluation - (Rosenbrock, Rastrigin, Lennard-Jones, etc.). + (Rosenbrock, Rastrigin, Lennard-Jones, etc_docs) [julius@julius-Desktop sphinx]$ ./compile.sh +rm -rf _build/* +warning: Tag 'TCL_SUBST' at line 270 of file 'Doxyfile' has become obsolete. + To avoid this warning please remove this line from your configuration file or upgrade it using "doxygen -u" +/home/julius/Projects/pagmo2/doc/sphinx/docs/cpp/problems/hock_schittkowsky_71.rst:2: WARNING: Explicit markup ends without a blank line; unexpected unindent. +/home/julius/Projects/pagmo2/doc/sphinx/doc.). * A library of optimisation-oriented utilities (e.g., hypervolume computation, non-dominated sorting, plotting, etc.). +.. _available_algorithms_problems: + List of algorithms ------------------ @@ -64,6 +73,8 @@ to use :ref:`meta-problems ` to turn constrained problems into unconstrained ones, and multi-objective problems into single-objective ones. +.. _heuristic_global_optimization: + Heuristic Global Optimization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ========================================================== ========================================= ========================= @@ -89,6 +100,8 @@ Multi-objective Hypervolume-based ACO (MHACO) :cpp:class:`pagmo::ma Non-dominated Sorting PSO (NSPSO) :cpp:class:`pagmo::nspso` M-U ========================================================== ========================================= ========================= +.. _local_optimization: + Local optimization ^^^^^^^^^^^^^^^^^^ ====================================================== ============================================================================================= =============== @@ -112,6 +125,8 @@ SNOPT (in pagmo_plugins_non_free affiliated package) `pagmo::snopt7 `__ S-CU ====================================================== ============================================================================================= =============== +.. _meta_algorithms: + Meta-algorithms ^^^^^^^^^^^^^^^ @@ -148,7 +163,7 @@ according to the following flags: * U = Unconstrained * I = Integer programming * sto = Stochastic - +.. _available_meta_problems: Scalable problems ^^^^^^^^^^^^^^^^^ ========================================================== ========================================= =============== diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index a44abec04..22e3e8b7e 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -19,7 +19,13 @@ endfunction() ADD_PAGMO_TUTORIAL(getting_started) ADD_PAGMO_TUTORIAL(first_udp_ver0) ADD_PAGMO_TUTORIAL(first_udp_ver1) +ADD_PAGMO_TUTORIAL(first_udp_ver1_solve) +ADD_PAGMO_TUTORIAL(first_udp_ver1_solve_parallel) +ADD_PAGMO_TUTORIAL(first_udp_ver1_solve_parallel_topology) ADD_PAGMO_TUTORIAL(nsga2_example) ADD_PAGMO_TUTORIAL(problem_basic) ADD_PAGMO_TUTORIAL(problem_basic_gh) ADD_PAGMO_TUTORIAL(problem_basic_s) +ADD_PAGMO_TUTORIAL(problem_bin_packing) +ADD_PAGMO_TUTORIAL(problem_bin_packing_EGOP) + diff --git a/tutorials/EGOP.cpp b/tutorials/EGOP.cpp new file mode 100644 index 000000000..6baaea0b7 --- /dev/null +++ b/tutorials/EGOP.cpp @@ -0,0 +1 @@ +#include "EGOP.h" diff --git a/tutorials/EGOP.h b/tutorials/EGOP.h new file mode 100644 index 000000000..d89be3759 --- /dev/null +++ b/tutorials/EGOP.h @@ -0,0 +1,8 @@ +#ifndef PAGMO_EGOP_H +#define PAGMO_EGOP_H + +class EGOP +{ +}; + +#endif // PAGMO_EGOP_H diff --git a/tutorials/first_udp_ver0.cpp b/tutorials/first_udp_ver0.cpp index 2c0574a17..9fcc45fa4 100644 --- a/tutorials/first_udp_ver0.cpp +++ b/tutorials/first_udp_ver0.cpp @@ -25,16 +25,16 @@ struct problem_v0 { int main() { // Construct a pagmo::problem from our example problem. - problem p{problem_v0{}}; + problem prob{problem_v0{}}; // Compute the value of the objective function // in the point (1, 2, 3, 4). - std::cout << "Value of the objfun in (1, 2, 3, 4): " << p.fitness({1, 2, 3, 4})[0] << '\n'; + std::cout << "Value of the objfun in (1, 2, 3, 4): " << prob.fitness({1, 2, 3, 4})[0] << '\n'; // Fetch the lower/upper bounds for the first variable. - std::cout << "Lower bounds: [" << p.get_lb()[0] << "]\n"; - std::cout << "Upper bounds: [" << p.get_ub()[0] << "]\n\n"; + std::cout << "Lower bounds: [" << prob.get_lb()[0] << "]\n"; + std::cout << "Upper bounds: [" << prob.get_ub()[0] << "]\n\n"; // Print p to screen. - std::cout << p << '\n'; + std::cout << prob << '\n'; } diff --git a/tutorials/first_udp_ver1.cpp b/tutorials/first_udp_ver1.cpp index b0d512c61..f418cd5d4 100644 --- a/tutorials/first_udp_ver1.cpp +++ b/tutorials/first_udp_ver1.cpp @@ -39,19 +39,19 @@ struct problem_v1 { int main() { // Construct a pagmo::problem from our example problem. - problem p{problem_v1{}}; + problem prob{problem_v1{}}; // Compute the value of the objective function, equality and // inequality constraints in the point (1, 2, 3, 4). - const auto fv = p.fitness({1, 2, 3, 4}); + const auto fv = prob.fitness({1, 2, 3, 4}); std::cout << "Value of the objfun in (1, 2, 3, 4): " << fv[0] << '\n'; std::cout << "Value of the eq. constraint in (1, 2, 3, 4): " << fv[1] << '\n'; std::cout << "Value of the ineq. constraint in (1, 2, 3, 4): " << fv[2] << '\n'; // Fetch the lower/upper bounds for the first variable. - std::cout << "Lower bounds: [" << p.get_lb()[0] << "]\n"; - std::cout << "Upper bounds: [" << p.get_ub()[0] << "]\n\n"; + std::cout << "Lower bounds: [" << prob.get_lb()[0] << "]\n"; + std::cout << "Upper bounds: [" << prob.get_ub()[0] << "]\n\n"; // Print p to screen. - std::cout << p << '\n'; + std::cout << prob << '\n'; } diff --git a/tutorials/first_udp_ver1_solve.cpp b/tutorials/first_udp_ver1_solve.cpp new file mode 100644 index 000000000..bad664e9b --- /dev/null +++ b/tutorials/first_udp_ver1_solve.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +using namespace pagmo; + +// Our simple example problem, version 2. +struct problem_v1 { + // Number of equality constraints. + vector_double::size_type get_nec() const + { + return 1; + } + // Number of inequality constraints. + vector_double::size_type get_nic() const + { + return 1; + } + // Implementation of the objective function. + vector_double fitness(const vector_double &dv) const + { + return { + dv[0] * dv[3] * (dv[0] + dv[1] + dv[2]) + dv[2], // objfun + dv[0] * dv[0] + dv[1] * dv[1] + dv[2] * dv[2] + dv[3] * dv[3] - 40., // equality con. + 25. - dv[0] * dv[1] * dv[2] * dv[3] // inequality con. + }; + } + // Implementation of the box bounds. + std::pair get_bounds() const + { + return {{1., 1., 1., 1.}, {5., 5., 5., 5.}}; + } +}; + +int main() +{ + // 1 - Construct a pagmo::problem from our example problem. + problem prob{problem_v1{}}; + + // 2 - Define a algorithm to solve the problem. In this case the Extended Ant Colony Optimization with 1000 generations + algorithm algo{gaco(1000)}; + + // 3 - Initiate the population of 1000 individuals + population pop{prob, 1000}; + + // 4 - Evolve the initialized population + pop = algo.evolve(pop); + + // 5 - Print the final individuals after + std::cout << pop; +} + diff --git a/tutorials/first_udp_ver1_solve_parallel.cpp b/tutorials/first_udp_ver1_solve_parallel.cpp new file mode 100644 index 000000000..b44246292 --- /dev/null +++ b/tutorials/first_udp_ver1_solve_parallel.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +using namespace pagmo; + +// Our simple example problem, version 3. +struct problem_v1 { + // Number of equality constraints. + vector_double::size_type get_nec() const + { + return 1; + } + // Number of inequality constraints. + vector_double::size_type get_nic() const + { + return 1; + } + // Implementation of the objective function. + vector_double fitness(const vector_double &dv) const + { + return { + dv[0] * dv[3] * (dv[0] + dv[1] + dv[2]) + dv[2], // objfun + dv[0] * dv[0] + dv[1] * dv[1] + dv[2] * dv[2] + dv[3] * dv[3] - 40., // equality con. + 25. - dv[0] * dv[1] * dv[2] * dv[3] // inequality con. + }; + } + // Implementation of the box bounds. + std::pair get_bounds() const + { + return {{1., 1., 1., 1.}, {5., 5., 5., 5.}}; + } +}; + +int main() +{ + // 1 - Construct a pagmo::problem from our example problem. + problem prob{problem_v1{}}; + + // 2 - Define a algorithm to solve the problem. In this case the Extended Ant Colony Optimization with 1000 generations. + algorithm algo{gaco(1000)}; + + // 3 - Instantiate an archipelago with 16 islands having each 1000 individuals. + archipelago archi{16, algo, prob, 1000}; + + // 4 - Run the evolution in parallel on the 16 separate islands 1 time. + archi.evolve(1); + + // 5 - Wait for the evolutions to finish. + archi.wait_check(); + + // 6 - Print the fitness of the best solution in each island. + for (const auto &isl : archi) { + std::cout << isl.get_population().champion_f()[0] << '\n'; + } +} + diff --git a/tutorials/first_udp_ver1_solve_parallel_topology.cpp b/tutorials/first_udp_ver1_solve_parallel_topology.cpp new file mode 100644 index 000000000..016f6c713 --- /dev/null +++ b/tutorials/first_udp_ver1_solve_parallel_topology.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +using namespace pagmo; + +// Our simple example problem, version 4. +struct problem_v1 { + // Number of equality constraints. + vector_double::size_type get_nec() const + { + return 1; + } + // Number of inequality constraints. + vector_double::size_type get_nic() const + { + return 1; + } + // Implementation of the objective function. + vector_double fitness(const vector_double &dv) const + { + return { + dv[0] * dv[3] * (dv[0] + dv[1] + dv[2]) + dv[2], // objfun + dv[0] * dv[0] + dv[1] * dv[1] + dv[2] * dv[2] + dv[3] * dv[3] - 40., // equality con. + 25. - dv[0] * dv[1] * dv[2] * dv[3] // inequality con. + }; + } + // Implementation of the box bounds. + std::pair get_bounds() const + { + return {{1., 1., 1., 1.}, {5., 5., 5., 5.}}; + } +}; + +int main() +{ + // 1 - Construct a pagmo::problem from our example problem. + problem prob{problem_v1{}}; + + // 2 - Define a algorithm to solve the problem. In this case the Extended Ant Colony Optimization with 1000 generations. + algorithm algo{gaco(100)}; + + // 3 - Define the topology of the archipelago + fully_connected topo{}; + + // 4 - Instantiate an archipelago with 16 islands having each 100 individuals. + archipelago archi{topo,16, algo, prob, 1000}; + + // 5 - Run the evolution in parallel on the 16 separate islands 10 times. + archi.evolve(10); + + // 6 - Wait for the evolutions to finish. + archi.wait_check(); + + // 7 - Print the fitness of the best solution in each island. + for (const auto &isl : archi) { + std::cout << isl.get_population().champion_f()[0] << '\n'; + } +} + diff --git a/tutorials/problem_bin_packing.cpp b/tutorials/problem_bin_packing.cpp new file mode 100644 index 000000000..b0a2605b7 --- /dev/null +++ b/tutorials/problem_bin_packing.cpp @@ -0,0 +1,122 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +struct bin_packing { + // constants of the bin packing problem (bpp) + int size_bins; // size and number of available bins + int num_bins; + std::vector items; // items that have to be packed + int num_items = int(items.size()); + + // Number of inequality constraints. + pagmo::vector_double::size_type get_nic() const { + return pagmo::vector_double::size_type(num_bins); + } + + // Integer dimension of the problem - i.e. where each item is packed + pagmo::vector_double::size_type get_nix() const { + return pagmo::vector_double::size_type(num_items); + } + + // Implementation of the objective function and all constraints + pagmo::vector_double fitness(const pagmo::vector_double &x_i) const { + // variables + double num_bins_used = 0; //how many bins are used + std::vector bin_used(num_bins, 0); + + // where x_i is the bin in which an item i is placed + // determine if a bin is used based on x_i + for (int i = 0; i < num_items; ++i) { + for (int j = 0; j < num_bins; ++j) { + if ( x_i[i] == j){ + bin_used[j] = 1; + } + } + } + + // Objective function calculation; i.e. how many bins are used? + // We want to minimize this! + for(auto& y: bin_used){ + num_bins_used += y; + } + + // Make return vector and adding objective + pagmo::vector_double return_vector{num_bins_used}; + + // Adding inequalities to stick to the maximum size of the bin + for (int j = 0; j < num_bins; ++j) { + int temp_bin_occupation = 0; + for (int i = 0; i < num_items; ++i) { + if (x_i[i] == j){ + temp_bin_occupation += items[i] ; // <= 0 + } + } + return_vector.emplace_back(temp_bin_occupation - size_bins); + } + return return_vector; + } + + // The lower and upper bounds are the bins in which an item can be placed. + std::pair get_bounds() const { + std::vector lower(num_items, 0); + std::vector upper(num_items, num_bins-1); + return {lower, upper}; + } +}; + + +int main(){ + + int size_bins = 7; + int num_bins = 6; + std::vector items{3,2,5,1,4,1,1,1,1}; + + // 1 - Define the topology of the archipelago + pagmo::problem prob{bin_packing{size_bins, num_bins, items}}; + + // 2 - Define the topology of the archipelago + pagmo::algorithm algo{pagmo::ihs(100)}; + + // 3 - Define the topology of the archipelago + pagmo::fully_connected topo{}; + + // 4 - Instantiate an archipelago with 16 islands having each 100 individuals. + pagmo::archipelago archi{topo, 16, algo, prob, 100}; + + // 5 - Run the evolution in parallel on the 8 separate islands 10 times. + archi.evolve(100); + + // 6 - Wait for the evolutions to finish. + archi.wait_check(); + + // 7 - Get the best solution across all islands. + // The first number in the champion vector is the number of islands used. + pagmo::population champion; + for (const auto &isl : archi) { + if (champion.size() == 0){ + champion = isl.get_population(); + } + if (champion.champion_f()[0] > isl.get_population().champion_f()[0]){ + champion = isl.get_population(); + } + } + + // 8 - Print the solution + for (int i=0; i < champion.champion_x().size(); i++){ + std::cout << "Item " << i << " is mapped to: " << champion.champion_x()[i] << std::endl; + } + // 9 - Print fitness value + std::cout << "Number of Islands used: " << champion.champion_f()[0] << std::endl; + + // 10 - Print space left in each bin. + for (int i=1; i < champion.champion_f().size(); i++){ + std::cout << "Space left in bin " << i << " : " << -champion.champion_f()[i] << std::endl; + } +} diff --git a/tutorials/problem_bin_packing_EGOP.cpp b/tutorials/problem_bin_packing_EGOP.cpp new file mode 100644 index 000000000..f0f51453d --- /dev/null +++ b/tutorials/problem_bin_packing_EGOP.cpp @@ -0,0 +1,122 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +struct bin_packing { + // constants of the bin packing problem (bpp) + int size_bins; // size and number of available bins + int num_bins; + std::vector items; // items that have to be packed + int num_items = int(items.size()); + + // Number of inequality constraints. + pagmo::vector_double::size_type get_nic() const { + return pagmo::vector_double::size_type(num_bins); + } + + // Integer dimension of the problem - i.e. where each item is packed + pagmo::vector_double::size_type get_nix() const { + return pagmo::vector_double::size_type(num_items); + } + + // Implementation of the objective function and all constraints + pagmo::vector_double fitness(const pagmo::vector_double &x_i) const { + // variables + double num_bins_used = 0; //how many bins are used + std::vector bin_used(num_bins, 0); + + // where x_i is the bin in which an item i is placed + // determine if a bin is used based on x_i + for (int i = 0; i < num_items; ++i) { + for (int j = 0; j < num_bins; ++j) { + if ( x_i[i] == j){ + bin_used[j] = 1; + } + } + } + + // Objective function calculation; i.e. how many bins are used? + // We want to minimize this! + for(auto& y: bin_used){ + num_bins_used += y; + } + + // Make return vector and adding objective + pagmo::vector_double return_vector{num_bins_used}; + + // Adding inequalities to stick to the maximum size of the bin + for (int j = 0; j < num_bins; ++j) { + int temp_bin_occupation = 0; + for (int i = 0; i < num_items; ++i) { + if (x_i[i] == j){ + temp_bin_occupation += items[i] ; // <= 0 + } + } + return_vector.emplace_back(temp_bin_occupation - size_bins); + } + return return_vector; + } + + // The lower and upper bounds are the bins in which an item can be placed. + std::pair get_bounds() const { + std::vector lower(num_items, 0); + std::vector upper(num_items, num_bins-1); + return {lower, upper}; + } +}; + +int main(){ + + int size_bins = 7; + int num_bins = 6; + std::vector items{3,2,5,1,4,1,1,1,1}; + + // 1 - Define the topology of the archipelago + pagmo::problem prob{bin_packing{size_bins, num_bins, items}}; + + // 2 - Define the topology of the archipelago + pagmo::algorithm algo{pagmo::ihs(100)}; + +// // 3 - Define the topology of the archipelago +// pagmo::fully_connected topo{}; +// +// // 4 - Instantiate an archipelago with 16 islands having each 100 individuals. +// pagmo::archipelago archi{topo, 16, algo, prob, 100}; +// +// // 5 - Run the evolution in parallel on the 8 separate islands 10 times. +// archi.evolve(100); +// +// // 6 - Wait for the evolutions to finish. +// archi.wait_check(); +// +// // 7 - Get the best solution across all islands. +// // The first number in the champion vector is the number of islands used. +// pagmo::population champion; +// for (const auto &isl : archi) { +// if (champion.size() == 0){ +// champion = isl.get_population(); +// } +// if (champion.champion_f()[0] > isl.get_population().champion_f()[0]){ +// champion = isl.get_population(); +// } +// } +// +// // 8 - Print the solution +// for (int i=0; i < champion.champion_x().size(); i++){ +// std::cout << "Item " << i << " is mapped to: " << champion.champion_x()[i] << std::endl; +// } +// // 9 - Print fitness value +// std::cout << "Number of Islands used: " << champion.champion_f()[0] << std::endl; +// +// // 10 - Print space left in each bin. +// for (int i=1; i < champion.champion_f().size(); i++){ +// std::cout << "Space left in bin " << i << " : " << -champion.champion_f()[i] << std::endl; +// } +}