Quick start
OptFrame is a C++ framework to solve challenging optimization problems, specially by means of metaheuristic techniques. It has no external dependencies, except a C++ compiler compatible with C++17 (or C++20).
After installing OptFrame (or just cloning it), user can start building a solution to the problem at hand.
Welcome Message
A useful abstraction was introduced since OptFrame 4.1, called OptFrame Functional Core (FCore). The idea of FCore is to provide a simplified access to OptFrame programming classes, by means of closures and lambdas. This way, a project that typically had 8 to 10 files is reduced to a single file (all included in headers!).
The first test on FCore is to see if it’s correctly compiling. So let’s just include its main header, and print its welcome() message:
File 'mytest.cpp' located in 'demo/01_QuickstartWelcome/src/'
1// file: 'mytest.cpp'
2#include <OptFCore/FCore.hpp>
3#include <iostream>
4int
5main()
6{
7 std::cout << optframe::FCore::welcome() << std::endl;
8 return 0;
9}
Build with make
One way to compile it locally is just copy src/ folder inside your project and see the results (using GCC C++ compiler):
g++ --std=c++20 mytest.cpp -o fcore_mytest
./fcore_mytest
# Welcome to OptFrame Functional Core (FCore) - version 4.1-dev
If a local copy of OptFrame is being used in other folder (via git clone), one needs to pass its location via flag -I to the compiler (considering relative location of ./optframe/src/):
File 'makefile' located in 'demo/01_QuickstartWelcome/'
1all: demo_quickstart_welcome
2
3demo_quickstart_welcome:
4 g++ --std=c++20 -I../../include src/mytest.cpp -o demo_welcome
5 # Expects: Welcome to OptFrame Functional Core (FCore) - version 4.1-dev
6 ./demo_welcome
7
8
9build_with_bazel:
10 bazel build ... --cxxopt=-std=c++17
Build with bazel
If one wants to build in Windows or any other system, easiest manner is to use Bazel. Just create a WORKSPACE.bazel file that points to remote OptFrame git repository:
File 'WORKSPACE.bazel' located in 'demo/01_QuickstartWelcome/'
1load('@bazel_tools//tools/build_defs/repo:git.bzl', 'git_repository')
2git_repository(
3 name='OptFrame',
4 remote='https://github.com/optframe/optframe.git',
5 branch='master'
6)
And use the following BUILD.bazel file (with dependency to @OptFrame):
File 'BUILD.bazel' located in 'demo/01_QuickstartWelcome/'
1#load("@rules_cc//cc:defs.bzl", "cc_library", "cc_binary")
2cc_binary(
3 name = "demo_welcome",
4 srcs = ["src/mytest.cpp"],
5 deps=["@optframe//include:OptFCore"],
6 copts = select({
7 "@bazel_tools//src/conditions:windows": ["/std:c++17"],
8 "@bazel_tools//src/conditions:darwin": ["--std=c++17"],
9 "//conditions:default": ["--std=c++17"],
10 }),
11)
Just invoke bazel build system (assuming MinGW C/C++ toolchain on Windows or just remove option --compiler for Linux):
bazel build --compiler=mingw-gcc ...
bazel run :demo_welcome
# Welcome to OptFrame Functional Core (FCore) - version 4.1-dev
A deeper explanation of OptFrame theoretical foundations can be found on Concepts section, so we will move fast here!
First Example: 0-1 Knapsack Problem and Simulated Annealing
Let’s consider a classic problem: the 0-1 Knapsack Problem (KP).
By: Dake CC BY-SA 2.5
Given a set of items \(I\), the KP consists in selecting some items \(S \subseteq I\), such that the sum of weights \(w_i\) (for each selected item) do not exceed knapsack capacity \(Q\), and profit \(p_i\) of the selected items is maximized.
$$maximize\; \sum_{i \in S} p_i$$ $$\sum_{i \in S} w_i \leq Q$$ $$S \subseteq I$$
Solution and Evaluation Types
Users must first define a Representation, which is a data structure that represents
an element in the Solution Space for the KP. A natural candidate here is an array of booleans,
since we need to decide if we are going to carry each item or not. In C++, an interesting
approach is to use stl containers, such as a std::vector<int>.
User also needs to specify the data type for the Objective Space, in general a numeric type.
In this case, we will simply choose
an Evaluation<int> (just ignore the Evaluation container for now…).
We declare a XESolution pair that aggregates both spaces as a single
type ESolutionKP (meaning an evaluated solution for the knapsack problem):
1// SPDX-License-Identifier: MIT OR LGPL-3.0-or-later
2// Copyright (C) 2007-2022 - OptFrame developers
3// https://github.com/optframe/optframe
4
5// OptFrame Demo 0-1 Knapsack Problem + Simulated Annealing
6// File: KP-fcore-ex.hpp
7#pragma once
8
9#define NO_CXX_MODULES 1
10
11// C++
12#include <algorithm>
13#include <functional>
14#include <iostream>
15#include <utility>
16#include <vector>
17//
18#include <OptFrame/printable/printable.hpp>
19using namespace optframe;
20//
21#include <OptFCore/FCore.hpp>
22#include <OptFCore/FCoreAll.hpp>
23#include <OptFrame/Core.hpp>
24#include <OptFrame/Heuristics.hpp> // many metaheuristics here...
25#include <OptFrame/Scanner++/Scanner.hpp>
26#include <OptFrame/Util/Matrix.hpp>
27#include <OptFrame/printable/printable.hpp>
28
29using namespace std; // NOLINT
30using namespace optframe; // NOLINT
31using namespace scannerpp; // NOLINT
32
33// namespace para o problema da mochila
34// namespace KP_fcore {
35
36// Solução para o problema da mochila, e elemento de avaliação
37
38// ================================
39// Definição do 'ESolution'
40// Par: (Representação, Avaliação)
41// ================================
42
43using ESolutionKP = std::pair<std::vector<bool>, // (representation)
44 Evaluation<int> // (objective value)
45 >;
Hint
As long as fields first and second are provided on XESolution concept, any class can
be used instead of std::pair, as demonstrated on Explicit XESolution
section.
Warning
Since OptFrame v4, any data structure can be used as a solution representation, as long as it implements operator<<.
OptFrame Classic (<= v3) required a templated class named Solution<R,ADS>, passing both
a representation type R and auxiliary data structure type ADS. This is no longer mandatory, but still widely
used on the available examples.
Problem Context
Users will need to store general problem information (such as profits and weights of items), so a ProblemContext can be introduced. For easy interoperability with file and string inputs (on Linux/Windows), we use Scanner class to process problem data (some details of ‘load’ function will only be discussed in a later moment):
1class ProblemContext {
2 public:
3 int n{0}; // numero de itens
4 int Q{-1}; // capacidade máxima da mochila
5 vector<int> p; // lucro 'p' de cada item
6 vector<int> w; // peso 'w' de cada item
7 //
8 // leitor de dados "estilo Java" (Scanner)
9 void load(Scanner& scanner) {
10 n = *scanner.nextInt(); // leitura do numero de itens na mochila
11 Q = *scanner.nextInt(); // leitura da capacidade da mochila
12 p = vector<int>(n); // realoca espaço
13 w = vector<int>(n); // realoca espaço
14 //
15 std::cout << "n=" << n << " Q=" << Q << std::endl;
16 //
17 // leitura do lucro do item i
18 for (int i = 0; i < n; i++) {
19 p[i] =
20 *scanner.nextInt(); // '*' é usado pq saída do 'nextInt' é 'optional'
21 std::cout << "p[" << i << "]=" << p[i] << " ";
22 }
23 std::cout << std::endl;
24 //
25 // leitura do peso do item i
26 for (int i = 0; i < n; i++) {
27 w[i] =
28 *scanner.nextInt(); // '*' é usado pq saída do 'nextInt' é 'optional'
29 std::cout << "w[" << i << "]=" << w[i] << " ";
30 }
31 std::cout << std::endl;
32 }
33};
34// Instanciar um problema da mochila pKP
35// ProblemContext pKP; // NOLINT
Hint
ProblemContext is a user-defined class that can have any desired format. A ‘load’ function
is just a suggestion, but not at all necessary. The object pKP is declared in global scope
just to simplify the example, but it could be embedded in any other component if user desires.
Random Constructive
We need to have some initial solution for the search process, so we just proceed in a random manner. For simplicity, we allow infeasible solutions to be generated (as if capacity was infinite).
1std::vector<bool> frandom(sref<ProblemContext> pKP) {
2 vector<bool> v(pKP->n, false); // começa sem nenhum item escolhido
3 for (unsigned i = 0; i < v.size(); i++)
4 v[i] = rand() % 2; // sorteia se leva item ou não (resultado 0 ou 1)
5 // retorna solução
6 return v;
7}
8
9// Gerador de solução inicial (método construtivo)
10// FConstructive<std::vector<bool>, ProblemContext> randomConstructive{pKP,
11// frandom};
Hint
User can also define many advanced constructive techniques in a similar manner, such as greedy and greedy randomized approaches.
Evaluator
Now it’s time to define an evaluation (or objective) function. According to the goal of maximizing the profits, we iterate over selected items to accumulate profit and weights. As discussed in constructive section, we allow accumulated weight to surpass knapsack capacity, for infeasible configurations. To discourage that, we introduce negative penalization whenever capacity is exceeded (assuming weight -1000000):
1// ===========================
2// Função de avaliação
3// ===========================
4
5// função de avaliação da mochila
6Evaluation<int> fevaluate(sref<ProblemContext> pKP,
7 const std::vector<bool>& s) {
8 int f = 0;
9 int somaPeso = 0;
10 for (int i = 0; i < pKP->n; i++)
11 if (s[i]) // se elemento foi escolhido
12 {
13 f += pKP->p[i]; // acumula lucro do elemento i
14 somaPeso += pKP->w[i]; // acumula peso do elemento i
15 }
16 // verifica capacidade excedida
17 if (somaPeso >= pKP->Q)
18 f -= 1000000 *
19 (somaPeso - pKP->Q); // punição proporcional ao excesso de peso
20 //
21 return Evaluation<int>{f};
22}
23
24// Evaluate (false -> maximização)
25// FEvaluator<ESolutionKP, MAXIMIZE> evalKP{fevaluate};
We have defined fevaluate function to create an Evaluator object named evalKP,
in a MAXIMIZE direction.
Hint
User can choose MINIMIZE if dealing with a minimization problem. For multi-objective
problems and Pareto optimization, user should visit Multi-Objective section.
Neighborhood Structure
In order to improve a given solution, several metaheuristics employ Local Search Optimization techniques based on the concept of Neighborhood Structure. Every neighborhood is related to a move operator, which is required (on FCore) to have an undo operation (capable of reverting the effects of the move).
We create a BitFlip move, that changes the true/false selection of a given item \(k\).
In this case, the move structure (representation of the move) is just an int, that represents the flipped item.
Note the makeMoveBitFlip move generator based on FCore library.
1// MoveBitFlip (moveData = 'int' (k))
2using MoveBitFlip = FMove<int, ESolutionKP>;
3
4// vizinhança: operador de "movimento" que faz "bit flip" (0 -> 1; 1 -> 0) na
5// posição k
6int fApplyFlip(const int& k, ESolutionKP& se) {
7 // se.first[k] = 1 - se.first[k]; // inverte elemento 'k'
8 se.first[k] = !se.first[k]; // inverte elemento 'k'
9 return k; // movimento reverso
10}
11
12uptr<Move<ESolutionKP>> makeMoveBitFlip(int k) {
13 return uptr<Move<ESolutionKP>>(new MoveBitFlip{k, fApplyFlip});
14}
The definition of the move can be done using inheritance, if one finds easier (which is what we will adopt).
1//
2class MoveBitFlip : public Move<ESolutionKP> {
3 public:
4 int k; // MoveBitFlip (moveData = 'int' (k))
5
6 explicit MoveBitFlip(int _k) : k{_k} {}
7
8 uptr<Move<ESolutionKP>> apply(ESolutionKP& se) override {
9 se.first[k] = !se.first[k]; // reverts element 'k'
10 return uptr<Move<ESolutionKP>>(new MoveBitFlip{k}); // returns reverse move
11 }
12};
13
14uptr<Move<ESolutionKP>> makeMoveBitFlip(int k) {
15 return uptr<Move<ESolutionKP>>(new MoveBitFlip{k});
16}
Now, it’s time to define a neighborhood generator for the move.
OptFrame has three main types of neighborhoods: NS, NSSeq and NSEnum.
In this example, we will use NS, since it only requires the generation of random moves:
1// gerador de movimentos aleatórios do tipo BitFlip
2uptr<Move<ESolutionKP>> fRandomFlip(sref<ProblemContext> pKP,
3 const ESolutionKP& se) {
4 int k = ::rand() % pKP->n; // sorteia um item entre [0..n-1]
5 // cria um "movimento" de flip, na posição k, com operação 'fApplyFlip'
6 return uptr<Move<ESolutionKP>>(makeMoveBitFlip(k));
7}
8
9// Estrutura de Vizinhança para BitFlip (NS)
10// FNS<ESolutionKP> nsFlip{fRandomFlip};
11
12// ================== EVERYTHING TOGETHER ====================
13
14class OptFrameDemoKP {
15 public:
16 FConstructive<std::vector<bool>, ProblemContext> randomConstructive;
17 FEvaluator<ESolutionKP, MAXIMIZE, ProblemContext> evalKP;
18 FNS<ESolutionKP, ProblemContext> nsFlip;
19
20 explicit OptFrameDemoKP(sref<ProblemContext> p)
21 : randomConstructive{p, frandom},
22 evalKP{FEvaluator<ESolutionKP, MAXIMIZE, ProblemContext>{p, fevaluate}},
23 nsFlip{FNS<ESolutionKP, ProblemContext>{p, fRandomFlip}} {}
24};
Hint
It is usually a good idea to start developing over the simplest neighborhood, which is NS.
Most (non-deterministic) metaheuristics only requires a NS, as it only requires the generation of random moves.
More advanced neighborhoods based on iterators, such as NSSeq and NSEnum are only required for advanced Local Search methods.
Time to Test!
At this point, you can already test many nice metaheuristics and solve your knapsack problem! We use the following code to load a problem instance (see Complete Example after):
1std::cout << "======== Carregando Problema ========" << std::endl;
2// semente pseudo-aleatória fixa em zero
3srand(time(NULL));
4
5std::string sinstance = "knapsack-example.txt";
6File f{sinstance};
7
8if (!f.isOpen()) {
9 std::cerr << "Problema '" << sinstance << "' não encontrado no diretório!"
10 << std::endl;
11 return 1;
12}
13
14Scanner scanner{std::move(f)};
15
16sref<ProblemContext> pKP{new ProblemContext{}};
17pKP->load(scanner);
18std::cout << "número de elementos na mochila:" << pKP->n << std::endl;
19
20OptFrameDemoKP demo{pKP};
Hint
It is useful to test every FCore structure independently, so as to develop unit testing for them.
To test the constructive and evaluator:
1std::cout << "======== Testa Construtivo Aleatório ========" << std::endl;
2// invoca método 'generateSolution' do FCore 'FConstructive' para construtivo
3// aleatório
4std::vector<bool> sol = *demo.randomConstructive.generateSolution(0.0);
5// imprime solução inicial
6std::cout << sol << std::endl;
7//
8std::cout << "======== Testa Avaliador ========" << std::endl;
9// avalia solução inicial e cria um par 'ESolution'
10ESolutionKP esol(sol, demo.evalKP.evaluate(sol));
11// imprime avaliação da solução inicial
12esol.second.print();
Now we give an example with of the most well-known metaheuristics: the Simulated Annealing.
It has few parameters, including: initial temperature T0, cooling factor alpha, and iterations per temperature iterT.
1std::cout << "======== Executa Simulated Annealing ========" << std::endl;
2// Especifica um gerador aleatório para o Simulated Annealing
3RandGen rg;
4//
5// Cria objeto da classe 'InitialSearch' (parecido com 'construtivoAleatório')
6BasicInitialSearch<ESolutionKP> initRand(nnptr::copy(demo.randomConstructive),
7 nnptr::copy(demo.evalKP));
8// Instancia um Simulated Annealing com alpha=98%, iterações na temp = 100,
9// temperatura inicial = 99999
10BasicSA<ESolutionKP> sa(nnptr::copy(demo.evalKP), nnptr::copy(initRand),
11 nnptr::copy(demo.nsFlip), 0.98, 100, 99999,
12 nnptr::copy(rg));
13// executa o SA e coleta o 'status' de saída
14// passa um 'Criterio de Parada' por tempo (= 10 segundos)
15optframe::Timer t;
16auto searchOut = sa.search(
17 StopCriteria<ESolutionKP::second_type>{10.0}); // 10.0 seconds max
18std::cout << "spent time: " << t.now() << "s" << std::endl;
19// pega melhor solução do método SA
20ESolutionKP melhor = *searchOut.best; //*sa.getBestSolution();
21std::cout << "======== Imprime melhor solução do SA ========" << std::endl;
22// imprime representação da melhor solução
23cout << melhor.first << std::endl;
24// imprime avaliação da melhor solução
25melhor.second.print();
Complete Example
Warning
We present a complete example below. Note that some small differences may exist due to updates in tutorial, including language details.
Feel free to check folder OptFrame/Examples for other examples on FCore and OptFrame Classic.
Example is divided in two files: KP-fcore-ex.hpp and mainKP-fcore-ex.cpp.
Hint
This example could be made in a single file, to be even simpler. However, we recommend users to have
a clear separation for the header declaration of FCore components (on KP-fcore-ex.hpp)
from the main() entrypoint (on mainKP-fcore-ex.cpp), since unit testing is much simpler when these are decoupled.
KP-fcore-ex.hpp
File 'KP-fcore-ex.hpp' located in 'demo/02_QuickstartKP_SA/'
1// SPDX-License-Identifier: MIT OR LGPL-3.0-or-later
2// Copyright (C) 2007-2022 - OptFrame developers
3// https://github.com/optframe/optframe
4
5// OptFrame Demo 0-1 Knapsack Problem + Simulated Annealing
6// File: KP-fcore-ex.hpp
7#pragma once
8
9#define NO_CXX_MODULES 1
10
11// C++
12#include <algorithm>
13#include <functional>
14#include <iostream>
15#include <utility>
16#include <vector>
17//
18#include <OptFrame/printable/printable.hpp>
19using namespace optframe;
20//
21#include <OptFCore/FCore.hpp>
22#include <OptFCore/FCoreAll.hpp>
23#include <OptFrame/Core.hpp>
24#include <OptFrame/Heuristics.hpp> // many metaheuristics here...
25#include <OptFrame/Scanner++/Scanner.hpp>
26#include <OptFrame/Util/Matrix.hpp>
27#include <OptFrame/printable/printable.hpp>
28
29using namespace std; // NOLINT
30using namespace optframe; // NOLINT
31using namespace scannerpp; // NOLINT
32
33// namespace para o problema da mochila
34// namespace KP_fcore {
35
36// Solução para o problema da mochila, e elemento de avaliação
37
38// ================================
39// Definição do 'ESolution'
40// Par: (Representação, Avaliação)
41// ================================
42
43using ESolutionKP = std::pair<std::vector<bool>, // (representation)
44 Evaluation<int> // (objective value)
45 >;
46class ProblemContext {
47 public:
48 int n{0}; // numero de itens
49 int Q{-1}; // capacidade máxima da mochila
50 vector<int> p; // lucro 'p' de cada item
51 vector<int> w; // peso 'w' de cada item
52 //
53 // leitor de dados "estilo Java" (Scanner)
54 void load(Scanner& scanner) {
55 n = *scanner.nextInt(); // leitura do numero de itens na mochila
56 Q = *scanner.nextInt(); // leitura da capacidade da mochila
57 p = vector<int>(n); // realoca espaço
58 w = vector<int>(n); // realoca espaço
59 //
60 std::cout << "n=" << n << " Q=" << Q << std::endl;
61 //
62 // leitura do lucro do item i
63 for (int i = 0; i < n; i++) {
64 p[i] =
65 *scanner.nextInt(); // '*' é usado pq saída do 'nextInt' é 'optional'
66 std::cout << "p[" << i << "]=" << p[i] << " ";
67 }
68 std::cout << std::endl;
69 //
70 // leitura do peso do item i
71 for (int i = 0; i < n; i++) {
72 w[i] =
73 *scanner.nextInt(); // '*' é usado pq saída do 'nextInt' é 'optional'
74 std::cout << "w[" << i << "]=" << w[i] << " ";
75 }
76 std::cout << std::endl;
77 }
78};
79// Instanciar um problema da mochila pKP
80// ProblemContext pKP; // NOLINT
81
82std::vector<bool> frandom(sref<ProblemContext> pKP) {
83 vector<bool> v(pKP->n, false); // começa sem nenhum item escolhido
84 for (unsigned i = 0; i < v.size(); i++)
85 v[i] = rand() % 2; // sorteia se leva item ou não (resultado 0 ou 1)
86 // retorna solução
87 return v;
88}
89
90// Gerador de solução inicial (método construtivo)
91// FConstructive<std::vector<bool>, ProblemContext> randomConstructive{pKP,
92// frandom};
93
94// ===========================
95// Função de avaliação
96// ===========================
97
98// função de avaliação da mochila
99Evaluation<int> fevaluate(sref<ProblemContext> pKP,
100 const std::vector<bool>& s) {
101 int f = 0;
102 int somaPeso = 0;
103 for (int i = 0; i < pKP->n; i++)
104 if (s[i]) // se elemento foi escolhido
105 {
106 f += pKP->p[i]; // acumula lucro do elemento i
107 somaPeso += pKP->w[i]; // acumula peso do elemento i
108 }
109 // verifica capacidade excedida
110 if (somaPeso >= pKP->Q)
111 f -= 1000000 *
112 (somaPeso - pKP->Q); // punição proporcional ao excesso de peso
113 //
114 return Evaluation<int>{f};
115}
116
117// Evaluate (false -> maximização)
118// FEvaluator<ESolutionKP, MAXIMIZE> evalKP{fevaluate};
119//
120class MoveBitFlip : public Move<ESolutionKP> {
121 public:
122 int k; // MoveBitFlip (moveData = 'int' (k))
123
124 explicit MoveBitFlip(int _k) : k{_k} {}
125
126 uptr<Move<ESolutionKP>> apply(ESolutionKP& se) override {
127 se.first[k] = !se.first[k]; // reverts element 'k'
128 return uptr<Move<ESolutionKP>>(new MoveBitFlip{k}); // returns reverse move
129 }
130};
131
132uptr<Move<ESolutionKP>> makeMoveBitFlip(int k) {
133 return uptr<Move<ESolutionKP>>(new MoveBitFlip{k});
134}
135// gerador de movimentos aleatórios do tipo BitFlip
136uptr<Move<ESolutionKP>> fRandomFlip(sref<ProblemContext> pKP,
137 const ESolutionKP& se) {
138 int k = ::rand() % pKP->n; // sorteia um item entre [0..n-1]
139 // cria um "movimento" de flip, na posição k, com operação 'fApplyFlip'
140 return uptr<Move<ESolutionKP>>(makeMoveBitFlip(k));
141}
142
143// Estrutura de Vizinhança para BitFlip (NS)
144// FNS<ESolutionKP> nsFlip{fRandomFlip};
145
146// ================== EVERYTHING TOGETHER ====================
147
148class OptFrameDemoKP {
149 public:
150 FConstructive<std::vector<bool>, ProblemContext> randomConstructive;
151 FEvaluator<ESolutionKP, MAXIMIZE, ProblemContext> evalKP;
152 FNS<ESolutionKP, ProblemContext> nsFlip;
153
154 explicit OptFrameDemoKP(sref<ProblemContext> p)
155 : randomConstructive{p, frandom},
156 evalKP{FEvaluator<ESolutionKP, MAXIMIZE, ProblemContext>{p, fevaluate}},
157 nsFlip{FNS<ESolutionKP, ProblemContext>{p, fRandomFlip}} {}
158};
mainKP-fcore-ex.cpp
File 'mainKP-fcore-ex.cpp' located in 'demo/02_QuickstartKP_SA/'
1// mainKP-fcore-ex.cpp
2
3#define NO_CXX_MODULES 1
4
5// C++
6#include <iostream>
7
8//
9#include "KP-fcore-ex.hpp" // implementação da mochila
10
11// import everything on main()
12using namespace std; // NOLINT
13using namespace optframe; // NOLINT
14using namespace scannerpp; // NOLINT
15// using namespace KP_fcore;
16
17int main(int argc, char** argv) {
18 std::cout << "======== Carregando Problema ========" << std::endl;
19 // semente pseudo-aleatória fixa em zero
20 srand(time(NULL));
21
22 std::string sinstance = "knapsack-example.txt";
23 File f{sinstance};
24
25 if (!f.isOpen()) {
26 std::cerr << "Problema '" << sinstance << "' não encontrado no diretório!"
27 << std::endl;
28 return 1;
29 }
30
31 Scanner scanner{std::move(f)};
32
33 sref<ProblemContext> pKP{new ProblemContext{}};
34 pKP->load(scanner);
35 std::cout << "número de elementos na mochila:" << pKP->n << std::endl;
36
37 OptFrameDemoKP demo{pKP};
38 std::cout << "======== Testa Construtivo Aleatório ========" << std::endl;
39 // invoca método 'generateSolution' do FCore 'FConstructive' para construtivo
40 // aleatório
41 std::vector<bool> sol = *demo.randomConstructive.generateSolution(0.0);
42 // imprime solução inicial
43 std::cout << sol << std::endl;
44 //
45 std::cout << "======== Testa Avaliador ========" << std::endl;
46 // avalia solução inicial e cria um par 'ESolution'
47 ESolutionKP esol(sol, demo.evalKP.evaluate(sol));
48 // imprime avaliação da solução inicial
49 esol.second.print();
50
51 std::cout << "======== Executa Simulated Annealing ========" << std::endl;
52 // Especifica um gerador aleatório para o Simulated Annealing
53 RandGen rg;
54 //
55 // Cria objeto da classe 'InitialSearch' (parecido com 'construtivoAleatório')
56 BasicInitialSearch<ESolutionKP> initRand(nnptr::copy(demo.randomConstructive),
57 nnptr::copy(demo.evalKP));
58 // Instancia um Simulated Annealing com alpha=98%, iterações na temp = 100,
59 // temperatura inicial = 99999
60 BasicSA<ESolutionKP> sa(nnptr::copy(demo.evalKP), nnptr::copy(initRand),
61 nnptr::copy(demo.nsFlip), 0.98, 100, 99999,
62 nnptr::copy(rg));
63 // executa o SA e coleta o 'status' de saída
64 // passa um 'Criterio de Parada' por tempo (= 10 segundos)
65 optframe::Timer t;
66 auto searchOut = sa.search(
67 StopCriteria<ESolutionKP::second_type>{10.0}); // 10.0 seconds max
68 std::cout << "spent time: " << t.now() << "s" << std::endl;
69 // pega melhor solução do método SA
70 ESolutionKP melhor = *searchOut.best; //*sa.getBestSolution();
71 std::cout << "======== Imprime melhor solução do SA ========" << std::endl;
72 // imprime representação da melhor solução
73 cout << melhor.first << std::endl;
74 // imprime avaliação da melhor solução
75 melhor.second.print();
76
77 std::cout << "======== Fim da Execução ========" << std::endl;
78 return 0;
79} // main
knapsack-example.txt
File 'knapsack-example.txt' located in 'demo/02_QuickstartKP_SA/'
15
210
31 1 1 5 5
41 2 3 7 8
To compile it (generates binary app_KP):
g++ -g -O3 --std=c++20 -I../../include mainKP-fcore-ex.cpp -o app_KP