#include #include #include #include #define FUNCTOR_plus2 PL_new_functor(PL_new_atom("+"), 2) #define FUNCTOR_minus2 PL_new_functor(PL_new_atom("-"), 2) #define FUNCTOR_times2 PL_new_functor(PL_new_atom("*"), 2) #define FUNCTOR_divide2 PL_new_functor(PL_new_atom("/"), 2) #define FUNCTOR_pow2 PL_new_functor(PL_new_atom("^"), 2) #define FUNCTOR_LO PL_new_functor(PL_new_atom(">="), 2) #define FUNCTOR_UP PL_new_functor(PL_new_atom("=<"), 2) #define FUNCTOR_BD PL_new_functor(PL_new_atom("="), 2) typedef struct node { int is_terminal; int j; struct node* edges[10]; } node; const int inf = 1e9; node* root = NULL; size_t maxVarId = 0; size_t ar_size = 0; double* ar; int* ia; int* ja; glp_prob *lp; size_t last_symbol = 1; size_t row_number = 0; node* newNode() { node* ans = (node*)calloc(1, sizeof(node)); if (ans == NULL) { printf("There's no memory"); PL_fail; } return ans; } void init() { root = newNode(); maxVarId = 0; ar_size = 0; last_symbol = 1; row_number = 0; return; } void FreeNodes(node* x) { if (x == NULL) return; for (int i = 0; i < 10; ++i) { FreeNodes(x->edges[i]); } free(x); } int GetColId(char* nameInProlog) { node* itr = root; for (size_t i = 1; i < strlen(nameInProlog); ++i) { if (nameInProlog[i]-'0' < 0 || nameInProlog[i]-'0' > 9) { printf("Error in nameInProlog"); PL_fail; } if (itr->edges[nameInProlog[i]-'0'] == NULL) { itr->edges[nameInProlog[i]-'0'] = newNode(); } itr = itr->edges[nameInProlog[i]-'0']; } if (itr->is_terminal == 0) { itr->is_terminal = 1; itr->j = ++maxVarId; // printf("Added var: %d, %s\n", itr->j, nameInProlog); // glp_set_col_bnds(lp, itr->j, GLP_LO, 0.0, 0.0); // all Vars must be >= 0 } return itr->j; } char* GetName(term_t term) { char* name; if (PL_get_chars(term, &name, CVT_VARIABLE | CVT_WRITE | REP_UTF8)) { return name; } else { printf("\nFailed to get variable name.\n"); PL_fail; } } void ReadVars(term_t itr, int is_obj) { if (PL_is_compound(itr)) { functor_t f; if (PL_get_functor(itr, &f)) { if (f == FUNCTOR_times2 || f == FUNCTOR_plus2 || f == FUNCTOR_minus2) { term_t arg1 = PL_new_term_ref(); term_t arg2 = PL_new_term_ref(); if (PL_get_arg(1, itr, arg1) && PL_get_arg(2, itr, arg2)) { ReadVars(arg1, is_obj); ReadVars(arg2, is_obj); return; } } else { printf("Unknown functor"); } } } if (PL_is_variable(itr)) { if (!is_obj) ++ar_size; // printf("Read: %d -> %s\n", ar_size, GetName(itr)); GetColId(GetName(itr)); } } void AddingExprToLP(term_t itr, int row_id, int negative, int is_obj) { if (PL_is_compound(itr)) { functor_t f; if (PL_get_functor(itr, &f)) { term_t arg1 = PL_new_term_ref(); term_t arg2 = PL_new_term_ref(); if (f == FUNCTOR_times2 ){ if (PL_get_arg(1, itr, arg1) && PL_get_arg(2, itr, arg2)) { if (PL_is_integer(arg1) || PL_is_float(arg1)) { int id = GetColId(GetName(arg2)); double val; if (PL_is_integer(arg1)) { int i; PL_get_integer(arg1, &i); val = (double)i; } else PL_get_float(arg1, &val); if (negative) val *= -1; if (!is_obj) { ia[last_symbol] = row_id; ja[last_symbol] = id; ar[last_symbol] = val; ++last_symbol; // printf("Added: (i: %d, j: %d, v: %lf)\n", row_id, id, val); } else { glp_set_obj_coef(lp, id, val); } } else printf("Please use const*Var notation"); } } else if (f == FUNCTOR_plus2) { if (PL_get_arg(1, itr, arg1) && PL_get_arg(2, itr, arg2)) { AddingExprToLP(arg1, row_id, 0, is_obj); AddingExprToLP(arg2, row_id, 0, is_obj); } } else if (f == FUNCTOR_minus2) { if (PL_get_arg(1, itr, arg1) && PL_get_arg(2, itr, arg2)) { AddingExprToLP(arg1, row_id, 0, is_obj); AddingExprToLP(arg2, row_id, 1, is_obj); } } else { printf("Unknown functor"); } } } else if (PL_is_variable(itr)) { int id = GetColId(GetName(itr)); if (!is_obj) { ia[last_symbol] = row_id; ja[last_symbol] = id; if (negative) ar[last_symbol] = -1; else ar[last_symbol] = 1; ++last_symbol; } else { if (negative) glp_set_obj_coef(lp, id, -1); else glp_set_obj_coef(lp, id, 1); } } } /** list of integers vars Min Value (return) Status from glpk list of constrains | objective func | List of asked vars (return) | | | | | | | V V V V V V */ foreign_t pl_expr(term_t cons, term_t ints, term_t obj, term_t _mn, term_t _ans, term_t _status) { init(); glp_term_out(GLP_OFF); term_t head = PL_new_term_ref(); term_t tail = PL_new_term_ref(); lp = glp_create_prob(); glp_set_prob_name(lp, "BSP-2"); glp_set_obj_dir(lp, GLP_MAX); term_t cons_copy = PL_copy_term_ref(cons); while (PL_get_list(cons_copy, head, tail)) { term_t expr = PL_new_term_ref(); PL_get_arg(1, head, expr); ReadVars(expr, 0); ++row_number; cons_copy = tail; } if (!PL_get_nil(cons_copy)) { printf("The list is not properly terminated.\n"); PL_fail; } ReadVars(obj, 1); cons_copy = PL_copy_term_ref(ints); while (PL_get_list(cons_copy, head, tail)) { if (PL_is_variable(head)) { GetColId(GetName(head)); // Just to add vars to Trie } else { printf("Ints must be the list of variables"); PL_fail; } cons_copy = tail; } if (!PL_get_nil(cons_copy)) { printf("The list is not properly terminated.\n"); PL_fail; } // printf("Cons: %ld, Vars: %ld\n", row_number, maxVarId); row_number = (row_number == 0) ? 1 : row_number; maxVarId = (maxVarId == 0) ? 1 : maxVarId; // This needs to create a problem. glp_add_rows(lp, row_number); cons_copy = PL_copy_term_ref(cons); size_t row_id = 1; glp_add_cols(lp, maxVarId); ia = (int*)malloc((100+ar_size) * sizeof(int)); ja = (int*)malloc((100+ar_size) * sizeof(int)); ar = (double*)malloc((100+ar_size) * sizeof(double)); for (int i = 1; i <= maxVarId; ++i) { // printf("Added %d\n", i); // glp_set_col_kind(lp, i, GLP_CV); glp_set_col_bnds(lp, i, GLP_FR, 0, 0); // Making variables be whatever they want } while (PL_get_list(cons_copy, head, tail)) { term_t expr = PL_new_term_ref(); PL_get_arg(1, head, expr); // printf("Row(%d):", row_id); AddingExprToLP(expr, row_id, 0, 0); term_t bound = PL_new_term_ref(); PL_get_arg(2, head, bound); double bd; if (PL_is_integer(bound)) { int i; PL_get_integer(bound, &i); bd = (float)i; } else if (PL_is_float(bound)) { PL_get_float(bound, &bd); } else { printf("Wrong bound number"); PL_fail; } functor_t f; PL_get_functor(head, &f); // printf("%d -> ", row_id); if (f == FUNCTOR_UP) { glp_set_row_bnds(lp, row_id, GLP_UP, 0.0, bd); // printf("=< %lf\n", bd); } else if (f == FUNCTOR_LO) { glp_set_row_bnds(lp, row_id, GLP_LO, bd, 0.0); // printf(">= %lf\n", bd); } else if (f == FUNCTOR_BD) { glp_set_row_bnds(lp, row_id, GLP_FX, bd, bd); // printf("= %lf\n", bd); } else { printf("Please use only =/="); PL_fail; } ++row_id; cons_copy = tail; } if (!PL_get_nil(cons_copy)) { printf("The list is not properly terminated.\n"); PL_fail; } cons_copy = PL_copy_term_ref(ints); while (PL_get_list(cons_copy, head, tail)) { if (PL_is_variable(head)) { int id = GetColId(GetName(head)); // printf("%s - integer!!!\n", GetName(head)); glp_set_col_kind(lp, id, GLP_IV); // Say to glpk that head must be int. } else { printf("Ints must be the list of variables"); PL_fail; } cons_copy = tail; } // printf("number of integer columns - %d\n", glp_get_num_int(lp)); if (!PL_get_nil(cons_copy)) { printf("The list is not properly terminated.\n"); PL_fail; } AddingExprToLP(obj, 0, 0, 1); glp_load_matrix(lp, ar_size, ia, ja, ar); int ret = glp_simplex(lp, NULL); if (ret != 0) PL_fail; int st = glp_get_status(lp); PL_unify_integer(_status, st); // printf("!!!!Status::: %d\nVars: \n", st); /*for (int i = 1; i <= maxVarId; ++i) { printf("%d -> %g\n", i, glp_get_col_prim(lp, i)); }*/ // printf("Answer (prim): %lf\n", glp_get_obj_val(lp)); if (st == 4) { printf("LP has No feasuble solution."); fflush(stdout); PL_succeed; } if (st == 6) { printf("As solution is unbounded, all variables are bounded with [-1e9, 1e9] and the result is the following:\n"); for (int i = 1; i <= maxVarId; ++i) glp_set_col_bnds(lp, i, GLP_DB, -inf, inf); glp_set_obj_dir(lp, GLP_MIN); glp_simplex(lp, NULL); st = glp_get_status(lp); } if (st == 5) { glp_intopt(lp, NULL); int status_mip = glp_mip_status(lp); if (status_mip == 4) { printf("LP has solution, but it cannot be optimize to mip solution"); fflush(stdout); PL_unify_integer(_status, st); PL_succeed; } double val = glp_mip_obj_val(lp); // printf("Answer is %lf\n", val); PL_unify_float(_mn, val); cons_copy = PL_copy_term_ref(ints); term_t list = PL_new_term_refs(1); PL_put_nil(list); while (PL_get_list(cons_copy, head, tail)) { if (PL_is_variable(head)) { double node_val = glp_mip_col_val(lp, GetColId(GetName(head))); term_t value = PL_new_term_ref(); PL_put_float(value, node_val); PL_cons_list(list, value, list); } else { printf("Ints must be the list of variables"); PL_fail; } cons_copy = tail; } PL_unify(_ans, list); if (!PL_get_nil(cons_copy)) { printf("The list is not properly terminated.\n"); PL_fail; } } // printf("!!!Mip status: %d\n", glp_mip_status(lp)); glp_delete_prob(lp); // free Trie; for (int i = 0; i < 10; ++i) FreeNodes(root->edges[i]); printf("\nThanks!\n"); fflush(stdout); PL_succeed; } install_t install() { PL_register_foreign("maximize", 6, pl_expr, 0); } int main(void) { return 0; }