/* nag_opt_handle_set_quadmatineq (e04rpc) Example Program.
*
* Copyright 2023 Numerical Algorithms Group.
*
* Mark 29.3, 2023.
*/
/* Read a 'generic' LMI/BMI SDP problem from the input file,
* formulate the problem via a handle and pass it to the solver.
*/
#include <nag.h>
#include <stdio.h>
int main(void) {
Integer exit_status = 0;
Integer blkidx, dimaq, idblk, idlc, idx, idxend, inform, j, midx, nblk, nclin,
nnzasum, nnzb, nnzc, nnzh, nnzqsum, nq, nvar;
double *a = 0, *b = 0, *bl = 0, *bu = 0, *cvec = 0, *h = 0, *q = 0, *x = 0;
double rinfo[32], stats[32];
Integer *icola = 0, *icolb = 0, *icolh = 0, *icolq = 0, *idxc = 0, *irowa = 0,
*irowb = 0, *irowh = 0, *irowq = 0, *nnza = 0, *nnzq = 0, *qi = 0,
*qj = 0;
void *handle = 0;
/* Nag Types */
NagError fail;
printf("nag_opt_handle_set_quadmatineq (e04rpc) Example Program Results\n\n");
fflush(stdout);
/* Skip heading in the data file. */
scanf("%*[^\n]");
/* Read the problem size. */
scanf("%" NAG_IFMT "%*[^\n]", &nvar);
scanf("%" NAG_IFMT "%*[^\n]", &nnzh);
scanf("%" NAG_IFMT " %" NAG_IFMT "%*[^\n]", &nclin, &nnzb);
scanf("%" NAG_IFMT "%*[^\n]", &nblk);
/* nag_opt_handle_init (e04rac).
* Initialize an empty problem handle with nvar variables. */
nag_opt_handle_init(&handle, nvar, NAGERR_DEFAULT);
/* Read the linear part of the objective function. */
if (!(cvec = NAG_ALLOC(nvar, double))) {
printf("Allocation failure\n");
exit_status = -1;
goto END;
}
for (j = 0; j < nvar; j++)
scanf("%lf", &cvec[j]);
scanf("%*[^\n]");
if (nnzh == 0) {
/* nag_opt_handle_set_linobj (e04rec).
* Add the linear objective function to the formulation. */
nag_opt_handle_set_linobj(handle, nvar, cvec, NAGERR_DEFAULT);
NAG_FREE(cvec);
} else {
/* The objective function is quadratic. Read nonzeros for H. */
if (!(irowh = NAG_ALLOC(nnzh, Integer)) ||
!(icolh = NAG_ALLOC(nnzh, Integer)) || !(h = NAG_ALLOC(nnzh, double)) ||
!(idxc = NAG_ALLOC(nvar, Integer))) {
printf("Allocation failure\n");
exit_status = -1;
goto END;
}
for (idx = 0; idx < nnzh; idx++)
scanf("%lf %" NAG_IFMT " %" NAG_IFMT "%*[^\n]", &h[idx], &irowh[idx],
&icolh[idx]);
/* The linear part of the objective was read in as dense,
* but the sparse format is needed here. */
for (idx = 0; idx < nvar; idx++)
idxc[idx] = idx + 1;
nnzc = nvar;
/* nag_opt_handle_set_quadobj (e04rfc).
* Add the quadratic objective to the handle.*/
nag_opt_handle_set_quadobj(handle, nnzc, idxc, cvec, nnzh, icolh, irowh, h,
NAGERR_DEFAULT);
NAG_FREE(idxc);
NAG_FREE(cvec);
NAG_FREE(irowh);
NAG_FREE(icolh);
NAG_FREE(h);
}
/* Read a block of linear constraints and its bounds if present. */
if (nclin > 0 && nnzb > 0) {
if (!(irowb = NAG_ALLOC(nnzb, Integer)) ||
!(icolb = NAG_ALLOC(nnzb, Integer)) || !(b = NAG_ALLOC(nnzb, double)) ||
!(bl = NAG_ALLOC(nclin, double)) || !(bu = NAG_ALLOC(nclin, double))) {
printf("Allocation failure\n");
exit_status = -1;
goto END;
}
/* Read all matrix B nonzeros. */
for (idx = 0; idx < nnzb; idx++)
scanf("%lf %" NAG_IFMT " %" NAG_IFMT "%*[^\n]", &b[idx], &irowb[idx],
&icolb[idx]);
/* Read the lower and upper bounds. */
for (j = 0; j < nclin; j++)
scanf("%lf", &bl[j]);
scanf("%*[^\n]");
for (j = 0; j < nclin; j++)
scanf("%lf", &bu[j]);
scanf("%*[^\n]");
idlc = 0;
/* nag_opt_handle_set_linconstr (e04rjc).
* Add the block of linear constraints to the problem formulation. */
nag_opt_handle_set_linconstr(handle, nclin, bl, bu, nnzb, irowb, icolb, b,
&idlc, NAGERR_DEFAULT);
NAG_FREE(irowb);
NAG_FREE(icolb);
NAG_FREE(b);
NAG_FREE(bl);
NAG_FREE(bu);
}
/* Read all matrix inequalities. */
for (blkidx = 0; blkidx < nblk; blkidx++) {
/* Read the dimension of this matrix inequality. */
scanf("%" NAG_IFMT "%*[^\n]", &dimaq);
/* Read the number of all nonzeros in linear and bilinear parts. */
scanf("%" NAG_IFMT " %" NAG_IFMT "%*[^\n]", &nnzasum, &nnzqsum);
idblk = 0;
if (nnzasum > 0) {
/* Read a linear matrix inequality composed of (nvar+1) matrices. */
if (!(nnza = NAG_ALLOC(nvar + 1, Integer)) ||
!(irowa = NAG_ALLOC(nnzasum, Integer)) ||
!(icola = NAG_ALLOC(nnzasum, Integer)) ||
!(a = NAG_ALLOC(nnzasum, double))) {
printf("Allocation failure\n");
exit_status = -1;
goto END;
}
idx = 0;
for (midx = 0; midx <= nvar; midx++) {
/* Read matrix A_midx. */
scanf("%" NAG_IFMT "%*[^\n]", &nnza[midx]);
idxend = idx + nnza[midx];
for (; idx < idxend; idx++)
scanf("%lf %" NAG_IFMT " %" NAG_IFMT "%*[^\n]", &a[idx], &irowa[idx],
&icola[idx]);
}
idblk = 0;
/* nag_opt_handle_set_linmatineq (e04rnc).
* Add the linear matrix constraint to the problem formulation. */
nag_opt_handle_set_linmatineq(handle, nvar, dimaq, nnza, nnzasum, irowa,
icola, a, 1, NULL, &idblk, NAGERR_DEFAULT);
NAG_FREE(nnza);
NAG_FREE(irowa);
NAG_FREE(icola);
NAG_FREE(a);
}
if (nnzqsum > 0) {
/* Read bilinear part of the matrix inequality composed
* of nq matrices. */
scanf("%" NAG_IFMT "%*[^\n]", &nq);
if (!(qi = NAG_ALLOC(nq, Integer)) || !(qj = NAG_ALLOC(nq, Integer)) ||
!(nnzq = NAG_ALLOC(nq, Integer)) ||
!(irowq = NAG_ALLOC(nnzqsum, Integer)) ||
!(icolq = NAG_ALLOC(nnzqsum, Integer)) ||
!(q = NAG_ALLOC(nnzqsum, double))) {
printf("Allocation failure\n");
exit_status = -1;
goto END;
}
idx = 0;
for (midx = 0; midx < nq; midx++) {
/* Read matrix Q_ij where i=qi[midx], j=qj[midx]. */
scanf("%" NAG_IFMT " %" NAG_IFMT "%*[^\n]", &qi[midx], &qj[midx]);
scanf("%" NAG_IFMT "%*[^\n]", &nnzq[midx]);
idxend = idx + nnzq[midx];
for (; idx < idxend; idx++)
scanf("%lf %" NAG_IFMT " %" NAG_IFMT "%*[^\n]", &q[idx], &irowq[idx],
&icolq[idx]);
}
/* nag_opt_handle_set_quadmatineq (e04rpc).
* Expand the existing linear matrix inequality with the bilinear
* terms or (if the linear part was not present) create a
* new matrix inequality. */
nag_opt_handle_set_quadmatineq(handle, nq, qi, qj, dimaq, nnzq, nnzqsum,
irowq, icolq, q, &idblk, NAGERR_DEFAULT);
NAG_FREE(qi);
NAG_FREE(qj);
NAG_FREE(nnzq);
NAG_FREE(irowq);
NAG_FREE(icolq);
NAG_FREE(q);
}
}
/* Problem was successfully decoded. */
printf("SDP problem was read, passing it to the solver.\n\n");
fflush(stdout);
/* nag_opt_handle_print (e04ryc).
* Print overview of the handle. */
nag_opt_handle_print(handle, 6, "Overview, Matrix Constraints",
NAGERR_DEFAULT);
/* Allocate memory for the solver. */
if (!(x = NAG_ALLOC(nvar, double))) {
printf("Allocation failure\n");
exit_status = -1;
goto END;
}
for (j = 0; j < nvar; j++)
x[j] = 0.0;
/* Call the solver nag_opt_handle_solve_pennon (e04svc),
* ignore Lagrangian multipliers. */
INIT_FAIL(fail);
nag_opt_handle_solve_pennon(handle, nvar, x, 0, NULL, 0, NULL, 0, NULL, rinfo,
stats, &inform, &fail);
if (fail.code != NE_NOERROR) {
printf("Error from nag_opt_handle_solve_pennon (e04svc).\n%s\n",
fail.message);
exit_status = 1;
goto END;
}
END:
/* nag_opt_handle_free (e04rzc).
* Destroy the problem handle and deallocate all the memory. */
if (handle)
nag_opt_handle_free(&handle, NAGERR_DEFAULT);
NAG_FREE(x);
return exit_status;
}