;; ;; Chicken interface to the GLPK API. ;; ;; Copyright 2008-2010 Ivan Raikov and the Okinawa Institute of ;; Science and Technology. ;; ;; This program is free software: you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation, either version 3 of the ;; License, or (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; ;; A full copy of the GPL license can be found at ;; . ;; (module glpk (lpx? lpx:empty-problem lpx:make-problem lpx:set-problem-name lpx:get-problem-name lpx:set-direction lpx:get-direction lpx:set-class lpx:get-class lpx:add-rows lpx:add-columns lpx:set-row-name lpx:set-column-name lpx:get-column-name lpx:get-row-name lpx:get-num-rows lpx:get-num-columns lpx:set-row-bounds lpx:set-column-bounds lpx:set-objective-coefficient lpx:set-column-kind lpx:load-constraint-matrix lpx:get-column-primals lpx:get-objective-value lpx:message_level lpx:scaling lpx:use_dual_simplex lpx:pricing lpx:solution_rounding lpx:iteration_limit lpx:iteration_count lpx:branching_heuristic lpx:backtracking_heuristic lpx:use_presolver lpx:relaxation lpx:time_limit LPX_E_OK LPX_E_EMPTY LPX_E_BADB LPX_E_INFEAS LPX_E_FAULT LPX_E_OBJLL LPX_E_OBJUL LPX_E_ITLIM LPX_E_TMLIM LPX_E_NOFEAS LPX_E_INSTAB LPX_E_SING LPX_E_NOCONV LPX_E_NOPFS LPX_E_NODFS lpx:scale-problem lpx:simplex lpx:integer ) (import scheme chicken foreign srfi-1 srfi-4 ) #> #include #include #define ERR_INVALID_LPX 1 #define ERR_INVALID_LPX_DIR 2 #define ERR_INVALID_LPX_CLASS 3 #define ERR_NEG_IND 4 #define ERR_INVALID_COL_KIND 5 #define ERR_INVALID_MAT_ORD 6 static C_word LPX_p(C_word obj) { if (C_immediatep(obj)) { return C_SCHEME_FALSE; } else if (C_block_header(obj) == LPX_TAG) { return C_SCHEME_TRUE; } else { return C_SCHEME_FALSE; } } static void chicken_Panic (C_char *) C_noret; static void chicken_Panic (C_char *msg) { C_word *a = C_alloc (C_SIZEOF_STRING (strlen (msg))); C_word scmmsg = C_string2 (&a, msg); C_halt (scmmsg); exit (5); /* should never get here */ } static void chicken_ThrowException(C_word value) C_noret; static void chicken_ThrowException(C_word value) { char *aborthook = C_text("\003sysabort"); C_word *a = C_alloc(C_SIZEOF_STRING(strlen(aborthook))); C_word abort = C_intern2(&a, aborthook); abort = C_block_item(abort, 0); if (C_immediatep(abort)) chicken_Panic(C_text("`##sys#abort' is not defined")); C_save(value); C_do_apply(1, abort, C_SCHEME_UNDEFINED); } void chicken_LPX_exception (int code, int msglen, const char *msg) { C_word *a; C_word scmmsg; C_word list; a = C_alloc (C_SIZEOF_STRING (msglen) + C_SIZEOF_LIST(2)); scmmsg = C_string2 (&a, (char *) msg); list = C_list(&a, 2, C_fix(code), scmmsg); chicken_ThrowException(list); } static C_word check_LPX (C_word obj) { if (C_immediatep(obj)) { chicken_LPX_exception (ERR_INVALID_LPX, 18, "invalid LPX object"); } else if (C_block_header(obj) == LPX_TAG) { return C_SCHEME_UNDEFINED; } else { chicken_LPX_exception (ERR_INVALID_LPX, 18, "invalid LPX object"); } } <# (define lpx? (foreign-lambda scheme-object "LPX_p" scheme-object)) (define lpx:empty-problem (foreign-primitive scheme-object () #< 0)) { chicken_LPX_exception (ERR_NEG_IND, 22, "nrows must be positive"); } lp = LPX_val(lpx); lpx_add_rows (lp, nrows); C_return(lpx); END )) (define lpx:get-num-rows (foreign-lambda* int ((scheme-object lpx)) #< 0)) { chicken_LPX_exception (ERR_NEG_IND, 22, "ncols must be positive"); } lp = LPX_val(lpx); lpx_add_cols (lp, ncols); C_return(lpx); END )) (define lpx:get-num-columns (foreign-lambda* int ((scheme-object lpx)) #<= 0)) { chicken_LPX_exception (ERR_NEG_IND, 34, "row index must be zero or positive"); } lp = LPX_val(lpx); lpx_set_row_name (lp, i, name); C_return(lpx); END )) (define lpx:set-column-name (foreign-lambda* scheme-object ((scheme-object lpx) (int j) (c-string name)) #<= 0)) { chicken_LPX_exception (ERR_NEG_IND, 37, "column index must be zero or positive"); } lp = LPX_val(lpx); lpx_set_col_name (lp, j, name); C_return(lpx); END )) (define lpx:get-row-name (foreign-lambda* c-string ((scheme-object lpx) (int i)) #<= 0)) { chicken_LPX_exception (ERR_NEG_IND, 34, "row index must be zero or positive"); } lp = LPX_val(lpx); result = lpx_get_row_name (lp, i); C_return(result); END )) (define lpx:get-column-name (foreign-lambda* c-string ((scheme-object lpx) (int i)) #<= 0)) { chicken_LPX_exception (ERR_NEG_IND, 37, "column index must be zero or positive"); } lp = LPX_val(lpx); result = lpx_get_col_name (lp, i); C_return(result); END )) (define LPX_LO (foreign-value "LPX_LO" int)) (define LPX_UP (foreign-value "LPX_UP" int)) (define LPX_DB (foreign-value "LPX_DB" int)) (define LPX_FX (foreign-value "LPX_FX" int)) (define LPX_FR (foreign-value "LPX_FR" int)) (define lpx_set_row_bounds (foreign-lambda* scheme-object ((scheme-object lpx) (int i) (int typx) (double lb) (double ub) ) #<= 0)) { chicken_LPX_exception (ERR_NEG_IND, 34, "row index must be zero or positive"); } lp = LPX_val(lpx); lpx_set_row_bnds (lp, i, typx, lb, ub); C_return(lpx); END )) (define lpx_set_col_bounds (foreign-lambda* scheme-object ((scheme-object lpx) (int j) (int typx) (double lb) (double ub) ) #<= 0)) { chicken_LPX_exception (ERR_NEG_IND, 37, "column index must be zero or positive"); } lp = LPX_val(lpx); lpx_set_col_bnds (lp, j, typx, lb, ub); C_return(lpx); END )) (define (lpx_set_bounds label f_set_bounds) (lambda (lpx i typx . rest) (let-optionals rest ((b1 #f) (b2 #f)) (case typx ((free unbounded) (f_set_bounds lpx i LPX_FR 0 0)) ((lower-bound lower lo lb) (if (integer? b1) (f_set_bounds lpx i LPX_LO b1 0) (error label "lower bound argument must be an integer"))) ((upper-bound upper up ub) (if (integer? b1) (f_set_bounds lpx i LPX_UP 0 b1) (error label "upper bound argument must be an integer"))) ((double-bounded double db) (if (and (integer? b1) (integer? b2)) (f_set_bounds lpx i LPX_DB b1 b2) (error label "lower and upper bound arguments must be integers"))) ((fixed fx) (if (and (integer? b1) (integer? b2)) (f_set_bounds lpx i LPX_FX b1 b2) (error label "lower and upper bound arguments must be integers"))) (else (error label "invalid bound type" typx)))))) (define lpx:set-row-bounds (lpx_set_bounds 'lpx:set-row-bounds lpx_set_row_bounds)) (define lpx:set-column-bounds (lpx_set_bounds 'lpx:set-column-bounds lpx_set_col_bounds)) (define lpx_get_column_primals (foreign-lambda* void ((scheme-object lpx) (int n) (f64vector v) ) #<= 0)) { chicken_LPX_exception (ERR_NEG_IND, 37, "column index must be zero or positive"); } lp = LPX_val(lpx); lpx_set_obj_coef (lp, j, coef); C_return(lpx); END )) (define LPX_CV (foreign-value "LPX_CV" int)) (define LPX_IV (foreign-value "LPX_IV" int)) (define lpx_set_column_kind (foreign-lambda* scheme-object ((scheme-object lpx) (int j) (int kind) ) #<= 0)) { chicken_LPX_exception (ERR_NEG_IND, 37, "column index must be zero or positive"); } if (!((kind == LPX_CV) || (kind == LPX_IV))) { chicken_LPX_exception (ERR_INVALID_COL_KIND, 23, "invalid LPX column kind"); } lp = LPX_val(lpx); lpx_set_col_kind (lp, j, kind); C_return(lpx); END )) (define (lpx:set-column-kind lpx j kind) (case kind ((integer int iv) (lpx_set_column_kind lpx j LPX_IV)) ((continuous cont cv) (lpx_set_column_kind lpx j LPX_CV)) (else (error 'lpx:set-column-kind "invalid column kind" kind)))) (define lpx_load_constraint_matrix (foreign-lambda* scheme-object ((scheme-object lpx) (int nrows) (int ncols) (char order) (f64vector m) (s32vector ia) (s32vector ja) (f64vector ar) ) #<