Using GLPK in parallel_for loop - c++

I want to run the LP solver in GLPK in a parallel_for loop. The problems are all independent of each other so there shouldn't be any interference.
Here is an example code that fails, this is essentially the example code from the glpk wikibook but wrapped in a parallel_for loop. Any help will be appreciated
//#include <stdio.h> /* C input/output */
//#include <stdlib.h> /* C standard library */
#include <iostream>
#include <glpk.h> /* GNU GLPK linear/mixed integer solver */
#include <ppl.h>
using namespace concurrency;
using namespace std;
void main()
{
parallel_for(0, 10, [](int i){
/* declare variables */
glp_prob *lp;
int *ia = new int[4];
int *ja = new int[4];
double *ar = new double[4];
double z, x1, x2;
/* create problem */
lp = glp_create_prob();
glp_set_prob_name(lp, "minimax");
glp_set_obj_dir(lp, GLP_MAX);
/* fill problem */
glp_add_rows(lp, 2);
//glp_set_row_name(lp, 1, "p");
glp_set_row_bnds(lp, 1, GLP_UP, 0.0, 1.0);
//glp_set_row_name(lp, 2, "q");
glp_set_row_bnds(lp, 2, GLP_UP, 0.0, 2.0);
glp_add_cols(lp, 2);
//glp_set_col_name(lp, 1, "x1");
glp_set_col_bnds(lp, 1, GLP_LO, 0.0, 0.0);
glp_set_obj_coef(lp, 1, 0.6);
//glp_set_col_name(lp, 2, "x2");
glp_set_col_bnds(lp, 2, GLP_LO, 0.0, 0.0);
glp_set_obj_coef(lp, 2, 0.5);
ia[1] = 1, ja[1] = 1, ar[1] = 1.0; /* a[1,1] = 1 */
ia[2] = 1, ja[2] = 2, ar[2] = 2.0; /* a[1,2] = 2 */
ia[3] = 2, ja[3] = 1, ar[3] = 3.0; /* a[2,1] = 3 */
ia[4] = 2, ja[4] = 2, ar[4] = 1.0; /* a[2,2] = 1 */
glp_load_matrix(lp, 4, ia, ja, ar);
/* solve problem */
glp_simplex(lp, NULL);
/* recover and display results */
z = glp_get_obj_val(lp);
x1 = glp_get_col_prim(lp, 1);
x2 = glp_get_col_prim(lp, 2);
printf("z = %g; x1 = %g; x2 = %g\n", z, x1, x2);
/* housekeeping */
glp_delete_prob(lp);
glp_free_env();
});
system("pause");
}

You're calling glp_free_env from inside each thread, while the library is still actively doing work in other threads. That won't work well -- you're yanking the rug out from under threads working hard..
Instead call it only after all threads completed computation (join them). For this simple example, you can probably skip the cleanup step altogether.

I have found the problem. The issue is with the GLPK source code, there are a couple of routines that are not reenterable causing some big issues. This is documented here: http://en.wikibooks.org/wiki/GLPK/Using_the_GLPK_callable_library . There is also a fix in place but it requires rebuilding it. Note that this only works with version 4.50 of GLPK and older, newer versions have a slightly different layout.
While Ben was completely correct, making this change to the library solves all issues and lets you free the environment inside the loop.

Related

ncursesw causing weird behaviour

On WSL2, I'm using the first example code given in this tutorial website: https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/panels.html.
Code:
#include <panel.h>
int main()
{ WINDOW *my_wins[3];
PANEL *my_panels[3];
int lines = 10, cols = 40, y = 2, x = 4, i;
initscr();
cbreak();
noecho();
/* Create windows for the panels */
my_wins[0] = newwin(lines, cols, y, x);
my_wins[1] = newwin(lines, cols, y + 1, x + 5);
my_wins[2] = newwin(lines, cols, y + 2, x + 10);
/*
* Create borders around the windows so that you can see the effect
* of panels
*/
for(i = 0; i < 3; ++i)
box(my_wins[i], 0, 0);
/* Attach a panel to each window */ /* Order is bottom up */
my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */
my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */
my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */
/* Update the stacking order. 2nd panel will be on top */
update_panels();
/* Show it on the screen */
doupdate();
getch();
endwin();
}
When I run the code with the flags -lpanel -ncurses, it works fine as shown below:
When I run the code with the flags -lpanel -ncursesw, it doesn't work well:
The example shows two problems:
mixing -lpanel with -lncursesw (won't work because the size of the types holding character plus attributes differs).
You should use -lpanelw.
there's no call to setlocale to make line-drawing work portably.

How to solve a state space model with Odeint?

I am trying to implement a numerical simulation of a state space model using Eigen and Odeint. My trouble is that I need to reference control data U (predefined before integration) in order to properly solve the Ax+Bu part of the state space model. I was trying to accomplish this by using a counter to keep track of the current time step, but for whatever reason, it is reset to zero every time the System Function is called by Odeint.
How would I get around this? Is my approach to modeling the state space system flawed?
My System
struct Eigen_SS_NLTIV_Model
{
Eigen_SS_NLTIV_Model(matrixXd &ssA, matrixXd &ssB, matrixXd &ssC,
matrixXd &ssD, matrixXd &ssU, matrixXd &ssY)
:A(ssA), B(ssB), C(ssC), D(ssD), U(ssU), Y(ssY)
{
Y.resizeLike(U);
Y.setZero();
observerStep = 0;
testPtr = &observerStep;
}
/* Observer Function:*/
void operator()(matrixXd &x, double t)
{
Y.col(observerStep) = C*x + D*U.col(observerStep);
observerStep += 1;
}
/* System Function:
* ONLY the mathematical description of the system dynamics may be placed
* here. Any data placed in here is destroyed after each iteration of the
* stepper.
*/
void operator()(matrixXd &x, matrixXd &dxdt, double t)
{
dxdt = A*x + B*U.col(*testPtr);
//Cannot reference the variable "observerStep" directly as it gets reset
//every time this is called. *testPtr doesn't work either.
}
int observerStep;
int *testPtr;
matrixXd &A, &B, &C, &D, &U, &Y; //Input Vectors
};
My ODE Solver Setup
const double t_end = 3.0;
const double dt = 0.5;
int steps = (int)std::ceil(t_end / dt) + 1;
matrixXd A(2, 2), B(2, 2), C(2, 2), D(2, 2), x(2, 1);
matrixXd U = matrixXd::Constant(2, steps, 1.0);
matrixXd Y;
A << -0.5572, -0.7814, 0.7814, 0.0000;
B << 1.0, -1.0, 0.0, 2.0;
C << 1.9691, 6.4493, 1.9691, 6.4493;
D << 0.0, 0.0, 0.0, 0.0;
x << 0, 0;
Eigen_SS_NLTIV_Model matrixTest(A, B, C, D, U, Y);
odeint::integrate_const(odeint::runge_kutta4<matrixXd, double, matrixXd, double,
odeint::vector_space_algebra>(),
matrixTest, x, 0.0, t_end, dt, matrixTest);
//Ignore these two functions. They are there mostly for debugging.
writeCSV<matrixXd>(Y, "Y_OUT.csv");
prettyPrint<matrixXd>(Y, "Out Full");
With classical Runge-Kutta you know that your ODE model function is called 4 times per step with times t, t+h/2, t+h/2, t+h. With other solvers that implement adaptive step size you can not know in advance at what t the ODE model function is called.
You should implement U via some kind of interpolation function, in the most simple case as step function that computes some index from t and returns the U value for that index. Something like
i = (int)(t/U_step)
dxdt = A*x + B*U.col(i);

SuiteSparse(4.5.1)'s SPQR - calling to cholmod_allocate_triplet always returns NULL

I am trying to use SuiteSparse SPQR to solve a linear equation system x = A\b; my A matrix is sparse and it is a rectangular matrix so I chose SPQR to solve this.
I built SuiteSparse using MS Visual Studio 2012 on Windows 7 x64 using those provided by https://github.com/jlblancoc/suitesparse-metis-for-windows.
In order to test the function, I modified the spqr_example project to allocate tripets before converting to sparse matrix, instead of originally reading input from stdin to create a sparse matrix. I input a small A and b matrix for testing. The program compiled successfully. I debugged the program and found that my call to cholmod_allocate_triplet() has failed because in the declaration of this function it has this code below:
RETURN_IF_NULL_COMMON (NULL) ;
This always return false (even though my common starts successfully).
I don't want to explicitly make change to this line, as I might have make mistake somewhere or I forgot to do something I have to do because I am new to use the library.
Can anybody help give me some suggestion on how to make my program run properly? My code below is modified from the provided spqr_example. Thank you very much.
#include <iostream>
#include "SuiteSparseQR.hpp"
int main (int argc, char **argv)
{
cholmod_common Common, *cc ;
cholmod_sparse *A ;
cholmod_dense *X, *B, *Residual ;
double rnorm, one [2] = {1,0}, minusone [2] = {-1,0} ;
int mtype ;
// start CHOLMOD
cc = &Common ;
cholmod_l_start (cc) ;
// load A
//A = (cholmod_sparse *) cholmod_l_read_matrix (stdin, 1, &mtype, cc) ;
// A = [ 1 0 0 0;
// -1 1 0 0; ...
// 0 -1 1 0; ...
// 0 0 -1 1; ...
// 0 0 0 -1];
int row[] = {0, 1, 1, 2, 2, 3, 3, 4};
int col[] = {0, 0, 1, 1, 2, 2, 3, 3};
double val[] = {1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0};
int numEq = 5;
int numElement = 8;
int numSol = 4;
double b[] = {5.0, -5.0, 2.0, 1.0, 0.0};
cholmod_triplet* triplet = cholmod_allocate_triplet(5,4,5*4,0,CHOLMOD_REAL,cc);
int * triplet_i = (int *)(triplet->i);
int * triplet_j = (int *)(triplet->j);
double * triplet_x = (double *)(triplet->x);
for (int ne=0; ne<numElement; ne++)
{
triplet_i[triplet->nnz] = row[ne];
triplet_j[triplet->nnz] = col[ne];
triplet_x[triplet->nnz] = val[ne];
triplet->nnz++;
}
// Convert triplet to sparse matrix
A = cholmod_triplet_to_sparse(triplet, numElement, cc);
cholmod_free_triplet(&triplet, cc);
// B = ones (size (A,1),1)
//B = cholmod_l_ones (A->nrow, 1, A->xtype, cc) ;
B = cholmod_l_zeros(numEq, 1, CHOLMOD_REAL, cc);
for (int ne=0; ne<numEq; ne++)
{
((double *)(B->x))[ne] = val[ne];
}
// X = A\B
X = SuiteSparseQR<double>(A,B,cc);
//X = SuiteSparseQR <double> (A, B, cc) ;
// Print out the result
double *sol = static_cast<double *>(malloc(sizeof(X->x)));
sol = (double *)(X->x);
for (int r=0; r<numSol; r++)
{
std::cout << "x[" << r << "] = " << sol << std::endl;
sol++;
}
///// END HERE
// rnorm = norm (B-A*X)
Residual = cholmod_l_copy_dense (B, cc) ;
cholmod_l_sdmult (A, 0, minusone, one, X, Residual, cc) ;
rnorm = cholmod_l_norm_dense (Residual, 2, cc) ;
printf ("2-norm of residual: %8.1e\n", rnorm) ;
printf ("rank %ld\n", cc->SPQR_istat [4]) ;
// free everything and finish CHOLMOD
cholmod_l_free_dense (&Residual, cc) ;
cholmod_l_free_sparse (&A, cc) ;
cholmod_l_free_dense (&X, cc) ;
cholmod_l_free_dense (&B, cc) ;
cholmod_l_finish (cc) ;
return (0) ;
}
I have finally find out why my program broke after the line below
cholmod_triplet* triplet = cholmod_allocate_triplet(5,4,5*4,0,CHOLMOD_REAL,cc);
as the result of the cholmod_allocate_triplet() internally calling RETURN_IF_NULL_COMMON (NULL), which return false.
The reason is that I start the process calling
cholmod_l_start (cc) ;
which is the long int version of cholmod_start().
To fix the problem, I have to call cholmod_l_allocate_triplet() instead of cholmod_allocate_triplet() as well as change all other functions to use cholmod_l instead of only calling cholmod_

Any example of `cholmod_updown_solve()` (Updating in CHOLMOD)?

I'm working on a project using CHOLMOD in C++ to do Cholesky factorization updating. The only reference I can find is the User Guide. And cholmod_updown_solve() seems to be the right function for me. But there is no example on this function and I can't get a correct result.
Below is the essential part of my code. According to the user guide, the only thing to notice seems to be sorting the update matrix C in advance. But that doesn't work. Could anyone tell me if there's any important step I missed?
Also, I'm confused because the user guide says that the solution phi will be given "in the permuted ordering, not your original ordering". How could I restore the order without knowing the permutation matrix? (L->Perm doesn't work.)
// The original system is At*A*phi = At*b
// Updates: C*Ct is added to At*A (Here C is a sparse column vector)
size_t n = m_pMesh->numVertices();
double w = 1e3;
cholmod_sparse *C;
cholmod_triplet *C_coefficients;
cholmod_dense *Delta_Atb;
cholmod_common common;
cholmod_common *cm = &common;
cholmod_start(cm);
C_coefficients = cholmod_allocate_triplet(n, 1, 2, 0, CHOLMOD_REAL, cm);
Delta_Atb = cholmod_zeros(n, 1, CHOLMOD_REAL, cm);
// updates: two more constraints
CViewerVertex *pNew = stroke_ends.start;
CViewerVertex *qNew = stroke_ends.end;
cholmodEntry(C_coefficients, pNew->sid(), pNew->sid(), w, cm);
cholmodEntry(C_coefficients, qNew->sid(), qNew->sid(), w, cm);
// change to At*b is Delta_Atb
((double*)Delta_Atb->x)[pNew->sid()] = w * w;
C = cholmod_triplet_to_sparse(C_coefficients, C_coefficients->nnz, cm);
cholmod_sort(C, cm);
// phi is the given solution to the original system At*A*phi = At*b
// L is the Cholesky factor to modify
// Both phi and L should be overwritten here
cholmod_updown_solve(1, C, L, phi, Delta_Atb, cm);
cholmod_free_sparse(&C, cm);
cholmod_free_triplet(&C_coefficients, cm);
cholmod_free_dense(&Delta_Atb, cm);
cholmod_finish(cm);

Creating a sparse matrix in CHOLMOD or SuiteSparseQR

In SparseSuiteQR, all of the examples I can find use stdin or a file read to create a sparse matrix. Could someone provide a simple example of how to create one directly in C++?
Even better, in the CHOLMOD documentation, there is mention of a sparse2 function available in matlab, which behaves the same as the sparse. Can this be used in C++?
The data structures used by SuiteSparseQR (e.g. cholmod_sparse) are defined in the CHOLMOD library. You can find more information about it on the CHOLMOD documentation, which is much larger than the one from SuiteSparseQR.
I am assuming that you try to solve a linear system, see the CSparse package from Tim Davies, or boost matrix libraries which also have numeric bindings which interface umfpack and some lapack functions AFAIK...
CHOLMOD is a pretty awesome project - thanks Tim Davis :)
There is surprisingly a lot of code on GitHub that makes use of CHOLMOD, but you have to be logged into GitHub and know what you're looking for!
So, after crawling through CHOLMOD documentation and source code and then searching through GitHub for source code that uses CHOLMOD you would find out what to do.
But for most developers who want/need a quick example, here it is below.
*Note that your mileage might vary depending on how you compiled SuiteSparse.
(You might need to use the cholmod_ variant (without the l), i.e. not cholmod_l_; and use int for indexing, not long int).
// example.cpp
#include "SuiteSparseQR.hpp"
#include "SuiteSparse_config.h"
int main (int argc, char **argv)
{
cholmod_common Common, *cc;
cholmod_sparse *A;
cholmod_dense *X, *B;
// start CHOLMOD
cc = &Common;
cholmod_l_start (cc);
/* A =
[
1.1, 0.0, -0.5, 0.7
0.0, -2.0, 0.0, 0.0
0.0, 0.0, 0.9, 0.0
0.0, 0.0, 0.0, 0.6
]
*/
int m = 4; // num rows in A
int n = 4; // num cols in A
int nnz = 6; // num non-zero elements in A
int unsymmetric = 0; // A is non-symmetric: see cholmod.h > search for `stype` for more details
// In coordinate form (COO) a.k.a. triplet form (zero-based indexing)
int i[nnz] = {0, 1, 0, 2, 0, 3}; // row indices
int j[nnz] = {0, 1, 2, 2, 3, 3}; // col indices
double x[nnz] = {1.1, -2.0, -0.5, 0.9, 0.7, 0.6}; // values
// Set up the cholmod matrix in COO/triplet form
cholmod_triplet *T = cholmod_l_allocate_triplet(m, n, nnz, unsymmetric, CHOLMOD_REAL, cc);
T->nnz = nnz;
for (int ind = 0; ind < nnz; ind++)
{
((long int *) T->i)[ind] = i[ind]; // Notes:
((long int *) T->j)[ind] = j[ind]; // (1) casting necessary because these are void* (see cholmod.h)
((double *) T->x)[ind] = x[ind]; // (2) direct assignment will cause memory corruption
} // (3) long int for index pointers corresponds to usage of cholmod_l_* functions
// convert COO/triplet to CSC (compressed sparse column) format
A = (cholmod_sparse *) cholmod_l_triplet_to_sparse(T, nnz, cc);
// note: if you already know CSC format you can skip the triplet allocation and instead use cholmod_allocate_sparse
// and assign the member variables: see cholmod.h > cholmod_sparse_struct definition
// B = ones (size (A,1),1)
B = cholmod_l_ones (A->nrow, 1, A->xtype, cc);
// X = A\B
X = SuiteSparseQR <double> (A, B, cc);
// Print contents of X
printf("X = [\n");
for (int ind = 0; ind < n; ind++)
{
printf("%f\n", ((double *) X->x)[ind]);
}
printf("]\n");
fflush(stdout);
// free everything and finish CHOLMOD
cholmod_l_free_triplet (&T, cc);
cholmod_l_free_sparse (&A, cc);
cholmod_l_free_dense (&X, cc);
cholmod_l_free_dense (&B, cc);
cholmod_l_finish (cc);
return 0;
}
Supposing you have compiled SuiteSparse successfully and you have saved example.cpp in the base directory, then the following should work (on Linux):
gcc example.cpp -I./include -L./lib -lcholmod -lspqr -lsuitesparseconfig -o example
#Add SuiteSpare libraries to your `ld` search path if necessary
LD_LIBRARY_PATH=$(pwd)/lib
export LD_LIBRARY_PATH
./example
Output:
X = [
0.353535
-0.500000
1.111111
1.666667
]