an example of a multi-precision call#
This is an example of how to use the expo package to solve a nonlinearly
constrained optimization problem with data provided both as
32-bit integers and double precision reals, and then again as
64-bit integers and single precision reals; the code is available in
$GALAHAD/src/expo/C/expotm.c .
Notice that C-style indexing is used, and that this is flagged by setting
control.f_indexing to false. The appropriate real and integer
types are supplied to each set of data. The structures and calls
for the first set of data takes double reals and int32_t integers,
while for the second the data uses
float reals and int64_t integers, and appends _s_64 to all
structure and function names.
/* expotm.c */
/* Test for the EXPO C interface using C sparse matrix indexing */
/* and simulataneous use of different precisions and integer types */
/* Jari Fowkes & Nick Gould, STFC-Rutherford Appleton Laboratory, 2025 */
#include <stdio.h>
#include <math.h>
#include "galahad_c.h"
#ifdef REAL_128
#include <quadmath.h>
#endif
// Custom userdata struct
struct userdata_type {
double p;
};
struct userdata_type_s_64 {
float p;
};
// Function prototypes
int fc( int32_t n, int32_t m, const double x[], double *f, double c[],
const void * );
int gj( int32_t n, int32_t m, int32_t jne, const double x[], double g[],
double jval[], const void * );
int hl( int32_t n, int32_t m, int32_t hne, const double x[], const double y[],
double hval[], const void * );
int fc_s_64( int64_t n, int64_t m, const float x[], float *f, float c[],
const void * );
int gj_s_64( int64_t n, int64_t m, int64_t jne, const float x[], float g[],
float jval[], const void * );
int hl_s_64( int64_t n, int64_t m, int64_t hne, const float x[],
const float y[], float hval[], const void * );
int main(void) {
// double precision reals and 32-bit integers
// Derived types
void *data;
struct expo_control_type control;
struct expo_inform_type inform;
printf(" tests double precision reals and 32-bit integers\n\n");
// Set user data
struct userdata_type userdata;
userdata.p = 9.0;
// Set problem data
int32_t n = 2; // # variables
int32_t m = 5; // # constraints
int32_t j_ne = 10; // Jacobian elements
int32_t h_ne = 2; // Hesssian (lower triangle) elements
// 0-based indices
int32_t J_row[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4}; // Jacobian J
int32_t J_col[] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
int32_t H_row[] = {0, 1}; // Hessian H, NB lower triangle
int32_t H_col[] = {0, 1};
// Set storage
double y[m]; // multipliers
double z[n]; // dual variables
double c[m]; // constraints
double gl[n]; // gradients
double xl[] = {-50.0, -50.0}; // lower variable bounds
double xu[] = {50.0, 50.0}; // upper variable bounds
double cl[] = {0.0, 0.0, 0.0, 0.0, 0.0}; // lower constraint bounds
double cu[] = {INFINITY, INFINITY, INFINITY,
INFINITY, INFINITY}; // upper constraint bounds
double x[] = {3.0,1.0}; // starting point
int32_t status;
// Initialize EXPO
expo_initialize( &data, &control, &inform );
// Set user-defined control options
control.f_indexing = false; // C sparse matrix indexing
//control.print_level = 1;
control.max_it = 20;
control.max_eval = 100;
control.stop_abs_p = 0.00001;
control.stop_abs_d = 0.00001;
control.stop_abs_c = 0.00001;
// Solve the problem
expo_import( &control, &data, &status, n, m,
"coordinate", j_ne, J_row, J_col, NULL,
"coordinate", h_ne, H_row, H_col, NULL );
expo_solve_hessian_direct( &data, &userdata, &status,
n, m, j_ne, h_ne,
cl, cu, xl, xu, x, y, z, c, gl,
fc, gj, hl );
expo_information( &data, &inform, &status );
if(inform.status == 0){
printf("%6i iterations. Optimal objective value"
" = %.2f status = %1i\n", inform.iter, inform.obj, inform.status);
}else{
printf("EXPO_solve exit status = %1i\n", inform.status);
}
// Delete internal workspace
expo_terminate( &data, &control, &inform );
// double precision reals and 32-bit integers
// Derived types
void *data_s_64;
struct expo_control_type_s_64 control_s_64;
struct expo_inform_type_s_64 inform_s_64;
printf("\n expo test with single precision reals and 64-bit integers\n\n");
// Set user data
struct userdata_type_s_64 userdata_s_64;
userdata_s_64.p = 9.0;
// Set problem data
int64_t n_64 = 2; // # variables
int64_t m_64 = 5; // # constraints
int64_t j_ne_64 = 10; // Jacobian elements
int64_t h_ne_64 = 2; // Hesssian elements
// 0-based indices
int64_t J_row_64[] = {0, 0, 1, 1, 2, 2, 3, 3, 4, 4}; // Jacobian J
int64_t J_col_64[] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
int64_t H_row_64[] = {0, 1}; // Hessian H, NB lower triangle
int64_t H_col_64[] = {0, 1};
// Set storage
float y_s[m]; // multipliers
float z_s[n]; // dual variables
float c_s[m]; // constraints
float gl_s[n]; // gradients
float xl_s[] = {-50.0, -50.0}; // lower variable bounds
float xu_s[] = {50.0, 50.0}; // upper variable bounds
float cl_s[] = {0.0, 0.0, 0.0, 0.0, 0.0}; // lower constraint bounds
float cu_s[] = {INFINITY, INFINITY, INFINITY,
INFINITY, INFINITY}; // upper constraint bounds
float x_s[] = {3.0,1.0}; // starting point
int64_t status_64;
// Initialize EXPO
expo_initialize_s_64( &data_s_64, &control_s_64, &inform_s_64 );
// Set user-defined control options
control_s_64.f_indexing = false; // C sparse matrix indexing
//control_s_64.print_level = 1;
control_s_64.max_it = 20;
control_s_64.max_eval = 100;
control_s_64.stop_abs_p = 0.001;
control_s_64.stop_abs_d = 0.001;
control_s_64.stop_abs_c = 0.001;
control_s_64.tru_control.error = 0;
// Solve the problem
expo_import_s_64( &control_s_64, &data_s_64, &status_64, n_64, m_64,
"coordinate", j_ne_64, J_row_64, J_col_64, NULL,
"coordinate", h_ne_64, H_row_64, H_col_64, NULL );
expo_solve_hessian_direct_s_64( &data_s_64, &userdata_s_64, &status_64,
n_64, m_64, j_ne_64, h_ne_64,
cl_s, cu_s, xl_s, xu_s,
x_s, y_s, z_s, c_s, gl_s,
fc_s_64, gj_s_64, hl_s_64 );
expo_information_s_64( &data_s_64, &inform_s_64, &status_64 );
if(inform_s_64.status == 0){
printf("%6li iterations. Optimal objective value = %.2f status = %1li\n",
inform_s_64.iter, inform_s_64.obj, inform_s_64.status);
}else{
printf("EXPO_solve exit status = %1li\n", inform_s_64.status);
}
// Delete internal workspace
expo_terminate_s_64( &data_s_64, &control_s_64, &inform_s_64 );
}
// compute the function and constraint values
int fc( int32_t n, int32_t m, const double x[], double *f, double c[],
const void *userdata ){
struct userdata_type *myuserdata = ( struct userdata_type * ) userdata;
double p = myuserdata->p;
*f = pow(x[0],2.0) + pow(x[1],2.0);
c[0] = x[0] + x[1] - 1.0;
c[1] = pow(x[0],2.0) + pow(x[1],2.0) - 1.0;
c[2] = p * pow(x[0],2.0) + pow(x[1],2.0) - p;
c[3] = pow(x[0],2.0) - x[1];
c[4] = pow(x[1],2.0) - x[0];
return 0;
}
// compute the gradient and Jacobian
int gj( int32_t n, int32_t m, int32_t jne, const double x[], double g[],
double jval[], const void *userdata ){
struct userdata_type *myuserdata = (struct userdata_type *) userdata;
double p = myuserdata->p;
g[0] = 2.0 * x[0];
g[1] = 2.0 * x[1];
jval[0] = 1.0;
jval[1] = 1.0;
jval[2] = 2.0 * x[0];
jval[3] = 2.0 * x[1];
jval[4] = 2.0 * p * x[0];
jval[5] = 2.0 * x[1];
jval[6] = 2.0 * x[0];
jval[7] = - 1.0;
jval[8] = - 1.0;
jval[9] = 2.0 * x[1];
return 0;
}
// compute the Hessian of the Lagrangian
int hl( int32_t n, int32_t m, int32_t hne, const double x[], const double y[],
double hval[], const void *userdata ){
struct userdata_type *myuserdata = (struct userdata_type *) userdata;
double p = myuserdata->p;
hval[0] = 2.0 - 2.0 * (y[1] + p * y[2] + y[3]);
hval[1] = 2.0 - 2.0 * (y[1] + y[2] + y[4]);
return 0;
}
// compute the function and constraint values
int fc_s_64( int64_t n, int64_t m, const float x[], float *f, float c[],
const void *userdata_s_64 ){
struct userdata_type_s_64 *myuserdata
= (struct userdata_type_s_64 *) userdata_s_64;
float p = myuserdata->p;
*f = pow(x[0],2.0) + pow(x[1],2.0);
c[0] = x[0] + x[1] - 1.0;
c[1] = pow(x[0],2.0) + pow(x[1],2.0) - 1.0;
c[2] = p * pow(x[0],2.0) + pow(x[1],2.0) - p;
c[3] = pow(x[0],2.0) - x[1];
c[4] = pow(x[1],2.0) - x[0];
return 0;
}
// compute the gradient and Jacobian
int gj_s_64( int64_t n, int64_t m, int64_t jne, const float x[],
float g[], float jval[], const void *userdata_s_64 ){
struct userdata_type_s_64 *myuserdata
= (struct userdata_type_s_64 *) userdata_s_64;
float p = myuserdata->p;
g[0] = 2.0 * x[0];
g[1] = 2.0 * x[1];
jval[0] = 1.0;
jval[1] = 1.0;
jval[2] = 2.0 * x[0];
jval[3] = 2.0 * x[1];
jval[4] = 2.0 * p * x[0];
jval[5] = 2.0 * x[1];
jval[6] = 2.0 * x[0];
jval[7] = - 1.0;
jval[8] = - 1.0;
jval[9] = 2.0 * x[1];
return 0;
}
// compute the Hessian of the Lagrangian
int hl_s_64( int64_t n, int64_t m, int64_t hne, const float x[],
const float y[], float hval[], const void *userdata_s_64 ){
struct userdata_type_s_64 *myuserdata
= (struct userdata_type_s_64 *) userdata_s_64;
float p = myuserdata->p;
hval[0] = 2.0 - 2.0 * (y[1] + p * y[2] + y[3]);
hval[1] = 2.0 - 2.0 * (y[1] + y[2] + y[4]);
return 0;
}