# Category talk:Wren-linear

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

## Linear Algebra

There have been several RC tasks where the use of linear algebra solvers has produced results much more quickly than more basic algorithms and the purpose of this module is to provide such functionality for the Wren programmer.

Rather than try to write a solver from scratch in Wren itself which would be very difficult and relatively slow, I've decided instead to write a Wren wrapper for most of the GNU Linear Programming Kit (GLPK) - only the more advanced routines have been omitted. Although not the fastest solver available, GLPK is open source, well documented and written in Ansi C which makes it a good fit for solving smaller problems using Wren.

Despite its C heritage, GLPK uses 1-based arrays but, as a convenience feature, one can pass Wren's normal zero-based lists to the C wrapper and the underlying C code will change them to 1-based before passing them to the API functions themselves.

Whilst calling API functions directly is usually faster, it is also possible to write problems using GLPK's MathProg language and then process these using methods in the Tran class. This is far easier when there are a large number of variables and/or constraints to deal with.

## Source code (Wren)

```/* Module "linear.wren" */

/* Glp contains various glpk constants and miscellaneous methods. */
class Glp {
/* optimization direction flag */
static MIN { 1 }  // minimization
static MAX { 2 }  // maximization

/* kind of structural variable */
static CV { 1 }  // continuous
static IV { 2 }  // integer
static BV { 3 }  // binary

/* type of auxiliary/structural variable */
static FR { 1 }  // free (unbounded)
static LO { 2 }  // has lower bound
static UP { 3 }  // has upper bound
static DB { 4 }  // has double bound
static FX { 5 }  // fixed

/* status of auxiliary/structural variable */
static BS { 1 }  // basic
static NL { 2 }  // non-basic on lower bound
static NU { 3 }  // non-basic on upper bound
static NF { 4 }  // non-basic free (unbounded)
static NS { 5 }  // non-basic fixed

/* scaling options */
static SF_GM   { 0x01 }  // geometric mean
static SF_EQ   { 0x10 }  // equilibration
static SF_2N   { 0x20 }  // power of two
static SF_SKIP { 0x40 }  // skip if well scaled
static SF_AUTO { 0x80 }  // automatic

/* solution indicator */
static SOL { 1 }  // basic
static IPT { 2 }  // interior-point
static MIP { 3 }  // mixed integer

/* solution status */
static UNDEF  { 1 }  // undefined
static FEAS   { 2 }  // feasible
static INFEAS { 3 }  // infeasible
static NOFEAS { 4 }  // no feasible exists
static OPT    { 5 }  // optimal
static UNBND  { 6 }  // unbounded

/* simplex solver control message level */
static MSG_OFF { 0 }  // no output
static MSG_ERR { 1 }  // warning and error messages only
static MSG_ON  { 2 }  // normal output
static MSG_ALL { 3 }  // full output
static MSG_DBG { 4 }  // debug output

/* simplex solver control method option */
static PRIMAL { 1 }  // use primal
static DUALP  { 2 }  // use dual; if it fails, use primal
static DUAL   { 3 }  // use dual

/* simplex solver control pricing technique */
static PT_STD { 0x11 }  // standard (Dantzig's rule)
static PT_PSE { 0x22 }  // projected steepest edge

/* simplex solver control ratio test technique */
static RT_STD { 0x11 }  // standard (textbook)
static RT_HAR { 0x22 }  // Harris' two-pass

/* interior-point solver control ordering algorithm */
static ORD_NONE   { 0 }  // natural (original) ordering
static ORD_QMD    { 1 }  // quotient minimum degree (QMD)
static ORD_AMD    { 2 }  // approx. minimum degree (AMD)
static ORD_SYMAMD { 3 }  // approx. minimum degree (SYMAMD)

/* integer optimizer control branching technique */
static BR_FFV { 1 }  // first fractional variable
static BR_LFV { 2 }  // last fractional variable
static BR_MFV { 3 }  // most fractional variable
static BR_DTH { 4 }  // heuristic by Driebeck and Tomlin
static BR_PCH { 5 }  // hybrid pseudocost heuristic

/* integer optimizer control backtracking technique */
static BT_DFS { 1 }  // depth first search
static BT_BFS { 2 }  // breadth first search
static BT_BLB { 3 }  // best local bound
static BT_BPH { 4 }  // best projection heuristic

/* integer optimizer control preprocessing technique */
static PP_NONE { 0 }  // disable preprocessing
static PP_ROOT { 1 }  // preprocessing only on root level
static PP_ALL  { 2 }  // preprocessing on all levels

/* enable/disable flag */
static ON  { 1 }  // enable something
static OFF { 0 }  // disable something

/* return codes */
static EBADB   { 0x01 }  // invalid basis
static ESING   { 0x02 }  // singular matrix
static ECOND   { 0x03 }  // ill-conditioned matrix
static EBOUND  { 0x04 }  // invalid bounds
static EFAIL   { 0x05 }  // solver failed
static EOBJLL  { 0x06 }  // objective lower limit reached
static EOBJUL  { 0x07 }  // objective upper limit reached
static EITLIM  { 0x08 }  // iteration limit exceeded
static ETMLIM  { 0x09 }  // time limit exceeded
static ENOPFS  { 0x0A }  // no primal feasible solution
static ENODFS  { 0x0B }  // no dual feasible solution
static EROOT   { 0x0C }  // root LP optimum not provided
static ESTOP   { 0x0D }  // search terminated by application
static EMIPGAP { 0x0E }  // relative mip gap tolerance reached
static ENOFEAS { 0x0F }  // no primal/dual feasible solution
static ENOCVG  { 0x10 }  // no convergence
static EINSTAB { 0x11 }  // numerical instability
static EDATA   { 0x12 }  // invalid data
static ERANGE  { 0x13 }  // result out of range

/* condition indicator */
static KKT_PE { 1 }  // primal equalities
static KKT_PB { 2 }  // primal bounds
static KKT_DE { 3 }  // dual equalities
static KKT_DB { 4 }  // dual bounds
static KKT_CS { 5 }  // complementary slackness

/* MPS file format */
static MPS_DECK { 1 }  // fixed (ancient)
static MPS_FILE { 2 }  // free (modern)

/* Miscellaneous methods */
foreign static checkDup(m, n, ne, ia, ja)
foreign static initEnv()
foreign static version
foreign static freeEnv()
foreign static termOut(flag)
}

/* Prob represents an optimization problem. */
foreign class Prob {
construct create() {}

foreign setProbName(name)
foreign setObjName(name)
foreign setObjDir(dir)
foreign setRowName(i, name)
foreign setColName(j, name)
foreign setRowBnds(i, type, lb, ub)
foreign setColBnds(j, type, lb, ub)
foreign setObjCoef(j, coef)
foreign setMatRow(i, len, ind, val)
foreign setMatCol(j, len, ind, val)
foreign sortMatrix()
foreign delRows(nrs, num)
foreign delCols(ncs, num)
foreign copy(names)
foreign erase()
foreign delete()

foreign probName
foreign objName
foreign objDir
foreign numRows
foreign numCols
foreign rowName(i)
foreign colName(j)
foreign rowType(i)
foreign rowLB(i)
foreign rowUB(i)
foreign colType(j)
foreign colLB(j)
foreign colUB(j)
foreign objCoef(j)
foreign numNZ
foreign matRow(i, ind, val)
foreign matCol(j, ind, val)

foreign createIndex()
foreign findRow(name)
foreign findCol(name)
foreign deleteIndex()

foreign setRii(i, rii)
foreign setSjj(j, sjj)
foreign rii(i)
foreign sjj(j)
foreign scale(flags)
foreign unscale()

foreign setRowStat(i, stat)
foreign setColStat(j, stat)
foreign stdBasis()
foreign cpxBasis()

foreign simplex(parm)
foreign exact(parm)
foreign status
foreign primStat
foreign dualStat
foreign objVal
foreign rowStat(i)
foreign rowPrim(i)
foreign rowDual(i)
foreign colStat(j)
foreign colPrim(j)
foreign colDual(j)
foreign unbndRay

foreign interior(parm)
foreign iptStatus
foreign iptObjVal
foreign iptRowPrim(i)
foreign iptRowDual(i)
foreign iptColPrim(j)
foreign iptColDual(j)

foreign setColKind(j, kind)
foreign colKind(j)
foreign numInt
foreign numBin
foreign intOpt(parm)
foreign mipStatus
foreign mipObjVal
foreign mipRowVal(i)
foreign mipColVal(j)

foreign checkKKT(sol, cond, aeMax, aeInd, reMax, reInd)

foreign writeMPS(format, fname)
foreign writeLP(fname)
foreign writeProb(fname)

foreign printSol(fname)
foreign writeSol(fname)
foreign printIpt(fname)
foreign writeIpt(fname)
foreign printMip(fname)
foreign writeMip(fname)

foreign printRanges(len, list, fname)
}

/* Smcp represents simplex solver control parameters. */
foreign class Smcp {
construct init() {}

foreign meth
foreign msgLev
foreign pricing
foreign rTest

foreign meth=(m)
foreign msgLev=(l)
foreign pricing=(p)
foreign rTest=(r)
}

/* Iptcp represents interior-point solver control parameters. */
foreign class Iptcp {
construct init() {}

foreign msgLev
foreign ordAlg

foreign msgLev=(l)
foreign ordAlg=(o)
}

/* Iocp represents MIP solver control parameters. */
foreign class Iocp {
construct init() {}

foreign msgLev
foreign brTech
foreign btTech
foreign ppTech
foreign presolve

foreign msgLev=(l)
foreign brTech=(b)
foreign btTech=(b)
foreign ppTech=(p)
foreign presolve=(b)
}

/* Tran contains routines for processing MathProg models. */
foreign class Tran {
construct mplAllocWksp() {}

foreign mplInitRand(seed)
foreign mplGenerate(fname)
foreign mplBuildProb(p)
foreign mplPostSolve(p, sol)
foreign mplFreeWksp()
}
/* File contains routines for writing text to a
temporary file and removing it when no longer needed. */
class File {
foreign static write(fname, text)
foreign static remove(fname)
}
```

## Source code (C)

```/* gcc -O3 wren-linear.c -o wren-linear -lglpk -lwren -lm  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glpk.h>
#include "wren.h"

/* Glp functions */
void Glp_checkDup(WrenVM* vm) {
int m = (int)wrenGetSlotDouble(vm, 1);
int n = (int)wrenGetSlotDouble(vm, 2);
int ne = (int)wrenGetSlotDouble(vm, 3);
int ia[ne+1];
int ja[ne+1];
for (int ix = 0; ix < ne; ++ix) {
wrenGetListElement(vm, 4, ix, 1);
ia[ix+1] = (int)wrenGetSlotDouble(vm, 1);
wrenGetListElement(vm, 5, ix, 1);
ja[ix+1] = (int)wrenGetSlotDouble(vm, 1);
}
int res = glp_check_dup(m, n, ne, ia, ja);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Glp_initEnv(WrenVM* vm) {
int res = glp_init_env();
wrenSetSlotDouble(vm, 0, (double)res);
}

void Glp_version(WrenVM* vm) {
const char *res = glp_version();
wrenSetSlotString(vm, 0, res);
}

void Glp_freeEnv(WrenVM* vm) {
int res = glp_free_env();
wrenSetSlotDouble(vm, 0, (double)res);
}

void Glp_termOut(WrenVM* vm) {
int flag = (int)wrenGetSlotDouble(vm, 1);
int res = glp_term_out(flag);
wrenSetSlotDouble(vm, 0, (double)res);
}

/* Prob functions */
void Prob_allocate(WrenVM* vm) {
glp_prob **ppprob = (glp_prob**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(glp_prob*));
*ppprob = glp_create_prob();
}

void Prob_setProbName(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *name = wrenGetSlotString(vm, 1);
glp_set_prob_name(pprob, name);
}

void Prob_setObjName(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *name = wrenGetSlotString(vm, 1);
glp_set_obj_name(pprob, name);
}

void Prob_setObjDir(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int dir = (int)wrenGetSlotDouble(vm, 1);
glp_set_obj_dir(pprob, dir);
}

glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int nrs = (int)wrenGetSlotDouble(vm, 1);
wrenSetSlotDouble(vm, 0, (double)res);
}

glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int ncs = (int)wrenGetSlotDouble(vm, 1);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_setRowName(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
const char *name = wrenGetSlotString(vm, 2);
glp_set_row_name(pprob, i, name);
}

void Prob_setColName(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
const char *name = wrenGetSlotString(vm, 2);
glp_set_col_name(pprob, j, name);
}

void Prob_setRowBnds(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
int type = (int)wrenGetSlotDouble(vm, 2);
double lb = wrenGetSlotDouble(vm, 3);
double ub = wrenGetSlotDouble(vm, 4);
glp_set_row_bnds(pprob, i, type, lb, ub);
}

void Prob_setColBnds(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
int type = (int)wrenGetSlotDouble(vm, 2);
double lb = wrenGetSlotDouble(vm, 3);
double ub = wrenGetSlotDouble(vm, 4);
glp_set_col_bnds(pprob, j, type, lb, ub);
}

void Prob_setObjCoef(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double coef = wrenGetSlotDouble(vm, 2);
glp_set_obj_coef(pprob, j, coef);
}

void Prob_setMatRow(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
int len = (int)wrenGetSlotDouble(vm, 2);
if (!len) {
glp_set_mat_row(pprob, i, 0, NULL, NULL);
return;
}
int ind[len+1];
double val[len+1];
for (int ix = 0; ix < len; ++ix) {
wrenGetListElement(vm, 3, ix, 1);
ind[ix+1] = (int)wrenGetSlotDouble(vm, 1);
wrenGetListElement(vm, 4, ix, 2);
val[ix+1] = wrenGetSlotDouble(vm, 2);
}
glp_set_mat_row(pprob, i, len, ind, val);
}

void Prob_setMatCol(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
int len = (int)wrenGetSlotDouble(vm, 2);
if (!len) {
glp_set_mat_col(pprob, j, 0, NULL, NULL);
return;
}
int ind[len+1];
double val[len+1];
for (int ix = 0; ix < len; ++ix) {
wrenGetListElement(vm, 3, ix, 1);
ind[ix+1] = (int)wrenGetSlotDouble(vm, 1);
wrenGetListElement(vm, 4, ix, 2);
val[ix+1] = wrenGetSlotDouble(vm, 2);
}
glp_set_mat_col(pprob, j, len, ind, val);
}

glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int ne = (int)wrenGetSlotDouble(vm, 1);
if (!ne) {
return;
}
int ia[ne+1];
int ja[ne+1];
double ar[ne+1];
for (int ix = 0; ix < ne; ++ix) {
wrenGetListElement(vm, 2, ix, 1);
ia[ix+1] = (int)wrenGetSlotDouble(vm, 1);
wrenGetListElement(vm, 3, ix, 1);
ja[ix+1] = (int)wrenGetSlotDouble(vm, 1);
wrenGetListElement(vm, 4, ix, 1);
ar[ix+1] = wrenGetSlotDouble(vm, 1);
}
}

void Prob_sortMatrix(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
glp_sort_matrix(pprob);
}

void Prob_delRows(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int nrs = (int)wrenGetSlotDouble(vm, 1);
int num[nrs+1];
for (int ix = 0; ix < nrs; ++ix) {
wrenGetListElement(vm, 2, ix, 1);
num[ix+1] = (int)wrenGetSlotDouble(vm, 1);
}
glp_del_rows(pprob, nrs, num);
}

void Prob_delCols(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int ncs = (int)wrenGetSlotDouble(vm, 1);
int num[ncs+1];
for (int ix = 0; ix < ncs; ++ix) {
wrenGetListElement(vm, 2, ix, 1);
num[ix+1] = (int)wrenGetSlotDouble(vm, 1);
}
glp_del_cols(pprob, ncs, num);
}

void Prob_copy(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int names = (int)wrenGetSlotDouble(vm, 1);
glp_prob **ppdest = (glp_prob**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(glp_prob*));
glp_copy_prob(*ppdest, pprob, names);
}

void Prob_erase(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
glp_erase_prob(pprob);
}

void Prob_delete(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
glp_delete_prob(pprob);
}

void Prob_probName(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *res = glp_get_prob_name(pprob);
wrenSetSlotString(vm, 0, res);
}

void Prob_objName(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *res = glp_get_obj_name(pprob);
wrenSetSlotString(vm, 0, res);
}

void Prob_objDir(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_get_obj_dir(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_numRows(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_get_num_rows(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_numCols(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_get_num_cols(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_rowName(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
const char *res = glp_get_row_name(pprob, i);
wrenSetSlotString(vm, 0, res);
}

void Prob_colName(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
const char *res = glp_get_col_name(pprob, j);
wrenSetSlotString(vm, 0, res);
}

void Prob_rowType(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
int res = glp_get_row_type(pprob, i);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_rowLB(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_row_lb(pprob, i);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_rowUB(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_row_ub(pprob, i);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_colType(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
int res = glp_get_col_type(pprob, j);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_colLB(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_col_lb(pprob, j);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_colUB(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_col_ub(pprob, j);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_objCoef(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_obj_coef(pprob, j);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_numNZ(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_get_num_nz(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_matRow(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
int len = wrenGetListCount(vm, 2);
int ind[len+1];
double val[len+1];
int rlen = glp_get_mat_row(pprob, i, ind, val);
for (int ix = 0; ix < rlen; ++ix) {
wrenSetSlotDouble(vm, 1, (double)ind[ix+1]);
wrenSetListElement(vm, 2, ix, 1);
wrenSetSlotDouble(vm, 1, val[ix+1]);
wrenSetListElement(vm, 3, ix, 1);
}
}

void Prob_matCol(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
int len = wrenGetListCount(vm, 2);
int ind[len+1];
double val[len+1];
int rlen = glp_get_mat_col(pprob, j, ind, val);
for (int ix = 0; ix < rlen; ++ix) {
wrenSetSlotDouble(vm, 1, (double)ind[ix+1]);
wrenSetListElement(vm, 2, ix, 1);
wrenSetSlotDouble(vm, 1, val[ix+1]);
wrenSetListElement(vm, 3, ix, 1);
}
}

void Prob_createIndex(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
glp_create_index(pprob);
}

void Prob_findRow(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *name = wrenGetSlotString(vm, 1);
int res = glp_find_row(pprob, name);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_findCol(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *name = wrenGetSlotString(vm, 1);
int res = glp_find_col(pprob, name);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_deleteIndex(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
glp_delete_index(pprob);
}

void Prob_setRii(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
double rii = wrenGetSlotDouble(vm, 2);
glp_set_rii(pprob, i, rii);
}

void Prob_setSjj(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double sjj = wrenGetSlotDouble(vm, 2);
glp_set_sjj(pprob, j, sjj);
}

void Prob_rii(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_rii(pprob, i);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_sjj(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_sjj(pprob, j);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_scale(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int flags = (int)wrenGetSlotDouble(vm, 1);
glp_scale_prob(pprob, flags);
}

void Prob_unscale(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
glp_unscale_prob(pprob);
}

void Prob_setRowStat(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
int stat = (int)wrenGetSlotDouble(vm, 2);
glp_set_row_stat(pprob, i, stat);
}

void Prob_setColStat(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
int stat = (int)wrenGetSlotDouble(vm, 2);
glp_set_col_stat(pprob, j, stat);
}

void Prob_stdBasis(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
glp_std_basis(pprob);
}

glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
}

void Prob_cpxBasis(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
glp_cpx_basis(pprob);
}

void Prob_simplex(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res;
if (wrenGetSlotType(vm, 1) == WREN_TYPE_NULL) {
res = glp_simplex(pprob, NULL);
} else {
const glp_smcp *parm = (const glp_smcp*)wrenGetSlotForeign(vm, 1);
res = glp_simplex(pprob, parm);
}
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_exact(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const glp_smcp *parm = (const glp_smcp*)wrenGetSlotForeign(vm, 1);
int res = glp_exact(pprob, parm);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_status(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_get_status(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_primStat(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_get_prim_stat(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_dualStat(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_get_dual_stat(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_objVal(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
double res = glp_get_obj_val(pprob);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_rowStat(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
int res = glp_get_row_stat(pprob, i);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_rowPrim(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_row_prim(pprob, i);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_rowDual(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_row_dual(pprob, i);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_colStat(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
int res = glp_get_col_stat(pprob, j);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_colPrim(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_col_prim(pprob, j);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_colDual(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double res = glp_get_col_dual(pprob, j);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_unbndRay(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_get_unbnd_ray(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_interior(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res;
if (wrenGetSlotType(vm, 1) == WREN_TYPE_NULL) {
res = glp_interior(pprob, NULL);
} else {
const glp_iptcp *parm = (const glp_iptcp*)wrenGetSlotForeign(vm, 1);
res = glp_interior(pprob, parm);
}
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_iptStatus(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_ipt_status(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_iptObjVal(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
double res = glp_ipt_obj_val(pprob);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_iptRowPrim(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
double res = glp_ipt_row_prim(pprob, i);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_iptRowDual(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
double res = glp_ipt_row_dual(pprob, i);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_iptColPrim(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double res = glp_ipt_col_prim(pprob, j);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_iptColDual(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double res = glp_ipt_col_dual(pprob, j);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_setColKind(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
int kind = (int)wrenGetSlotDouble(vm, 2);
glp_set_col_kind(pprob, j, kind);
}

void Prob_colKind(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
int res = glp_get_col_kind(pprob, j);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_numInt(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_get_num_int(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_numBin(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_get_num_bin(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_intOpt(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res;
if (wrenGetSlotType(vm, 1) == WREN_TYPE_NULL) {
res = glp_intopt(pprob, NULL);
} else {
const glp_iocp *parm = (const glp_iocp*)wrenGetSlotForeign(vm, 1);
res = glp_intopt(pprob, parm);
}
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_mipStatus(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int res = glp_mip_status(pprob);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_mipObjVal(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
double res = glp_mip_obj_val(pprob);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_mipRowVal(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int i = (int)wrenGetSlotDouble(vm, 1);
double res = glp_mip_row_val(pprob, i);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_mipColVal(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int j = (int)wrenGetSlotDouble(vm, 1);
double res = glp_mip_col_val(pprob, j);
wrenSetSlotDouble(vm, 0, res);
}

void Prob_checkKKT(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int sol = (int)wrenGetSlotDouble(vm, 1);
int cond = (int)wrenGetSlotDouble(vm, 2);
int ae_ind, re_ind;
double ae_max, re_max;
glp_check_kkt(pprob, sol, cond, &ae_max, &ae_ind, &re_max, &re_ind);
wrenSetSlotDouble(vm, 1, ae_max);
wrenSetListElement(vm, 3, 0, 1);
wrenSetSlotDouble(vm, 1, (double)ae_ind);
wrenSetListElement(vm, 4, 0, 1);
wrenSetSlotDouble(vm, 1, re_max);
wrenSetListElement(vm, 5, 0, 1);
wrenSetSlotDouble(vm, 1, (double)re_ind);
wrenSetListElement(vm, 6, 0, 1);
}

glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int format = (int)wrenGetSlotDouble(vm, 1);
const char *fname = wrenGetSlotString(vm, 2);
int res = glp_read_mps(pprob, format, NULL, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_writeMPS(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int format = (int)wrenGetSlotDouble(vm, 1);
const char *fname = wrenGetSlotString(vm, 2);
int res = glp_write_mps(pprob, format, NULL, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int res = glp_read_lp(pprob, NULL, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_writeLP(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int res = glp_write_lp(pprob, NULL, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int res = glp_read_prob(pprob, 0, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_writeProb(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int res = glp_write_prob(pprob, 0, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_printSol(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int res = glp_print_sol(pprob, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_writeSol(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int res = glp_write_sol(pprob, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_printIpt(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int res = glp_print_ipt(pprob, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_writeIpt(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int res = glp_write_ipt(pprob, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_printMip(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int res = glp_print_mip(pprob, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_writeMip(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int res = glp_write_mip(pprob, fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Prob_printRanges(WrenVM* vm) {
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 0);
int len = (int)wrenGetSlotDouble(vm, 1);
const char *fname = wrenGetSlotString(vm, 3);
int res;
if (!len) {
glp_print_ranges(pprob, 0, NULL, 0, fname);
} else {
int list[len+1];
for (int ix = 0; ix < len; ++ix) {
wrenGetListElement(vm, 2, ix, 1);
list[ix+1] = (int)wrenGetSlotDouble(vm, 1);
}
res = glp_print_ranges(pprob, len, list, 0, fname);
}
wrenSetSlotDouble(vm, 0, (double)res);
}

/* Smcp functions */
void Smcp_allocate(WrenVM* vm) {
glp_smcp *psmcp = (glp_smcp*)wrenSetSlotNewForeign(vm, 0, 0, sizeof(glp_smcp));
glp_init_smcp(psmcp);
}

void Smcp_meth(WrenVM* vm) {
glp_smcp *psmcp = (glp_smcp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)psmcp->meth);
}

void Smcp_msgLev(WrenVM* vm) {
glp_smcp *psmcp = (glp_smcp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)psmcp->msg_lev);
}

void Smcp_pricing(WrenVM* vm) {
glp_smcp *psmcp = (glp_smcp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)psmcp->pricing);
}

void Smcp_rTest(WrenVM* vm) {
glp_smcp *psmcp = (glp_smcp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)psmcp->r_test);
}

void Smcp_setMeth(WrenVM* vm) {
glp_smcp *psmcp = (glp_smcp*)wrenGetSlotForeign(vm, 0);
int meth = (int)wrenGetSlotDouble(vm, 1);
psmcp->meth = meth;
}

void Smcp_setMsgLev(WrenVM* vm) {
glp_smcp *psmcp = (glp_smcp*)wrenGetSlotForeign(vm, 0);
int msg_lev = (int)wrenGetSlotDouble(vm, 1);
psmcp->msg_lev = msg_lev;
}

void Smcp_setPricing(WrenVM* vm) {
glp_smcp *psmcp = (glp_smcp*)wrenGetSlotForeign(vm, 0);
int pricing = (int)wrenGetSlotDouble(vm, 1);
psmcp->pricing = pricing;
}

void Smcp_setRTest(WrenVM* vm) {
glp_smcp *psmcp = (glp_smcp*)wrenGetSlotForeign(vm, 0);
int r_test = (int)wrenGetSlotDouble(vm, 1);
psmcp->r_test = r_test;
}

/* Iptcp functions */
void Iptcp_allocate(WrenVM* vm) {
glp_iptcp *piptcp = (glp_iptcp*)wrenSetSlotNewForeign(vm, 0, 0, sizeof(glp_iptcp));
glp_init_iptcp(piptcp);
}

void Iptcp_msgLev(WrenVM* vm) {
glp_iptcp *piptcp = (glp_iptcp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)piptcp->msg_lev);
}

void Iptcp_ordAlg(WrenVM* vm) {
glp_iptcp *piptcp = (glp_iptcp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)piptcp->ord_alg);
}

void Iptcp_setMsgLev(WrenVM* vm) {
glp_iptcp *piptcp = (glp_iptcp*)wrenGetSlotForeign(vm, 0);
int msg_lev = (int)wrenGetSlotDouble(vm, 1);
piptcp->msg_lev = msg_lev;
}

void Iptcp_setOrdAlg(WrenVM* vm) {
glp_iptcp *piptcp = (glp_iptcp*)wrenGetSlotForeign(vm, 0);
int ord_alg = (int)wrenGetSlotDouble(vm, 1);
piptcp->ord_alg = ord_alg;
}

/* Iocp functions */
void Iocp_allocate(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenSetSlotNewForeign(vm, 0, 0, sizeof(glp_iocp));
glp_init_iocp(piocp);
}

void Iocp_msgLev(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)piocp->msg_lev);
}

void Iocp_brTech(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)piocp->br_tech);
}

void Iocp_btTech(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)piocp->bt_tech);
}

void Iocp_ppTech(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)piocp->pp_tech);
}

void Iocp_presolve(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenGetSlotForeign(vm, 0);
wrenSetSlotBool(vm, 0, piocp->presolve);
}

void Iocp_setMsgLev(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenGetSlotForeign(vm, 0);
int msg_lev = (int)wrenGetSlotDouble(vm, 1);
piocp->msg_lev = msg_lev;
}

void Iocp_setBrTech(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenGetSlotForeign(vm, 0);
int br_tech = (int)wrenGetSlotDouble(vm, 1);
piocp->br_tech = br_tech;
}

void Iocp_setBtTech(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenGetSlotForeign(vm, 0);
int bt_tech = (int)wrenGetSlotDouble(vm, 1);
piocp->bt_tech = bt_tech;
}

void Iocp_setPpTech(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenGetSlotForeign(vm, 0);
int pp_tech = (int)wrenGetSlotDouble(vm, 1);
piocp->pp_tech = pp_tech;
}

void Iocp_setPresolve(WrenVM* vm) {
glp_iocp *piocp = (glp_iocp*)wrenGetSlotForeign(vm, 0);
bool presolve = wrenGetSlotBool(vm, 1);
piocp->presolve = presolve;
}

/* Tran functions */
void Tran_allocate(WrenVM* vm) {
glp_tran **pptran = (glp_tran**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(glp_tran*));
*pptran = glp_mpl_alloc_wksp();
}

void Tran_mplInitRand(WrenVM* vm) {
glp_tran *ptran = *(glp_tran**)wrenGetSlotForeign(vm, 0);
int seed = (int)wrenGetSlotDouble(vm, 1);
glp_mpl_init_rand(ptran, seed);
}

glp_tran *ptran = *(glp_tran**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
int skip = (int)wrenGetSlotDouble(vm, 2);
int res = glp_mpl_read_model(ptran, fname, skip);
wrenSetSlotDouble(vm, 0, (double)res);
}

glp_tran *ptran = *(glp_tran**)wrenGetSlotForeign(vm, 0);
const char *fname = wrenGetSlotString(vm, 1);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Tran_mplGenerate(WrenVM* vm) {
glp_tran *ptran = *(glp_tran**)wrenGetSlotForeign(vm, 0);
int res;
if (wrenGetSlotType(vm, 1) == WREN_TYPE_NULL) {
res = glp_mpl_generate(ptran, NULL);
} else {
const char *fname = wrenGetSlotString(vm, 1);
res = glp_mpl_generate(ptran, fname);
}
wrenSetSlotDouble(vm, 0, (double)res);
}

void Tran_mplBuildProb(WrenVM* vm) {
glp_tran *ptran = *(glp_tran**)wrenGetSlotForeign(vm, 0);
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 1);
glp_mpl_build_prob(ptran, pprob);
}

void Tran_mplPostSolve(WrenVM* vm) {
glp_tran *ptran = *(glp_tran**)wrenGetSlotForeign(vm, 0);
glp_prob *pprob = *(glp_prob**)wrenGetSlotForeign(vm, 1);
int sol = (int)wrenGetSlotDouble(vm, 2);
int res = glp_mpl_postsolve(ptran, pprob, sol);
wrenSetSlotDouble(vm, 0, (double)res);
}

void Tran_mplFreeWksp(WrenVM* vm) {
glp_tran *ptran = *(glp_tran**)wrenGetSlotForeign(vm, 0);
glp_mpl_free_wksp(ptran);
}

/* File functions */

void File_write(WrenVM* vm) {
const char *fname = wrenGetSlotString(vm, 1);
const char *text = wrenGetSlotString(vm, 2);
FILE *fp = fopen(fname, "w+");
fputs(text, fp);
fclose(fp);
}

void File_remove(WrenVM* vm) {
const char *fname = wrenGetSlotString(vm, 1);
int res = remove(fname);
wrenSetSlotDouble(vm, 0, (double)res);
}

WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.allocate = NULL;
methods.finalize = NULL;
if (strcmp(module, "./linear") == 0) {
if (strcmp(className, "Prob") == 0) {
methods.allocate = Prob_allocate;
} else if (strcmp(className, "Smcp") == 0) {
methods.allocate = Smcp_allocate;
} else if (strcmp(className, "Iptcp") == 0) {
methods.allocate = Iptcp_allocate;
} else if (strcmp(className, "Iocp") == 0) {
methods.allocate = Iocp_allocate;
} else if (strcmp(className, "Tran") == 0) {
methods.allocate = Tran_allocate;
}
}
return methods;
}

WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "./linear") == 0) {
if (strcmp(className, "Glp") == 0) {
if(isStatic && strcmp(signature, "checkDup(_,_,_,_,_)") == 0) return Glp_checkDup;
if(isStatic && strcmp(signature, "initEnv()") == 0)           return Glp_initEnv;
if(isStatic && strcmp(signature, "version") == 0)             return Glp_version;
if(isStatic && strcmp(signature, "freeEnv()") == 0)           return Glp_freeEnv;
if(isStatic && strcmp(signature, "termOut(_)") == 0)          return Glp_termOut;
} else if (strcmp(className, "Prob") == 0) {
if(!isStatic && strcmp(signature, "setProbName(_)") == 0)      return Prob_setProbName;
if(!isStatic && strcmp(signature, "setObjName(_)") == 0)       return Prob_setObjName;
if(!isStatic && strcmp(signature, "setObjDir(_)") == 0)        return Prob_setObjDir;
if(!isStatic && strcmp(signature, "setRowName(_,_)") == 0)     return Prob_setRowName;
if(!isStatic && strcmp(signature, "setColName(_,_)") == 0)     return Prob_setColName;
if(!isStatic && strcmp(signature, "setRowBnds(_,_,_,_)") == 0) return Prob_setRowBnds;
if(!isStatic && strcmp(signature, "setColBnds(_,_,_,_)") == 0) return Prob_setColBnds;
if(!isStatic && strcmp(signature, "setObjCoef(_,_)") == 0)     return Prob_setObjCoef;
if(!isStatic && strcmp(signature, "setMatRow(_,_,_,_)") == 0)  return Prob_setMatRow;
if(!isStatic && strcmp(signature, "setMatCol(_,_,_,_)") == 0)  return Prob_setMatCol;
if(!isStatic && strcmp(signature, "sortMatrix()") == 0)        return Prob_sortMatrix;
if(!isStatic && strcmp(signature, "delRows(_,_)") == 0)        return Prob_delRows;
if(!isStatic && strcmp(signature, "delCols(_,_)") == 0)        return Prob_delCols;
if(!isStatic && strcmp(signature, "copy(_)") == 0)             return Prob_copy;
if(!isStatic && strcmp(signature, "erase()") == 0)             return Prob_erase;
if(!isStatic && strcmp(signature, "delete()") == 0)            return Prob_delete;

if(!isStatic && strcmp(signature, "probName") == 0)      return Prob_probName;
if(!isStatic && strcmp(signature, "objName") == 0)       return Prob_objName;
if(!isStatic && strcmp(signature, "objDir") == 0)        return Prob_objDir;
if(!isStatic && strcmp(signature, "numRows") == 0)       return Prob_numRows;
if(!isStatic && strcmp(signature, "numCols") == 0)       return Prob_numCols;
if(!isStatic && strcmp(signature, "rowName(_)") == 0)    return Prob_rowName;
if(!isStatic && strcmp(signature, "colName(_)") == 0)    return Prob_colName;
if(!isStatic && strcmp(signature, "rowType(_)") == 0)    return Prob_rowType;
if(!isStatic && strcmp(signature, "rowLB(_)") == 0)      return Prob_rowLB;
if(!isStatic && strcmp(signature, "rowUB(_)") == 0)      return Prob_rowUB;
if(!isStatic && strcmp(signature, "colType(_)") == 0)    return Prob_colType;
if(!isStatic && strcmp(signature, "colLB(_)") == 0)      return Prob_colLB;
if(!isStatic && strcmp(signature, "colUB(_)") == 0)      return Prob_colUB;
if(!isStatic && strcmp(signature, "objCoef(_)") == 0)    return Prob_objCoef;
if(!isStatic && strcmp(signature, "numNZ") == 0)         return Prob_numNZ;
if(!isStatic && strcmp(signature, "matRow(_,_,_)") == 0) return Prob_matRow;
if(!isStatic && strcmp(signature, "matCol(_,_,_)") == 0) return Prob_matCol;

if(!isStatic && strcmp(signature, "createIndex()") == 0) return Prob_createIndex;
if(!isStatic && strcmp(signature, "findRow(_)") == 0)    return Prob_findRow;
if(!isStatic && strcmp(signature, "findCol(_)") == 0)    return Prob_findCol;
if(!isStatic && strcmp(signature, "deleteIndex()") == 0) return Prob_deleteIndex;

if(!isStatic && strcmp(signature, "setRii(_,_)") == 0)   return Prob_setRii;
if(!isStatic && strcmp(signature, "setSjj(_,_)") == 0)   return Prob_setSjj;
if(!isStatic && strcmp(signature, "rii(_)") == 0)        return Prob_rii;
if(!isStatic && strcmp(signature, "sjj(_)") == 0)        return Prob_sjj;
if(!isStatic && strcmp(signature, "scale(_)") == 0)      return Prob_scale;
if(!isStatic && strcmp(signature, "unscale()") == 0)     return Prob_unscale;

if(!isStatic && strcmp(signature, "setRowStat(_,_)") == 0) return Prob_setRowStat;
if(!isStatic && strcmp(signature, "setColStat(_,_)") == 0) return Prob_setColStat;
if(!isStatic && strcmp(signature, "stdBasis()") == 0)      return Prob_stdBasis;
if(!isStatic && strcmp(signature, "cpxBasis()") == 0)      return Prob_cpxBasis;

if(!isStatic && strcmp(signature, "simplex(_)") == 0) return Prob_simplex;
if(!isStatic && strcmp(signature, "exact(_)") == 0)   return Prob_exact;
if(!isStatic && strcmp(signature, "status") == 0)     return Prob_status;
if(!isStatic && strcmp(signature, "primStat") == 0)   return Prob_primStat;
if(!isStatic && strcmp(signature, "dualStat") == 0)   return Prob_dualStat;
if(!isStatic && strcmp(signature, "objVal") == 0)     return Prob_objVal;
if(!isStatic && strcmp(signature, "rowStat(_)") == 0) return Prob_rowStat;
if(!isStatic && strcmp(signature, "rowPrim(_)") == 0) return Prob_rowPrim;
if(!isStatic && strcmp(signature, "rowDual(_)") == 0) return Prob_rowDual;
if(!isStatic && strcmp(signature, "colStat(_)") == 0) return Prob_colStat;
if(!isStatic && strcmp(signature, "colPrim(_)") == 0) return Prob_colPrim;
if(!isStatic && strcmp(signature, "colDual(_)") == 0) return Prob_colDual;
if(!isStatic && strcmp(signature, "unbndRay") == 0)   return Prob_unbndRay;

if(!isStatic && strcmp(signature, "interior(_)") == 0)   return Prob_interior;
if(!isStatic && strcmp(signature, "iptStatus") == 0)     return Prob_iptStatus;
if(!isStatic && strcmp(signature, "iptObjVal") == 0)     return Prob_iptObjVal;
if(!isStatic && strcmp(signature, "iptRowPrim(_)") == 0) return Prob_iptRowPrim;
if(!isStatic && strcmp(signature, "iptRowDual(_)") == 0) return Prob_iptRowDual;
if(!isStatic && strcmp(signature, "iptColPrim(_)") == 0) return Prob_iptColPrim;
if(!isStatic && strcmp(signature, "iptColDual(_)") == 0) return Prob_iptColDual;

if(!isStatic && strcmp(signature, "setColKind(_,_)") == 0) return Prob_setColKind;
if(!isStatic && strcmp(signature, "colKind(_)") == 0)      return Prob_colKind;
if(!isStatic && strcmp(signature, "numInt") == 0)          return Prob_numInt;
if(!isStatic && strcmp(signature, "numBin") == 0)          return Prob_numBin;
if(!isStatic && strcmp(signature, "intOpt(_)") == 0)       return Prob_intOpt;
if(!isStatic && strcmp(signature, "mipStatus") == 0)       return Prob_mipStatus;
if(!isStatic && strcmp(signature, "mipObjVal") == 0)       return Prob_mipObjVal;
if(!isStatic && strcmp(signature, "mipRowVal(_)") == 0)    return Prob_mipRowVal;
if(!isStatic && strcmp(signature, "mipColVal(_)") == 0)    return Prob_mipColVal;

if(!isStatic && strcmp(signature, "checkKKT(_,_,_,_,_,_)") == 0)  return Prob_checkKKT;

if(!isStatic && strcmp(signature, "writeMPS(_,_)") == 0) return Prob_writeMPS;
if(!isStatic && strcmp(signature, "writeLP(_)") == 0)    return Prob_writeLP;
if(!isStatic && strcmp(signature, "writeProb(_)") == 0)  return Prob_writeProb;

if(!isStatic && strcmp(signature, "printSol(_)") == 0) return Prob_printSol;
if(!isStatic && strcmp(signature, "writeSol(_)") == 0) return Prob_writeSol;
if(!isStatic && strcmp(signature, "printIpt(_)") == 0) return Prob_printIpt;
if(!isStatic && strcmp(signature, "writeIpt(_)") == 0) return Prob_writeIpt;
if(!isStatic && strcmp(signature, "printMip(_)") == 0) return Prob_printMip;
if(!isStatic && strcmp(signature, "writeMip(_)") == 0) return Prob_writeMip;

if(!isStatic && strcmp(signature, "printRanges(_,_,_)") == 0) return Prob_printRanges;
} else if (strcmp(className, "Smcp") == 0) {
if(!isStatic && strcmp(signature, "meth") == 0)        return Smcp_meth;
if(!isStatic && strcmp(signature, "msgLev") == 0)      return Smcp_msgLev;
if(!isStatic && strcmp(signature, "pricing") == 0)     return Smcp_pricing;
if(!isStatic && strcmp(signature, "rTest") == 0)       return Smcp_rTest;
if(!isStatic && strcmp(signature, "meth=(_)") == 0)    return Smcp_setMeth;
if(!isStatic && strcmp(signature, "msgLev=(_)") == 0)  return Smcp_setMsgLev;
if(!isStatic && strcmp(signature, "pricing=(_)") == 0) return Smcp_setPricing;
if(!isStatic && strcmp(signature, "rTest=(_)") == 0)   return Smcp_setRTest;
} else if (strcmp(className, "Iptcp") == 0) {
if(!isStatic && strcmp(signature, "msgLev") == 0)      return Iptcp_msgLev;
if(!isStatic && strcmp(signature, "ordAlg") == 0)      return Iptcp_ordAlg;
if(!isStatic && strcmp(signature, "msgLev=(_)") == 0)  return Iptcp_setMsgLev;
if(!isStatic && strcmp(signature, "ordAlg=(_)") == 0)  return Iptcp_setOrdAlg;
} else if (strcmp(className, "Iocp") == 0) {
if(!isStatic && strcmp(signature, "msgLev") == 0)       return Iocp_msgLev;
if(!isStatic && strcmp(signature, "brTech") == 0)       return Iocp_brTech;
if(!isStatic && strcmp(signature, "btTech") == 0)       return Iocp_btTech;
if(!isStatic && strcmp(signature, "ppTech") == 0)       return Iocp_ppTech;
if(!isStatic && strcmp(signature, "presolve") == 0)     return Iocp_presolve;
if(!isStatic && strcmp(signature, "msgLev=(_)") == 0)   return Iocp_setMsgLev;
if(!isStatic && strcmp(signature, "brTech=(_)") == 0)   return Iocp_setBrTech;
if(!isStatic && strcmp(signature, "btTech=(_)") == 0)   return Iocp_setBtTech;
if(!isStatic && strcmp(signature, "ppTech=(_)") == 0)   return Iocp_setPpTech;
if(!isStatic && strcmp(signature, "presolve=(_)") == 0) return Iocp_setPresolve;
} else if (strcmp(className, "Tran") == 0) {
if(!isStatic && strcmp(signature, "mplInitRand(_)") == 0)    return Tran_mplInitRand;
if(!isStatic && strcmp(signature, "mplGenerate(_)") == 0)    return Tran_mplGenerate;
if(!isStatic && strcmp(signature, "mplBuildProb(_)") == 0)   return Tran_mplBuildProb;
if(!isStatic && strcmp(signature, "mplPostSolve(_,_)") == 0) return Tran_mplPostSolve;
if(!isStatic && strcmp(signature, "mplFreeWksp()") == 0)     return Tran_mplFreeWksp;
} else if (strcmp(className, "File") == 0) {
if(isStatic && strcmp(signature, "write(_,_)") == 0) return File_write;
if(isStatic && strcmp(signature, "remove(_)") == 0)  return File_remove;
}
}
return NULL;
}

static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}

FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
size_t ret = fread(script, 1, fsize, f);
if (ret != fsize) printf("Error reading %s\n", fileName);
fclose(f);
script[fsize] = 0;
return script;
}

if( result.source) free((void*)result.source);
}

if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
char fullName[strlen(name) + 6];
strcpy(fullName, name);
strcat(fullName, ".wren");
}
return result;
}

int main(int argc, char **argv) {
if (argc != 2) {
printf("Please pass the name of the Wren file to be executed.\n");
return 1;
}
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignClassFn = &bindForeignClass;
config.bindForeignMethodFn = &bindForeignMethod;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = argv[1];
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}
```