naev 0.12.5
nlua_linopt.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
4
10
12#include "SDL_timer.h"
13#include "physfs.h"
14#include <glpk.h>
15#include <lauxlib.h>
16
17#include "naev.h"
19
20#include "nlua_linopt.h"
21
22#include "log.h"
23#include "nluadef.h"
24
25#define LINOPT_MAX_TM \
26 1000
27
28
32typedef struct LuaLinOpt_s {
33 int ncols;
34 int nrows;
35 glp_prob *prob;
37
38/* Optim metatable methods. */
39static int linoptL_gc( lua_State *L );
40static int linoptL_eq( lua_State *L );
41static int linoptL_new( lua_State *L );
42static int linoptL_size( lua_State *L );
43static int linoptL_addcols( lua_State *L );
44static int linoptL_addrows( lua_State *L );
45static int linoptL_setcol( lua_State *L );
46static int linoptL_setrow( lua_State *L );
47static int linoptL_loadmatrix( lua_State *L );
48static int linoptL_solve( lua_State *L );
49static int linoptL_readProblem( lua_State *L );
50static int linoptL_writeProblem( lua_State *L );
51
52static const luaL_Reg linoptL_methods[] = {
53 { "__gc", linoptL_gc },
54 { "__eq", linoptL_eq },
55 { "new", linoptL_new },
56 { "size", linoptL_size },
57 { "add_cols", linoptL_addcols },
58 { "add_rows", linoptL_addrows },
59 { "set_col", linoptL_setcol },
60 { "set_row", linoptL_setrow },
61 { "load_matrix", linoptL_loadmatrix },
62 { "solve", linoptL_solve },
63 { "read_problem", linoptL_readProblem },
64 { "write_problem", linoptL_writeProblem },
65 { 0, 0 } };
66
73int nlua_loadLinOpt( nlua_env env )
74{
75 nlua_register( env, LINOPT_METATABLE, linoptL_methods, 1 );
76 return 0;
77}
78
91LuaLinOpt_t *lua_tolinopt( lua_State *L, int ind )
92{
93 return (LuaLinOpt_t *)lua_touserdata( L, ind );
94}
95
103LuaLinOpt_t *luaL_checklinopt( lua_State *L, int ind )
104{
105 if ( lua_islinopt( L, ind ) )
106 return lua_tolinopt( L, ind );
107 luaL_typerror( L, ind, LINOPT_METATABLE );
108 return NULL;
109}
110
118LuaLinOpt_t *lua_pushlinopt( lua_State *L, LuaLinOpt_t linopt )
119{
120 LuaLinOpt_t *c = (LuaLinOpt_t *)lua_newuserdata( L, sizeof( LuaLinOpt_t ) );
121 *c = linopt;
122 luaL_getmetatable( L, LINOPT_METATABLE );
123 lua_setmetatable( L, -2 );
124 return c;
125}
126
134int lua_islinopt( lua_State *L, int ind )
135{
136 int ret;
137
138 if ( lua_getmetatable( L, ind ) == 0 )
139 return 0;
140 lua_getfield( L, LUA_REGISTRYINDEX, LINOPT_METATABLE );
141
142 ret = 0;
143 if ( lua_rawequal( L, -1, -2 ) ) /* does it have the correct mt? */
144 ret = 1;
145
146 lua_pop( L, 2 ); /* remove both metatables */
147 return ret;
148}
149
156static int linoptL_gc( lua_State *L )
157{
158 LuaLinOpt_t *lp = luaL_checklinopt( L, 1 );
159 glp_delete_prob( lp->prob );
160 return 0;
161}
162
171static int linoptL_eq( lua_State *L )
172{
173 LuaLinOpt_t *lp1, *lp2;
174 lp1 = luaL_checklinopt( L, 1 );
175 lp2 = luaL_checklinopt( L, 2 );
176 lua_pushboolean( L, ( memcmp( lp1, lp2, sizeof( LuaLinOpt_t ) ) == 0 ) );
177 return 1;
178}
179
191static int linoptL_new( lua_State *L )
192{
193 LuaLinOpt_t lp;
194 const char *name;
195 int max;
196
197 /* Input. */
198 name = luaL_optstring( L, 1, NULL );
199 lp.ncols = luaL_checkinteger( L, 2 );
200 lp.nrows = luaL_checkinteger( L, 3 );
201 max = lua_toboolean( L, 4 );
202
203#ifdef DEBUGGING
204 if ( lp.ncols <= 0 )
205 return NLUA_ERROR( L, _( "Number of columns in a linear optimization "
206 "problem must be greater than 0!" ) );
207#endif /* DEBUGGING */
208
209 /* Initialize and create. */
210 lp.prob = glp_create_prob();
211 glp_set_prob_name( lp.prob, name );
212 glp_add_cols( lp.prob, lp.ncols );
213 glp_add_rows( lp.prob, lp.nrows );
214 if ( max )
215 glp_set_obj_dir( lp.prob, GLP_MAX );
216
217 lua_pushlinopt( L, lp );
218 return 1;
219}
220
229static int linoptL_size( lua_State *L )
230{
231 LuaLinOpt_t *lp = luaL_checklinopt( L, 1 );
232 lua_pushinteger( L, glp_get_num_cols( lp->prob ) );
233 lua_pushinteger( L, glp_get_num_rows( lp->prob ) );
234 return 2;
235}
236
244static int linoptL_addcols( lua_State *L )
245{
246 LuaLinOpt_t *lp = luaL_checklinopt( L, 1 );
247 int toadd = luaL_checkinteger( L, 2 );
248 glp_add_cols( lp->prob, toadd );
249 lp->ncols += toadd;
250 return 0;
251}
252
260static int linoptL_addrows( lua_State *L )
261{
262 LuaLinOpt_t *lp = luaL_checklinopt( L, 1 );
263 int toadd = luaL_checkinteger( L, 2 );
264 glp_add_rows( lp->prob, toadd );
265 lp->nrows += toadd;
266 return 0;
267}
268
283static int linoptL_setcol( lua_State *L )
284{
285 LuaLinOpt_t *lp = luaL_checklinopt( L, 1 );
286 int idx = luaL_checkinteger( L, 2 );
287 const char *name = luaL_checkstring( L, 3 );
288 double coef = luaL_checknumber( L, 4 );
289 const char *skind = luaL_optstring( L, 5, "real" );
290 int haslb = !lua_isnoneornil( L, 6 );
291 int hasub = !lua_isnoneornil( L, 7 );
292 double lb = luaL_optnumber( L, 6, 0.0 );
293 double ub = luaL_optnumber( L, 7, 0.0 );
294 int type = GLP_FR, kind = GLP_CV;
295
296 /* glpk stuff */
297 glp_set_col_name( lp->prob, idx, name );
298 glp_set_obj_coef( lp->prob, idx, coef );
299
300 /* Determine bounds. */
301 if ( haslb && hasub ) {
302 if ( fabs( lb - ub ) < DOUBLE_TOL )
303 type = GLP_FX;
304 else
305 type = GLP_DB;
306 } else if ( haslb )
307 type = GLP_LO;
308 else if ( hasub )
309 type = GLP_UP;
310 else
311 type = GLP_FR;
312 glp_set_col_bnds( lp->prob, idx, type, lb, ub );
313
314 /* Get kind. */
315 if ( strcmp( skind, "real" ) == 0 )
316 kind = GLP_CV;
317 else if ( strcmp( skind, "integer" ) == 0 )
318 kind = GLP_IV;
319 else if ( strcmp( skind, "binary" ) == 0 )
320 kind = GLP_BV;
321 else
322 return NLUA_ERROR( L, _( "Unknown column kind '%s'!" ), skind );
323 glp_set_col_kind( lp->prob, idx, kind );
324
325 return 0;
326}
327
338static int linoptL_setrow( lua_State *L )
339{
340 LuaLinOpt_t *lp = luaL_checklinopt( L, 1 );
341 int idx = luaL_checkinteger( L, 2 );
342 const char *name = luaL_checkstring( L, 3 );
343 int haslb, hasub, type;
344 double lb, ub;
345
346 /* glpk stuff */
347 glp_set_row_name( lp->prob, idx, name );
348
349 /* Determine bounds. */
350 haslb = !lua_isnoneornil( L, 4 );
351 hasub = !lua_isnoneornil( L, 5 );
352 lb = luaL_optnumber( L, 4, 0.0 );
353 ub = luaL_optnumber( L, 5, 0.0 );
354 if ( haslb && hasub ) {
355 if ( fabs( lb - ub ) < DOUBLE_TOL )
356 type = GLP_FX;
357 else
358 type = GLP_DB;
359 } else if ( haslb )
360 type = GLP_LO;
361 else if ( hasub )
362 type = GLP_UP;
363 else
364 type = GLP_FR;
365 glp_set_row_bnds( lp->prob, idx, type, lb, ub );
366
367 return 0;
368}
369
379static int linoptL_loadmatrix( lua_State *L )
380{
381 size_t n;
382 int *ia, *ja;
383 double *ar;
384 LuaLinOpt_t *lp = luaL_checklinopt( L, 1 );
385 luaL_checktype( L, 2, LUA_TTABLE );
386 luaL_checktype( L, 3, LUA_TTABLE );
387 luaL_checktype( L, 4, LUA_TTABLE );
388
389 /* Make sure size is ok. */
390 n = lua_objlen( L, 2 );
391#if DEBUGGING
392 if ( ( n != lua_objlen( L, 3 ) ) || ( n != lua_objlen( L, 4 ) ) )
393 return NLUA_ERROR( L, _( "Table lengths don't match!" ) );
394#endif /* DEBUGGING */
395
396 /* Load everything from tables, has to be 1-index based. */
397 ia = calloc( n + 1, sizeof( int ) );
398 ja = calloc( n + 1, sizeof( int ) );
399 ar = calloc( n + 1, sizeof( double ) );
400 for ( size_t i = 1; i <= n; i++ ) {
401 lua_rawgeti( L, 2, i );
402 lua_rawgeti( L, 3, i );
403 lua_rawgeti( L, 4, i );
404#if DEBUGGING
405 ia[i] = luaL_checkinteger( L, -3 );
406 ja[i] = luaL_checkinteger( L, -2 );
407 ar[i] = luaL_checknumber( L, -1 );
408#else /* DEBUGGING */
409 ia[i] = lua_tointeger( L, -3 );
410 ja[i] = lua_tointeger( L, -2 );
411 ar[i] = lua_tonumber( L, -1 );
412#endif /* DEBUGGING */
413 lua_pop( L, 3 );
414 }
415
416 /* Set up the matrix. */
417 glp_load_matrix( lp->prob, n, ia, ja, ar );
418
419 /* Clean up. */
420 free( ia );
421 free( ja );
422 free( ar );
423 return 0;
424}
425
426static const char *linopt_status( int retval )
427{
428 switch ( retval ) {
429 case GLP_OPT:
430 return "solution is optimal";
431 case GLP_FEAS:
432 return "solution is feasible";
433 case GLP_INFEAS:
434 return "solution is infeasible";
435 case GLP_NOFEAS:
436 return "problem has no feasible solution";
437 case GLP_UNBND:
438 return "problem has unbounded solution";
439 case GLP_UNDEF:
440 return "solution is undefined";
441 default:
442 return "unknown GLPK status";
443 }
444}
445static const char *linopt_error( int retval )
446{
447 switch ( retval ) {
448 case 0:
449 return "No error";
450
451 /* COMMON */
452 case GLP_EFAIL:
453 return "The search was prematurely terminated due to the solver failure.";
454 case GLP_ETMLIM:
455 return "The search was prematurely terminated, because the time limit "
456 "has been exceeded.";
457
458 /* SIMPLEX */
459 case GLP_EBADB:
460 return "Unable to start the search, because the initial basis specified "
461 "in the problem object is invalid—the number of basic (auxiliary "
462 "and structural) variables is not the same as the number of rows "
463 "in the problem object.";
464 case GLP_ESING:
465 return "Unable to start the search, because the basis matrix "
466 "corresponding to the initial basis is singular within the "
467 "working precision.";
468 case GLP_ECOND:
469 return "Unable to start the search, because the basis matrix "
470 "corresponding to the initial basis is ill-conditioned, i.e. its "
471 "condition number is too large.";
472 case GLP_EBOUND:
473 return "Unable to start the search, because some double-bounded "
474 "(auxiliary or structural) variables have incorrect bounds.";
475 case GLP_EOBJLL:
476 return "The search was prematurely terminated, because the objective "
477 "function being maximized has reached its lower limit and "
478 "continues decreasing (the dual simplex only).";
479 case GLP_EOBJUL:
480 return "The search was prematurely terminated, because the objective "
481 "function being minimized has reached its upper limit and "
482 "continues increasing (the dual simplex only).";
483 case GLP_EITLIM:
484 return "The search was prematurely terminated, because the simplex "
485 "iteration limit has been exceeded.";
486
487 /* INTOPT */
488 case GLP_EROOT:
489 return "Unable to start the search, because optimal basis for initial LP "
490 "relaxation is not provided. (This code may appear only if the "
491 "presolver is disabled.)";
492 case GLP_ENOPFS:
493 return "Unable to start the search, because LP relaxation of the MIP "
494 "problem instance has no primal feasible solution. (This code may "
495 "appear only if the presolver is enabled.)";
496 case GLP_ENODFS:
497 return "Unable to start the search, because LP relaxation of the MIP "
498 "problem instance has no dual feasible solution. In other word, "
499 "this code means that if the LP relaxation has at least one "
500 "primal feasible solution, its optimal solution is unbounded, so "
501 "if the MIP problem has at least one integer feasible solution, "
502 "its (integer) optimal solution is also unbounded. (This code may "
503 "appear only if the presolver is enabled.)";
504 case GLP_EMIPGAP:
505 return "The search was prematurely terminated, because the relative mip "
506 "gap tolerance has been reached.";
507 case GLP_ESTOP:
508 return "The search was prematurely terminated by application. (This code "
509 "may appear only if the advanced solver interface is used.)";
510
511 default:
512 return "Unknown error.";
513 }
514}
515#if 1 /* GLPK Defaults. */
516/* SMCP */
517#define METH_DEF GLP_PRIMAL
518#define PRICING_DEF GLP_PT_PSE
519#define R_TEST_DEF GLP_RT_HAR
520#define PRESOLVE_DEF GLP_OFF
521/* IOCP */
522#define BR_TECH_DEF GLP_BR_DTH
523#define BT_TECH_DEF GLP_BT_BLB
524#define PP_TECH_DEF GLP_PP_ALL
525#define SR_HEUR_DEF GLP_ON
526#define FP_HEUR_DEF GLP_OFF
527#define PS_HEUR_DEF GLP_OFF
528#define GMI_CUTS_DEF GLP_OFF
529#define MIR_CUTS_DEF GLP_OFF
530#define COV_CUTS_DEF GLP_OFF
531#define CLQ_CUTS_DEF GLP_OFF
532#else
533/* Customized "optimal" defaults. */
534#define BR_TECH_DEF GLP_BR_PCH
535#define BT_TECH_DEF GLP_BT_DFS
536#define PP_TECH_DEF GLP_PP_ALL
537#define SR_HEUR_DEF GLP_ON
538#define FP_HEUR_DEF GLP_OFF
539#define PS_HEUR_DEF GLP_OFF
540#define GMI_CUTS_DEF GLP_ON
541#define MIR_CUTS_DEF GLP_OFF
542#define COV_CUTS_DEF GLP_ON
543#define CLQ_CUTS_DEF GLP_ON
544#endif
545#define STRCHK( val, ret ) \
546 if ( strcmp( str, ( val ) ) == 0 ) \
547 return ( ret );
548static int opt_meth( const char *str, int def )
549{
550 if ( str == NULL )
551 return def;
552 STRCHK( "primal", GLP_PRIMAL );
553 STRCHK( "dual", GLP_DUAL );
554 STRCHK( "dualp", GLP_DUALP );
555 WARN( "Unknown meth value '%s'", str );
556 return def;
557}
558static int opt_pricing( const char *str, int def )
559{
560 if ( str == NULL )
561 return def;
562 STRCHK( "std", GLP_PT_STD );
563 STRCHK( "pse", GLP_PT_PSE );
564 WARN( "Unknown pricing value '%s'", str );
565 return def;
566}
567static int opt_r_test( const char *str, int def )
568{
569 if ( str == NULL )
570 return def;
571 STRCHK( "std", GLP_RT_STD );
572 STRCHK( "har", GLP_RT_HAR );
573 WARN( "Unknown r_test value '%s'", str );
574 return def;
575}
576static int opt_br_tech( const char *str, int def )
577{
578 if ( str == NULL )
579 return def;
580 STRCHK( "ffv", GLP_BR_FFV );
581 STRCHK( "lfv", GLP_BR_LFV );
582 STRCHK( "mfv", GLP_BR_MFV );
583 STRCHK( "dth", GLP_BR_DTH );
584 STRCHK( "pch", GLP_BR_PCH );
585 WARN( "Unknown br_tech value '%s'", str );
586 return def;
587}
588static int opt_bt_tech( const char *str, int def )
589{
590 if ( str == NULL )
591 return def;
592 STRCHK( "dfs", GLP_BT_DFS );
593 STRCHK( "bfs", GLP_BT_BFS );
594 STRCHK( "blb", GLP_BT_BLB );
595 STRCHK( "bph", GLP_BT_BPH );
596 WARN( "Unknown bt_tech value '%s'", str );
597 return def;
598}
599static int opt_pp_tech( const char *str, int def )
600{
601 if ( str == NULL )
602 return def;
603 STRCHK( "none", GLP_PP_NONE );
604 STRCHK( "root", GLP_PP_ROOT );
605 STRCHK( "all", GLP_PP_ALL );
606 WARN( "Unknown pp_tech value '%s'", str );
607 return def;
608}
609static int opt_onoff( const char *str, int def )
610{
611 if ( str == NULL )
612 return def;
613 STRCHK( "on", GLP_ON );
614 STRCHK( "off", GLP_OFF );
615 WARN( "Unknown onoff value '%s'", str );
616 return def;
617}
618#undef STRCHK
619
620#define GETOPT_IOCP( name, func, def ) \
621 do { \
622 lua_getfield( L, 2, #name ); \
623 parm_iocp.name = func( luaL_optstring( L, -1, NULL ), def ); \
624 lua_pop( L, 1 ); \
625 } while ( 0 )
626#define GETOPT_SMCP( name, func, def ) \
627 do { \
628 lua_getfield( L, 2, #name ); \
629 parm_smcp.name = func( luaL_optstring( L, -1, NULL ), def ); \
630 lua_pop( L, 1 ); \
631 } while ( 0 )
640static int linoptL_solve( lua_State *L )
641{
642 LuaLinOpt_t *lp = luaL_checklinopt( L, 1 );
643 double z;
644 int ret, ismip;
645 glp_iocp parm_iocp;
646 glp_smcp parm_smcp;
647#if DEBUGGING
648 Uint64 starttime = SDL_GetTicks64();
649#endif /* DEBUGGING */
650
651 /* Parameters. */
652 ismip = ( glp_get_num_int( lp->prob ) > 0 );
653 glp_init_smcp( &parm_smcp );
654 parm_smcp.msg_lev = GLP_MSG_ERR;
655 parm_smcp.tm_lim = LINOPT_MAX_TM;
656 if ( ismip ) {
657 glp_init_iocp( &parm_iocp );
658 parm_iocp.msg_lev = GLP_MSG_ERR;
659 parm_iocp.tm_lim = LINOPT_MAX_TM;
660 }
661
662 /* Load parameters. */
663 if ( !lua_isnoneornil( L, 2 ) ) {
664 GETOPT_SMCP( meth, opt_meth, METH_DEF );
665 GETOPT_SMCP( pricing, opt_pricing, PRICING_DEF );
666 GETOPT_SMCP( r_test, opt_r_test, R_TEST_DEF );
667 GETOPT_SMCP( presolve, opt_onoff, PRESOLVE_DEF );
668 if ( ismip ) {
669 GETOPT_IOCP( br_tech, opt_br_tech, BR_TECH_DEF );
670 GETOPT_IOCP( bt_tech, opt_bt_tech, BT_TECH_DEF );
671 GETOPT_IOCP( pp_tech, opt_pp_tech, PP_TECH_DEF );
672 GETOPT_IOCP( sr_heur, opt_onoff, SR_HEUR_DEF );
673 GETOPT_IOCP( fp_heur, opt_onoff, FP_HEUR_DEF );
674 GETOPT_IOCP( ps_heur, opt_onoff, PS_HEUR_DEF );
675 GETOPT_IOCP( gmi_cuts, opt_onoff, GMI_CUTS_DEF );
676 GETOPT_IOCP( mir_cuts, opt_onoff, MIR_CUTS_DEF );
677 GETOPT_IOCP( cov_cuts, opt_onoff, COV_CUTS_DEF );
678 GETOPT_IOCP( clq_cuts, opt_onoff, CLQ_CUTS_DEF );
679 }
680 }
681#if 0
682 else {
683 parm_smcp.meth = METH_DEF;
684 parm_smcp.pricing = PRICING_DEF;
685 parm_smcp.r_test = R_TEST_DEF;
686 parm_smcp.presolve= PRESOLVE_DEF;
687 if (ismip) {
688 parm_iocp.br_tech = BR_TECH_DEF;
689 parm_iocp.bt_tech = BT_TECH_DEF;
690 parm_iocp.pp_tech = PP_TECH_DEF;
691 parm_iocp.sr_heur = SR_HEUR_DEF;
692 parm_iocp.fp_heur = FP_HEUR_DEF;
693 parm_iocp.ps_heur = PS_HEUR_DEF;
694 parm_iocp.gmi_cuts = GMI_CUTS_DEF;
695 parm_iocp.mir_cuts = MIR_CUTS_DEF;
696 parm_iocp.cov_cuts = COV_CUTS_DEF;
697 parm_iocp.clq_cuts = CLQ_CUTS_DEF;
698 }
699 }
700#endif
701
702 /* Optimization. */
703 if ( !ismip || !parm_iocp.presolve ) {
704 ret = glp_simplex( lp->prob, &parm_smcp );
705 if ( ( ret != 0 ) && ( ret != GLP_ETMLIM ) ) {
706 lua_pushnil( L );
707 lua_pushstring( L, linopt_error( ret ) );
708 return 2;
709 }
710 /* Check for optimality of continuous problem. */
711 ret = glp_get_status( lp->prob );
712 if ( ( ret != GLP_OPT ) && ( ret != GLP_FEAS ) ) {
713 lua_pushnil( L );
714 lua_pushstring( L, linopt_status( ret ) );
715 return 2;
716 }
717 }
718 if ( ismip ) {
719 ret = glp_intopt( lp->prob, &parm_iocp );
720 if ( ( ret != 0 ) && ( ret != GLP_ETMLIM ) ) {
721 lua_pushnil( L );
722 lua_pushstring( L, linopt_error( ret ) );
723 return 2;
724 }
725 /* Check for optimality of discrete problem. */
726 ret = glp_mip_status( lp->prob );
727 if ( ( ret != GLP_OPT ) && ( ret != GLP_FEAS ) ) {
728 lua_pushnil( L );
729 lua_pushstring( L, linopt_status( ret ) );
730 return 2;
731 }
732 }
733 z = glp_get_obj_val( lp->prob );
734
735 /* Output function value. */
736 lua_pushnumber( L, z );
737
738 /* Go over variables and store them. */
739 lua_newtable( L ); /* t */
740 for ( int i = 1; i <= lp->ncols; i++ ) {
741 if ( ismip )
742 z = glp_mip_col_val( lp->prob, i );
743 else
744 z = glp_get_col_prim( lp->prob, i );
745 lua_pushnumber( L, z ); /* t, z */
746 lua_rawseti( L, -2, i ); /* t */
747 }
748
749 /* Go over constraints and store them. */
750 lua_newtable( L ); /* t */
751 for ( int i = 1; i <= lp->nrows; i++ ) {
752 if ( ismip )
753 z = glp_mip_row_val( lp->prob, i );
754 else
755 z = glp_get_row_prim( lp->prob, i );
756 lua_pushnumber( L, z ); /* t, z */
757 lua_rawseti( L, -2, i ); /* t */
758 }
759
760 /* Complain about time. */
761#if DEBUGGING
762 if ( SDL_GetTicks64() - starttime > LINOPT_MAX_TM )
763 NLUA_WARN( L, _( "glpk: too over 1 second to optimize!" ) );
764#endif /* DEBUGGING */
765
766 return 3;
767}
768#undef GETOPT_IOCP
769
781static int linoptL_readProblem( lua_State *L )
782{
783 const char *fname = luaL_checkstring( L, 1 );
784 int glpk_format = lua_toboolean( L, 2 );
785 int maximize = lua_toboolean( L, 3 );
786 const char *dirname = PHYSFS_getRealDir( fname );
787 char *fpath;
788 int ret;
789 LuaLinOpt_t lp;
790 if ( dirname == NULL )
791 return NLUA_ERROR( L, _( "Failed to read LP problem \"%s\"!" ), fname );
792 SDL_asprintf( &fpath, "%s/%s", dirname, fname );
793 lp.prob = glp_create_prob();
794 ret = glpk_format ? glp_read_prob( lp.prob, 0, fpath )
795 : glp_read_mps( lp.prob, GLP_MPS_FILE, NULL, fpath );
796 free( fpath );
797 if ( ret != 0 ) {
798 glp_delete_prob( lp.prob );
799 return NLUA_ERROR( L, _( "Failed to read LP problem \"%s\"!" ), fname );
800 }
801 lp.ncols = glp_get_num_cols( lp.prob );
802 lp.nrows = glp_get_num_rows( lp.prob );
803 if ( maximize )
804 glp_set_obj_dir( lp.prob, GLP_MAX );
805 lua_pushlinopt( L, lp );
806 return 1;
807}
808
818static int linoptL_writeProblem( lua_State *L )
819{
820 LuaLinOpt_t *lp = luaL_checklinopt( L, 1 );
821 const char *fname = luaL_checkstring( L, 2 );
822 int glpk_format = lua_toboolean( L, 3 );
823 const char *dirname = PHYSFS_getWriteDir();
824 char *fpath;
825 int ret;
826 SDL_asprintf( &fpath, "%s/%s", dirname, fname );
827 ret = glpk_format ? glp_write_prob( lp->prob, 0, fpath )
828 : glp_write_mps( lp->prob, GLP_MPS_FILE, NULL, fpath );
829 free( fpath );
830 lua_pushboolean( L, ret == 0 );
831 return 1;
832}
Header file with generic functions and naev-specifics.
LuaLinOpt_t * luaL_checklinopt(lua_State *L, int ind)
Gets linopt at index or raises error if there is no linopt at index.
static int linoptL_loadmatrix(lua_State *L)
Loads the entire matrix for the linear program.
static const luaL_Reg linoptL_methods[]
Definition nlua_linopt.c:52
static int linoptL_setcol(lua_State *L)
Adds an optimization column.
static int linoptL_solve(lua_State *L)
Solves the linear optimization problem.
static int linoptL_gc(lua_State *L)
Frees a linopt.
LuaLinOpt_t * lua_pushlinopt(lua_State *L, LuaLinOpt_t linopt)
Pushes a linopt on the stack.
LuaLinOpt_t * lua_tolinopt(lua_State *L, int ind)
Lua bindings to interact with linopts.
Definition nlua_linopt.c:91
static int linoptL_readProblem(lua_State *L)
Reads an optimization problem from a file for debugging purposes.
static int linoptL_size(lua_State *L)
Adds columns to the linear program.
static int linoptL_addrows(lua_State *L)
Adds rows to the linear program.
static int linoptL_new(lua_State *L)
Opens a new linopt.
int lua_islinopt(lua_State *L, int ind)
Checks to see if ind is a linopt.
static int linoptL_addcols(lua_State *L)
Adds columns to the linear program.
#define LINOPT_MAX_TM
Definition nlua_linopt.c:25
static int linoptL_setrow(lua_State *L)
Adds an optimization row.
static int linoptL_eq(lua_State *L)
Compares two linopts to see if they are the same.
int nlua_loadLinOpt(nlua_env env)
Loads the linopt library.
Definition nlua_linopt.c:73
static int linoptL_writeProblem(lua_State *L)
Writes an optimization problem to a file for debugging purposes.
static const double c[]
Definition rng.c:256
Our cute little linear program wrapper.
Definition nlua_linopt.c:32
glp_prob * prob
Definition nlua_linopt.c:35