Solver lp_solve z C++ ako knižnica

Inštalácia a kompilácia pod Linuxom

Ak chceme lp_solve používať ako knižnicu, potrebujeme si nainštalovať -dev verziu príslušného balíčku. Týmto dosiahneme, že sa nám nainštaluje nielen samotný solver skompilovaný ako knižnica, ale aj hlavičkové súbory pre jej použitie v našich programoch.

V distribúciách Linuxu používajúcich apt by sa aktuálna verzia príslušného balíčku mala volať liblpsolve55-dev. (To "55" je aktuálna verzia, teda 5.5.)

Pri kompilácii z príkazového riadku môžeme následne používať napr. nasledovný príkaz:

g++ -g -O2 -std=gnu++20 -Wall -Wextra solve_lpsolve.cc -o solve_lpsolve -I /usr/include/lpsolve -llpsolve55 -lcolamd

(Prepínač -I hovorí kompilátoru kde hľadať dodatočné hlavičkové súbory a prepínač -l názov knižnice, ktorú k projektu prilinkovať. Pozor na to, že u prepínačov -l záleží na tom, že majú byť až na konci celého príkazového riadku.)

Inštalácia a kompilácia vo Windows

Skompilovanú (DLL aj LIB) knižnicu aj príslušné hlavičkové súbory si môžeš stiahnuť priamo od autorov tu: https://github.com/lp-solve/lp_solve/releases/download/5.5.2.14/lp_solve_5.5.2.14_dev_win64.zip.

Ďalej si v dokumentácii svojho IDE nájdi, kam umiestniť knižnicu a hlavičkové súbory tak, aby ich kompilátor našiel a použil. (Napr. vo VSCode by malo byť potrebné pridať príslušné -l prepínače do tasks.json a pridať hlavičkové súbory knižnice do projektu.)

Dokumentácia knižnice

Dokumentácia metód poskytovaných knižnicou je tu: https://lpsolve.sourceforge.net/5.5/.

Príklad použitia: kuracie nugetky

Nasledovný C++ program rieši ukážkovú úlohu s kuracími nugetkami. Vyskúšaj si ho skompilovať a spustiť.

#include <cassert>
#include <iostream>
#include <vector>
#include "lp_lib.h" // hlavickovy subor pre lp_solve
using namespace std;

int to_int(REAL hodnota) { return static_cast<int>(round(static_cast<double>(hodnota))); }

int main() {
    lprec *program = make_lp(0, 3); // vyrobime novy ILP s 0 "riadkami" (obmedzeniami) a 3 "stlpcami" (premennymi)

    // nastavime, ze vsetky premenne su celociselne
    for (int i=1; i<=3; ++i) set_int(program, i, TRUE); // set_binary ak chceme binarne premenne

    // definujeme si a pridame ciel
    REAL ciel[4]; // hodnota na indexe 0 sa ignoruje
    ciel[1] = 6;
    ciel[2] = 9;
    ciel[3] = 20;
    set_obj_fn(program, ciel);
    set_maxim(program); // ciel chceme maximalizovat

    // definujeme si a pridame obmedzenie
    REAL obmedzenie[4];
    obmedzenie[1] = 200;
    obmedzenie[2] = 290;
    obmedzenie[3] = 610;
    add_constraint(program, obmedzenie, LE, 3200); // LE je konstanta pre "Less than or Equal", su aj EQ a GE

    // nastavime nakolko vela vystupu chceme vidiet od solvera
    set_verbose(program, IMPORTANT);

    // tu to fakt netreba ale pre vacsie problemy chceme zapnut nejaky presolving
    set_presolve(program, PRESOLVE_ROWS | PRESOLVE_COLS | PRESOLVE_LINDEP, get_presolveloops(program));

    // vyriesime program a skontrolujeme, ze mal optimalne riesenie
    int result_code = solve(program);
    assert( result_code == OPTIMAL );

    // zistime a vypiseme optimalnu hodnotu ciela 
    REAL objective_value = get_objective(program);
    cout << to_int(objective_value) << endl;

    // zistime a vypiseme zodpovedajuce hodnoty premennych
    REAL hodnoty[3];
    get_variables(program, hodnoty); // pozor, tu kniznica indexuje od nuly
    cout << "   male = " << to_int(hodnoty[0]) << endl;
    cout << "stredne = " << to_int(hodnoty[1]) << endl;
    cout << "  velke = " << to_int(hodnoty[2]) << endl;

    // upraceme po sebe pamat
    delete_lp(program);
}