[9] | 1 | /* glpnpp01.c */ |
---|
| 2 | |
---|
| 3 | /*********************************************************************** |
---|
| 4 | * This code is part of GLPK (GNU Linear Programming Kit). |
---|
| 5 | * |
---|
| 6 | * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, |
---|
| 7 | * 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics, |
---|
| 8 | * Moscow Aviation Institute, Moscow, Russia. All rights reserved. |
---|
| 9 | * E-mail: <mao@gnu.org>. |
---|
| 10 | * |
---|
| 11 | * GLPK is free software: you can redistribute it and/or modify it |
---|
| 12 | * under the terms of the GNU General Public License as published by |
---|
| 13 | * the Free Software Foundation, either version 3 of the License, or |
---|
| 14 | * (at your option) any later version. |
---|
| 15 | * |
---|
| 16 | * GLPK is distributed in the hope that it will be useful, but WITHOUT |
---|
| 17 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
---|
| 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
---|
| 19 | * License for more details. |
---|
| 20 | * |
---|
| 21 | * You should have received a copy of the GNU General Public License |
---|
| 22 | * along with GLPK. If not, see <http://www.gnu.org/licenses/>. |
---|
| 23 | ***********************************************************************/ |
---|
| 24 | |
---|
| 25 | #include "glpnpp.h" |
---|
| 26 | |
---|
| 27 | NPP *npp_create_wksp(void) |
---|
| 28 | { /* create LP/MIP preprocessor workspace */ |
---|
| 29 | NPP *npp; |
---|
| 30 | npp = xmalloc(sizeof(NPP)); |
---|
| 31 | npp->orig_dir = 0; |
---|
| 32 | npp->orig_m = npp->orig_n = npp->orig_nnz = 0; |
---|
| 33 | npp->pool = dmp_create_pool(); |
---|
| 34 | npp->name = npp->obj = NULL; |
---|
| 35 | npp->c0 = 0.0; |
---|
| 36 | npp->nrows = npp->ncols = 0; |
---|
| 37 | npp->r_head = npp->r_tail = NULL; |
---|
| 38 | npp->c_head = npp->c_tail = NULL; |
---|
| 39 | npp->stack = dmp_create_pool(); |
---|
| 40 | npp->top = NULL; |
---|
| 41 | #if 0 /* 16/XII-2009 */ |
---|
| 42 | memset(&npp->count, 0, sizeof(npp->count)); |
---|
| 43 | #endif |
---|
| 44 | npp->m = npp->n = npp->nnz = 0; |
---|
| 45 | npp->row_ref = npp->col_ref = NULL; |
---|
| 46 | npp->sol = npp->scaling = 0; |
---|
| 47 | npp->p_stat = npp->d_stat = npp->t_stat = npp->i_stat = 0; |
---|
| 48 | npp->r_stat = NULL; |
---|
| 49 | /*npp->r_prim =*/ npp->r_pi = NULL; |
---|
| 50 | npp->c_stat = NULL; |
---|
| 51 | npp->c_value = /*npp->c_dual =*/ NULL; |
---|
| 52 | return npp; |
---|
| 53 | } |
---|
| 54 | |
---|
| 55 | void npp_insert_row(NPP *npp, NPPROW *row, int where) |
---|
| 56 | { /* insert row to the row list */ |
---|
| 57 | if (where == 0) |
---|
| 58 | { /* insert row to the beginning of the row list */ |
---|
| 59 | row->prev = NULL; |
---|
| 60 | row->next = npp->r_head; |
---|
| 61 | if (row->next == NULL) |
---|
| 62 | npp->r_tail = row; |
---|
| 63 | else |
---|
| 64 | row->next->prev = row; |
---|
| 65 | npp->r_head = row; |
---|
| 66 | } |
---|
| 67 | else |
---|
| 68 | { /* insert row to the end of the row list */ |
---|
| 69 | row->prev = npp->r_tail; |
---|
| 70 | row->next = NULL; |
---|
| 71 | if (row->prev == NULL) |
---|
| 72 | npp->r_head = row; |
---|
| 73 | else |
---|
| 74 | row->prev->next = row; |
---|
| 75 | npp->r_tail = row; |
---|
| 76 | } |
---|
| 77 | return; |
---|
| 78 | } |
---|
| 79 | |
---|
| 80 | void npp_remove_row(NPP *npp, NPPROW *row) |
---|
| 81 | { /* remove row from the row list */ |
---|
| 82 | if (row->prev == NULL) |
---|
| 83 | npp->r_head = row->next; |
---|
| 84 | else |
---|
| 85 | row->prev->next = row->next; |
---|
| 86 | if (row->next == NULL) |
---|
| 87 | npp->r_tail = row->prev; |
---|
| 88 | else |
---|
| 89 | row->next->prev = row->prev; |
---|
| 90 | return; |
---|
| 91 | } |
---|
| 92 | |
---|
| 93 | void npp_activate_row(NPP *npp, NPPROW *row) |
---|
| 94 | { /* make row active */ |
---|
| 95 | if (!row->temp) |
---|
| 96 | { row->temp = 1; |
---|
| 97 | /* move the row to the beginning of the row list */ |
---|
| 98 | npp_remove_row(npp, row); |
---|
| 99 | npp_insert_row(npp, row, 0); |
---|
| 100 | } |
---|
| 101 | return; |
---|
| 102 | } |
---|
| 103 | |
---|
| 104 | void npp_deactivate_row(NPP *npp, NPPROW *row) |
---|
| 105 | { /* make row inactive */ |
---|
| 106 | if (row->temp) |
---|
| 107 | { row->temp = 0; |
---|
| 108 | /* move the row to the end of the row list */ |
---|
| 109 | npp_remove_row(npp, row); |
---|
| 110 | npp_insert_row(npp, row, 1); |
---|
| 111 | } |
---|
| 112 | return; |
---|
| 113 | } |
---|
| 114 | |
---|
| 115 | void npp_insert_col(NPP *npp, NPPCOL *col, int where) |
---|
| 116 | { /* insert column to the column list */ |
---|
| 117 | if (where == 0) |
---|
| 118 | { /* insert column to the beginning of the column list */ |
---|
| 119 | col->prev = NULL; |
---|
| 120 | col->next = npp->c_head; |
---|
| 121 | if (col->next == NULL) |
---|
| 122 | npp->c_tail = col; |
---|
| 123 | else |
---|
| 124 | col->next->prev = col; |
---|
| 125 | npp->c_head = col; |
---|
| 126 | } |
---|
| 127 | else |
---|
| 128 | { /* insert column to the end of the column list */ |
---|
| 129 | col->prev = npp->c_tail; |
---|
| 130 | col->next = NULL; |
---|
| 131 | if (col->prev == NULL) |
---|
| 132 | npp->c_head = col; |
---|
| 133 | else |
---|
| 134 | col->prev->next = col; |
---|
| 135 | npp->c_tail = col; |
---|
| 136 | } |
---|
| 137 | return; |
---|
| 138 | } |
---|
| 139 | |
---|
| 140 | void npp_remove_col(NPP *npp, NPPCOL *col) |
---|
| 141 | { /* remove column from the column list */ |
---|
| 142 | if (col->prev == NULL) |
---|
| 143 | npp->c_head = col->next; |
---|
| 144 | else |
---|
| 145 | col->prev->next = col->next; |
---|
| 146 | if (col->next == NULL) |
---|
| 147 | npp->c_tail = col->prev; |
---|
| 148 | else |
---|
| 149 | col->next->prev = col->prev; |
---|
| 150 | return; |
---|
| 151 | } |
---|
| 152 | |
---|
| 153 | void npp_activate_col(NPP *npp, NPPCOL *col) |
---|
| 154 | { /* make column active */ |
---|
| 155 | if (!col->temp) |
---|
| 156 | { col->temp = 1; |
---|
| 157 | /* move the column to the beginning of the column list */ |
---|
| 158 | npp_remove_col(npp, col); |
---|
| 159 | npp_insert_col(npp, col, 0); |
---|
| 160 | } |
---|
| 161 | return; |
---|
| 162 | } |
---|
| 163 | |
---|
| 164 | void npp_deactivate_col(NPP *npp, NPPCOL *col) |
---|
| 165 | { /* make column inactive */ |
---|
| 166 | if (col->temp) |
---|
| 167 | { col->temp = 0; |
---|
| 168 | /* move the column to the end of the column list */ |
---|
| 169 | npp_remove_col(npp, col); |
---|
| 170 | npp_insert_col(npp, col, 1); |
---|
| 171 | } |
---|
| 172 | return; |
---|
| 173 | } |
---|
| 174 | |
---|
| 175 | NPPROW *npp_add_row(NPP *npp) |
---|
| 176 | { /* add new row to the current problem */ |
---|
| 177 | NPPROW *row; |
---|
| 178 | row = dmp_get_atom(npp->pool, sizeof(NPPROW)); |
---|
| 179 | row->i = ++(npp->nrows); |
---|
| 180 | row->name = NULL; |
---|
| 181 | row->lb = -DBL_MAX, row->ub = +DBL_MAX; |
---|
| 182 | row->ptr = NULL; |
---|
| 183 | row->temp = 0; |
---|
| 184 | npp_insert_row(npp, row, 1); |
---|
| 185 | return row; |
---|
| 186 | } |
---|
| 187 | |
---|
| 188 | NPPCOL *npp_add_col(NPP *npp) |
---|
| 189 | { /* add new column to the current problem */ |
---|
| 190 | NPPCOL *col; |
---|
| 191 | col = dmp_get_atom(npp->pool, sizeof(NPPCOL)); |
---|
| 192 | col->j = ++(npp->ncols); |
---|
| 193 | col->name = NULL; |
---|
| 194 | #if 0 |
---|
| 195 | col->kind = GLP_CV; |
---|
| 196 | #else |
---|
| 197 | col->is_int = 0; |
---|
| 198 | #endif |
---|
| 199 | col->lb = col->ub = col->coef = 0.0; |
---|
| 200 | col->ptr = NULL; |
---|
| 201 | col->temp = 0; |
---|
| 202 | npp_insert_col(npp, col, 1); |
---|
| 203 | return col; |
---|
| 204 | } |
---|
| 205 | |
---|
| 206 | NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val) |
---|
| 207 | { /* add new element to the constraint matrix */ |
---|
| 208 | NPPAIJ *aij; |
---|
| 209 | aij = dmp_get_atom(npp->pool, sizeof(NPPAIJ)); |
---|
| 210 | aij->row = row; |
---|
| 211 | aij->col = col; |
---|
| 212 | aij->val = val; |
---|
| 213 | aij->r_prev = NULL; |
---|
| 214 | aij->r_next = row->ptr; |
---|
| 215 | aij->c_prev = NULL; |
---|
| 216 | aij->c_next = col->ptr; |
---|
| 217 | if (aij->r_next != NULL) |
---|
| 218 | aij->r_next->r_prev = aij; |
---|
| 219 | if (aij->c_next != NULL) |
---|
| 220 | aij->c_next->c_prev = aij; |
---|
| 221 | row->ptr = col->ptr = aij; |
---|
| 222 | return aij; |
---|
| 223 | } |
---|
| 224 | |
---|
| 225 | int npp_row_nnz(NPP *npp, NPPROW *row) |
---|
| 226 | { /* count number of non-zero coefficients in row */ |
---|
| 227 | NPPAIJ *aij; |
---|
| 228 | int nnz; |
---|
| 229 | xassert(npp == npp); |
---|
| 230 | nnz = 0; |
---|
| 231 | for (aij = row->ptr; aij != NULL; aij = aij->r_next) |
---|
| 232 | nnz++; |
---|
| 233 | return nnz; |
---|
| 234 | } |
---|
| 235 | |
---|
| 236 | int npp_col_nnz(NPP *npp, NPPCOL *col) |
---|
| 237 | { /* count number of non-zero coefficients in column */ |
---|
| 238 | NPPAIJ *aij; |
---|
| 239 | int nnz; |
---|
| 240 | xassert(npp == npp); |
---|
| 241 | nnz = 0; |
---|
| 242 | for (aij = col->ptr; aij != NULL; aij = aij->c_next) |
---|
| 243 | nnz++; |
---|
| 244 | return nnz; |
---|
| 245 | } |
---|
| 246 | |
---|
| 247 | void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info), |
---|
| 248 | int size) |
---|
| 249 | { /* push new entry to the transformation stack */ |
---|
| 250 | NPPTSE *tse; |
---|
| 251 | tse = dmp_get_atom(npp->stack, sizeof(NPPTSE)); |
---|
| 252 | tse->func = func; |
---|
| 253 | tse->info = dmp_get_atom(npp->stack, size); |
---|
| 254 | tse->link = npp->top; |
---|
| 255 | npp->top = tse; |
---|
| 256 | return tse->info; |
---|
| 257 | } |
---|
| 258 | |
---|
| 259 | #if 1 /* 23/XII-2009 */ |
---|
| 260 | void npp_erase_row(NPP *npp, NPPROW *row) |
---|
| 261 | { /* erase row content to make it empty */ |
---|
| 262 | NPPAIJ *aij; |
---|
| 263 | while (row->ptr != NULL) |
---|
| 264 | { aij = row->ptr; |
---|
| 265 | row->ptr = aij->r_next; |
---|
| 266 | if (aij->c_prev == NULL) |
---|
| 267 | aij->col->ptr = aij->c_next; |
---|
| 268 | else |
---|
| 269 | aij->c_prev->c_next = aij->c_next; |
---|
| 270 | if (aij->c_next == NULL) |
---|
| 271 | ; |
---|
| 272 | else |
---|
| 273 | aij->c_next->c_prev = aij->c_prev; |
---|
| 274 | dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ)); |
---|
| 275 | } |
---|
| 276 | return; |
---|
| 277 | } |
---|
| 278 | #endif |
---|
| 279 | |
---|
| 280 | void npp_del_row(NPP *npp, NPPROW *row) |
---|
| 281 | { /* remove row from the current problem */ |
---|
| 282 | #if 0 /* 23/XII-2009 */ |
---|
| 283 | NPPAIJ *aij; |
---|
| 284 | #endif |
---|
| 285 | if (row->name != NULL) |
---|
| 286 | dmp_free_atom(npp->pool, row->name, strlen(row->name)+1); |
---|
| 287 | #if 0 /* 23/XII-2009 */ |
---|
| 288 | while (row->ptr != NULL) |
---|
| 289 | { aij = row->ptr; |
---|
| 290 | row->ptr = aij->r_next; |
---|
| 291 | if (aij->c_prev == NULL) |
---|
| 292 | aij->col->ptr = aij->c_next; |
---|
| 293 | else |
---|
| 294 | aij->c_prev->c_next = aij->c_next; |
---|
| 295 | if (aij->c_next == NULL) |
---|
| 296 | ; |
---|
| 297 | else |
---|
| 298 | aij->c_next->c_prev = aij->c_prev; |
---|
| 299 | dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ)); |
---|
| 300 | } |
---|
| 301 | #else |
---|
| 302 | npp_erase_row(npp, row); |
---|
| 303 | #endif |
---|
| 304 | npp_remove_row(npp, row); |
---|
| 305 | dmp_free_atom(npp->pool, row, sizeof(NPPROW)); |
---|
| 306 | return; |
---|
| 307 | } |
---|
| 308 | |
---|
| 309 | void npp_del_col(NPP *npp, NPPCOL *col) |
---|
| 310 | { /* remove column from the current problem */ |
---|
| 311 | NPPAIJ *aij; |
---|
| 312 | if (col->name != NULL) |
---|
| 313 | dmp_free_atom(npp->pool, col->name, strlen(col->name)+1); |
---|
| 314 | while (col->ptr != NULL) |
---|
| 315 | { aij = col->ptr; |
---|
| 316 | col->ptr = aij->c_next; |
---|
| 317 | if (aij->r_prev == NULL) |
---|
| 318 | aij->row->ptr = aij->r_next; |
---|
| 319 | else |
---|
| 320 | aij->r_prev->r_next = aij->r_next; |
---|
| 321 | if (aij->r_next == NULL) |
---|
| 322 | ; |
---|
| 323 | else |
---|
| 324 | aij->r_next->r_prev = aij->r_prev; |
---|
| 325 | dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ)); |
---|
| 326 | } |
---|
| 327 | npp_remove_col(npp, col); |
---|
| 328 | dmp_free_atom(npp->pool, col, sizeof(NPPCOL)); |
---|
| 329 | return; |
---|
| 330 | } |
---|
| 331 | |
---|
| 332 | void npp_del_aij(NPP *npp, NPPAIJ *aij) |
---|
| 333 | { /* remove element from the constraint matrix */ |
---|
| 334 | if (aij->r_prev == NULL) |
---|
| 335 | aij->row->ptr = aij->r_next; |
---|
| 336 | else |
---|
| 337 | aij->r_prev->r_next = aij->r_next; |
---|
| 338 | if (aij->r_next == NULL) |
---|
| 339 | ; |
---|
| 340 | else |
---|
| 341 | aij->r_next->r_prev = aij->r_prev; |
---|
| 342 | if (aij->c_prev == NULL) |
---|
| 343 | aij->col->ptr = aij->c_next; |
---|
| 344 | else |
---|
| 345 | aij->c_prev->c_next = aij->c_next; |
---|
| 346 | if (aij->c_next == NULL) |
---|
| 347 | ; |
---|
| 348 | else |
---|
| 349 | aij->c_next->c_prev = aij->c_prev; |
---|
| 350 | dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ)); |
---|
| 351 | return; |
---|
| 352 | } |
---|
| 353 | |
---|
| 354 | void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol, |
---|
| 355 | int scaling) |
---|
| 356 | { /* load original problem into the preprocessor workspace */ |
---|
| 357 | int m = orig->m; |
---|
| 358 | int n = orig->n; |
---|
| 359 | NPPROW **link; |
---|
| 360 | int i, j; |
---|
| 361 | double dir; |
---|
| 362 | xassert(names == GLP_OFF || names == GLP_ON); |
---|
| 363 | xassert(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP); |
---|
| 364 | xassert(scaling == GLP_OFF || scaling == GLP_ON); |
---|
| 365 | if (sol == GLP_MIP) xassert(!scaling); |
---|
| 366 | npp->orig_dir = orig->dir; |
---|
| 367 | if (npp->orig_dir == GLP_MIN) |
---|
| 368 | dir = +1.0; |
---|
| 369 | else if (npp->orig_dir == GLP_MAX) |
---|
| 370 | dir = -1.0; |
---|
| 371 | else |
---|
| 372 | xassert(npp != npp); |
---|
| 373 | npp->orig_m = m; |
---|
| 374 | npp->orig_n = n; |
---|
| 375 | npp->orig_nnz = orig->nnz; |
---|
| 376 | if (names && orig->name != NULL) |
---|
| 377 | { npp->name = dmp_get_atom(npp->pool, strlen(orig->name)+1); |
---|
| 378 | strcpy(npp->name, orig->name); |
---|
| 379 | } |
---|
| 380 | if (names && orig->obj != NULL) |
---|
| 381 | { npp->obj = dmp_get_atom(npp->pool, strlen(orig->obj)+1); |
---|
| 382 | strcpy(npp->obj, orig->obj); |
---|
| 383 | } |
---|
| 384 | npp->c0 = dir * orig->c0; |
---|
| 385 | /* load rows */ |
---|
| 386 | link = xcalloc(1+m, sizeof(NPPROW *)); |
---|
| 387 | for (i = 1; i <= m; i++) |
---|
| 388 | { GLPROW *rrr = orig->row[i]; |
---|
| 389 | NPPROW *row; |
---|
| 390 | link[i] = row = npp_add_row(npp); |
---|
| 391 | xassert(row->i == i); |
---|
| 392 | if (names && rrr->name != NULL) |
---|
| 393 | { row->name = dmp_get_atom(npp->pool, strlen(rrr->name)+1); |
---|
| 394 | strcpy(row->name, rrr->name); |
---|
| 395 | } |
---|
| 396 | if (!scaling) |
---|
| 397 | { if (rrr->type == GLP_FR) |
---|
| 398 | row->lb = -DBL_MAX, row->ub = +DBL_MAX; |
---|
| 399 | else if (rrr->type == GLP_LO) |
---|
| 400 | row->lb = rrr->lb, row->ub = +DBL_MAX; |
---|
| 401 | else if (rrr->type == GLP_UP) |
---|
| 402 | row->lb = -DBL_MAX, row->ub = rrr->ub; |
---|
| 403 | else if (rrr->type == GLP_DB) |
---|
| 404 | row->lb = rrr->lb, row->ub = rrr->ub; |
---|
| 405 | else if (rrr->type == GLP_FX) |
---|
| 406 | row->lb = row->ub = rrr->lb; |
---|
| 407 | else |
---|
| 408 | xassert(rrr != rrr); |
---|
| 409 | } |
---|
| 410 | else |
---|
| 411 | { double rii = rrr->rii; |
---|
| 412 | if (rrr->type == GLP_FR) |
---|
| 413 | row->lb = -DBL_MAX, row->ub = +DBL_MAX; |
---|
| 414 | else if (rrr->type == GLP_LO) |
---|
| 415 | row->lb = rrr->lb * rii, row->ub = +DBL_MAX; |
---|
| 416 | else if (rrr->type == GLP_UP) |
---|
| 417 | row->lb = -DBL_MAX, row->ub = rrr->ub * rii; |
---|
| 418 | else if (rrr->type == GLP_DB) |
---|
| 419 | row->lb = rrr->lb * rii, row->ub = rrr->ub * rii; |
---|
| 420 | else if (rrr->type == GLP_FX) |
---|
| 421 | row->lb = row->ub = rrr->lb * rii; |
---|
| 422 | else |
---|
| 423 | xassert(rrr != rrr); |
---|
| 424 | } |
---|
| 425 | } |
---|
| 426 | /* load columns and constraint coefficients */ |
---|
| 427 | for (j = 1; j <= n; j++) |
---|
| 428 | { GLPCOL *ccc = orig->col[j]; |
---|
| 429 | GLPAIJ *aaa; |
---|
| 430 | NPPCOL *col; |
---|
| 431 | col = npp_add_col(npp); |
---|
| 432 | xassert(col->j == j); |
---|
| 433 | if (names && ccc->name != NULL) |
---|
| 434 | { col->name = dmp_get_atom(npp->pool, strlen(ccc->name)+1); |
---|
| 435 | strcpy(col->name, ccc->name); |
---|
| 436 | } |
---|
| 437 | if (sol == GLP_MIP) |
---|
| 438 | #if 0 |
---|
| 439 | col->kind = ccc->kind; |
---|
| 440 | #else |
---|
| 441 | col->is_int = (char)(ccc->kind == GLP_IV); |
---|
| 442 | #endif |
---|
| 443 | if (!scaling) |
---|
| 444 | { if (ccc->type == GLP_FR) |
---|
| 445 | col->lb = -DBL_MAX, col->ub = +DBL_MAX; |
---|
| 446 | else if (ccc->type == GLP_LO) |
---|
| 447 | col->lb = ccc->lb, col->ub = +DBL_MAX; |
---|
| 448 | else if (ccc->type == GLP_UP) |
---|
| 449 | col->lb = -DBL_MAX, col->ub = ccc->ub; |
---|
| 450 | else if (ccc->type == GLP_DB) |
---|
| 451 | col->lb = ccc->lb, col->ub = ccc->ub; |
---|
| 452 | else if (ccc->type == GLP_FX) |
---|
| 453 | col->lb = col->ub = ccc->lb; |
---|
| 454 | else |
---|
| 455 | xassert(ccc != ccc); |
---|
| 456 | col->coef = dir * ccc->coef; |
---|
| 457 | for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next) |
---|
| 458 | npp_add_aij(npp, link[aaa->row->i], col, aaa->val); |
---|
| 459 | } |
---|
| 460 | else |
---|
| 461 | { double sjj = ccc->sjj; |
---|
| 462 | if (ccc->type == GLP_FR) |
---|
| 463 | col->lb = -DBL_MAX, col->ub = +DBL_MAX; |
---|
| 464 | else if (ccc->type == GLP_LO) |
---|
| 465 | col->lb = ccc->lb / sjj, col->ub = +DBL_MAX; |
---|
| 466 | else if (ccc->type == GLP_UP) |
---|
| 467 | col->lb = -DBL_MAX, col->ub = ccc->ub / sjj; |
---|
| 468 | else if (ccc->type == GLP_DB) |
---|
| 469 | col->lb = ccc->lb / sjj, col->ub = ccc->ub / sjj; |
---|
| 470 | else if (ccc->type == GLP_FX) |
---|
| 471 | col->lb = col->ub = ccc->lb / sjj; |
---|
| 472 | else |
---|
| 473 | xassert(ccc != ccc); |
---|
| 474 | col->coef = dir * ccc->coef * sjj; |
---|
| 475 | for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next) |
---|
| 476 | npp_add_aij(npp, link[aaa->row->i], col, |
---|
| 477 | aaa->row->rii * aaa->val * sjj); |
---|
| 478 | } |
---|
| 479 | } |
---|
| 480 | xfree(link); |
---|
| 481 | /* keep solution indicator and scaling option */ |
---|
| 482 | npp->sol = sol; |
---|
| 483 | npp->scaling = scaling; |
---|
| 484 | return; |
---|
| 485 | } |
---|
| 486 | |
---|
| 487 | void npp_build_prob(NPP *npp, glp_prob *prob) |
---|
| 488 | { /* build resultant (preprocessed) problem */ |
---|
| 489 | NPPROW *row; |
---|
| 490 | NPPCOL *col; |
---|
| 491 | NPPAIJ *aij; |
---|
| 492 | int i, j, type, len, *ind; |
---|
| 493 | double dir, *val; |
---|
| 494 | glp_erase_prob(prob); |
---|
| 495 | glp_set_prob_name(prob, npp->name); |
---|
| 496 | glp_set_obj_name(prob, npp->obj); |
---|
| 497 | glp_set_obj_dir(prob, npp->orig_dir); |
---|
| 498 | if (npp->orig_dir == GLP_MIN) |
---|
| 499 | dir = +1.0; |
---|
| 500 | else if (npp->orig_dir == GLP_MAX) |
---|
| 501 | dir = -1.0; |
---|
| 502 | else |
---|
| 503 | xassert(npp != npp); |
---|
| 504 | glp_set_obj_coef(prob, 0, dir * npp->c0); |
---|
| 505 | /* build rows */ |
---|
| 506 | for (row = npp->r_head; row != NULL; row = row->next) |
---|
| 507 | { row->temp = i = glp_add_rows(prob, 1); |
---|
| 508 | glp_set_row_name(prob, i, row->name); |
---|
| 509 | if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) |
---|
| 510 | type = GLP_FR; |
---|
| 511 | else if (row->ub == +DBL_MAX) |
---|
| 512 | type = GLP_LO; |
---|
| 513 | else if (row->lb == -DBL_MAX) |
---|
| 514 | type = GLP_UP; |
---|
| 515 | else if (row->lb != row->ub) |
---|
| 516 | type = GLP_DB; |
---|
| 517 | else |
---|
| 518 | type = GLP_FX; |
---|
| 519 | glp_set_row_bnds(prob, i, type, row->lb, row->ub); |
---|
| 520 | } |
---|
| 521 | /* build columns and the constraint matrix */ |
---|
| 522 | ind = xcalloc(1+prob->m, sizeof(int)); |
---|
| 523 | val = xcalloc(1+prob->m, sizeof(double)); |
---|
| 524 | for (col = npp->c_head; col != NULL; col = col->next) |
---|
| 525 | { j = glp_add_cols(prob, 1); |
---|
| 526 | glp_set_col_name(prob, j, col->name); |
---|
| 527 | #if 0 |
---|
| 528 | glp_set_col_kind(prob, j, col->kind); |
---|
| 529 | #else |
---|
| 530 | glp_set_col_kind(prob, j, col->is_int ? GLP_IV : GLP_CV); |
---|
| 531 | #endif |
---|
| 532 | if (col->lb == -DBL_MAX && col->ub == +DBL_MAX) |
---|
| 533 | type = GLP_FR; |
---|
| 534 | else if (col->ub == +DBL_MAX) |
---|
| 535 | type = GLP_LO; |
---|
| 536 | else if (col->lb == -DBL_MAX) |
---|
| 537 | type = GLP_UP; |
---|
| 538 | else if (col->lb != col->ub) |
---|
| 539 | type = GLP_DB; |
---|
| 540 | else |
---|
| 541 | type = GLP_FX; |
---|
| 542 | glp_set_col_bnds(prob, j, type, col->lb, col->ub); |
---|
| 543 | glp_set_obj_coef(prob, j, dir * col->coef); |
---|
| 544 | len = 0; |
---|
| 545 | for (aij = col->ptr; aij != NULL; aij = aij->c_next) |
---|
| 546 | { len++; |
---|
| 547 | ind[len] = aij->row->temp; |
---|
| 548 | val[len] = aij->val; |
---|
| 549 | } |
---|
| 550 | glp_set_mat_col(prob, j, len, ind, val); |
---|
| 551 | } |
---|
| 552 | xfree(ind); |
---|
| 553 | xfree(val); |
---|
| 554 | /* resultant problem has been built */ |
---|
| 555 | npp->m = prob->m; |
---|
| 556 | npp->n = prob->n; |
---|
| 557 | npp->nnz = prob->nnz; |
---|
| 558 | npp->row_ref = xcalloc(1+npp->m, sizeof(int)); |
---|
| 559 | npp->col_ref = xcalloc(1+npp->n, sizeof(int)); |
---|
| 560 | for (row = npp->r_head, i = 0; row != NULL; row = row->next) |
---|
| 561 | npp->row_ref[++i] = row->i; |
---|
| 562 | for (col = npp->c_head, j = 0; col != NULL; col = col->next) |
---|
| 563 | npp->col_ref[++j] = col->j; |
---|
| 564 | /* transformed problem segment is no longer needed */ |
---|
| 565 | dmp_delete_pool(npp->pool), npp->pool = NULL; |
---|
| 566 | npp->name = npp->obj = NULL; |
---|
| 567 | npp->c0 = 0.0; |
---|
| 568 | npp->r_head = npp->r_tail = NULL; |
---|
| 569 | npp->c_head = npp->c_tail = NULL; |
---|
| 570 | return; |
---|
| 571 | } |
---|
| 572 | |
---|
| 573 | void npp_postprocess(NPP *npp, glp_prob *prob) |
---|
| 574 | { /* postprocess solution from the resultant problem */ |
---|
| 575 | GLPROW *row; |
---|
| 576 | GLPCOL *col; |
---|
| 577 | NPPTSE *tse; |
---|
| 578 | int i, j, k; |
---|
| 579 | double dir; |
---|
| 580 | xassert(npp->orig_dir == prob->dir); |
---|
| 581 | if (npp->orig_dir == GLP_MIN) |
---|
| 582 | dir = +1.0; |
---|
| 583 | else if (npp->orig_dir == GLP_MAX) |
---|
| 584 | dir = -1.0; |
---|
| 585 | else |
---|
| 586 | xassert(npp != npp); |
---|
| 587 | xassert(npp->m == prob->m); |
---|
| 588 | xassert(npp->n == prob->n); |
---|
| 589 | xassert(npp->nnz == prob->nnz); |
---|
| 590 | /* copy solution status */ |
---|
| 591 | if (npp->sol == GLP_SOL) |
---|
| 592 | { npp->p_stat = prob->pbs_stat; |
---|
| 593 | npp->d_stat = prob->dbs_stat; |
---|
| 594 | } |
---|
| 595 | else if (npp->sol == GLP_IPT) |
---|
| 596 | npp->t_stat = prob->ipt_stat; |
---|
| 597 | else if (npp->sol == GLP_MIP) |
---|
| 598 | npp->i_stat = prob->mip_stat; |
---|
| 599 | else |
---|
| 600 | xassert(npp != npp); |
---|
| 601 | /* allocate solution arrays */ |
---|
| 602 | if (npp->sol == GLP_SOL) |
---|
| 603 | { if (npp->r_stat == NULL) |
---|
| 604 | npp->r_stat = xcalloc(1+npp->nrows, sizeof(char)); |
---|
| 605 | for (i = 1; i <= npp->nrows; i++) |
---|
| 606 | npp->r_stat[i] = 0; |
---|
| 607 | if (npp->c_stat == NULL) |
---|
| 608 | npp->c_stat = xcalloc(1+npp->ncols, sizeof(char)); |
---|
| 609 | for (j = 1; j <= npp->ncols; j++) |
---|
| 610 | npp->c_stat[j] = 0; |
---|
| 611 | } |
---|
| 612 | #if 0 |
---|
| 613 | if (npp->r_prim == NULL) |
---|
| 614 | npp->r_prim = xcalloc(1+npp->nrows, sizeof(double)); |
---|
| 615 | for (i = 1; i <= npp->nrows; i++) |
---|
| 616 | npp->r_prim[i] = DBL_MAX; |
---|
| 617 | #endif |
---|
| 618 | if (npp->c_value == NULL) |
---|
| 619 | npp->c_value = xcalloc(1+npp->ncols, sizeof(double)); |
---|
| 620 | for (j = 1; j <= npp->ncols; j++) |
---|
| 621 | npp->c_value[j] = DBL_MAX; |
---|
| 622 | if (npp->sol != GLP_MIP) |
---|
| 623 | { if (npp->r_pi == NULL) |
---|
| 624 | npp->r_pi = xcalloc(1+npp->nrows, sizeof(double)); |
---|
| 625 | for (i = 1; i <= npp->nrows; i++) |
---|
| 626 | npp->r_pi[i] = DBL_MAX; |
---|
| 627 | #if 0 |
---|
| 628 | if (npp->c_dual == NULL) |
---|
| 629 | npp->c_dual = xcalloc(1+npp->ncols, sizeof(double)); |
---|
| 630 | for (j = 1; j <= npp->ncols; j++) |
---|
| 631 | npp->c_dual[j] = DBL_MAX; |
---|
| 632 | #endif |
---|
| 633 | } |
---|
| 634 | /* copy solution components from the resultant problem */ |
---|
| 635 | if (npp->sol == GLP_SOL) |
---|
| 636 | { for (i = 1; i <= npp->m; i++) |
---|
| 637 | { row = prob->row[i]; |
---|
| 638 | k = npp->row_ref[i]; |
---|
| 639 | npp->r_stat[k] = (char)row->stat; |
---|
| 640 | /*npp->r_prim[k] = row->prim;*/ |
---|
| 641 | npp->r_pi[k] = dir * row->dual; |
---|
| 642 | } |
---|
| 643 | for (j = 1; j <= npp->n; j++) |
---|
| 644 | { col = prob->col[j]; |
---|
| 645 | k = npp->col_ref[j]; |
---|
| 646 | npp->c_stat[k] = (char)col->stat; |
---|
| 647 | npp->c_value[k] = col->prim; |
---|
| 648 | /*npp->c_dual[k] = dir * col->dual;*/ |
---|
| 649 | } |
---|
| 650 | } |
---|
| 651 | else if (npp->sol == GLP_IPT) |
---|
| 652 | { for (i = 1; i <= npp->m; i++) |
---|
| 653 | { row = prob->row[i]; |
---|
| 654 | k = npp->row_ref[i]; |
---|
| 655 | /*npp->r_prim[k] = row->pval;*/ |
---|
| 656 | npp->r_pi[k] = dir * row->dval; |
---|
| 657 | } |
---|
| 658 | for (j = 1; j <= npp->n; j++) |
---|
| 659 | { col = prob->col[j]; |
---|
| 660 | k = npp->col_ref[j]; |
---|
| 661 | npp->c_value[k] = col->pval; |
---|
| 662 | /*npp->c_dual[k] = dir * col->dval;*/ |
---|
| 663 | } |
---|
| 664 | } |
---|
| 665 | else if (npp->sol == GLP_MIP) |
---|
| 666 | { |
---|
| 667 | #if 0 |
---|
| 668 | for (i = 1; i <= npp->m; i++) |
---|
| 669 | { row = prob->row[i]; |
---|
| 670 | k = npp->row_ref[i]; |
---|
| 671 | /*npp->r_prim[k] = row->mipx;*/ |
---|
| 672 | } |
---|
| 673 | #endif |
---|
| 674 | for (j = 1; j <= npp->n; j++) |
---|
| 675 | { col = prob->col[j]; |
---|
| 676 | k = npp->col_ref[j]; |
---|
| 677 | npp->c_value[k] = col->mipx; |
---|
| 678 | } |
---|
| 679 | } |
---|
| 680 | else |
---|
| 681 | xassert(npp != npp); |
---|
| 682 | /* perform postprocessing to construct solution to the original |
---|
| 683 | problem */ |
---|
| 684 | for (tse = npp->top; tse != NULL; tse = tse->link) |
---|
| 685 | { xassert(tse->func != NULL); |
---|
| 686 | xassert(tse->func(npp, tse->info) == 0); |
---|
| 687 | } |
---|
| 688 | return; |
---|
| 689 | } |
---|
| 690 | |
---|
| 691 | void npp_unload_sol(NPP *npp, glp_prob *orig) |
---|
| 692 | { /* store solution to the original problem */ |
---|
| 693 | GLPROW *row; |
---|
| 694 | GLPCOL *col; |
---|
| 695 | int i, j; |
---|
| 696 | double dir; |
---|
| 697 | xassert(npp->orig_dir == orig->dir); |
---|
| 698 | if (npp->orig_dir == GLP_MIN) |
---|
| 699 | dir = +1.0; |
---|
| 700 | else if (npp->orig_dir == GLP_MAX) |
---|
| 701 | dir = -1.0; |
---|
| 702 | else |
---|
| 703 | xassert(npp != npp); |
---|
| 704 | xassert(npp->orig_m == orig->m); |
---|
| 705 | xassert(npp->orig_n == orig->n); |
---|
| 706 | xassert(npp->orig_nnz == orig->nnz); |
---|
| 707 | if (npp->sol == GLP_SOL) |
---|
| 708 | { /* store basic solution */ |
---|
| 709 | orig->valid = 0; |
---|
| 710 | orig->pbs_stat = npp->p_stat; |
---|
| 711 | orig->dbs_stat = npp->d_stat; |
---|
| 712 | orig->obj_val = orig->c0; |
---|
| 713 | orig->some = 0; |
---|
| 714 | for (i = 1; i <= orig->m; i++) |
---|
| 715 | { row = orig->row[i]; |
---|
| 716 | row->stat = npp->r_stat[i]; |
---|
| 717 | if (!npp->scaling) |
---|
| 718 | { /*row->prim = npp->r_prim[i];*/ |
---|
| 719 | row->dual = dir * npp->r_pi[i]; |
---|
| 720 | } |
---|
| 721 | else |
---|
| 722 | { /*row->prim = npp->r_prim[i] / row->rii;*/ |
---|
| 723 | row->dual = dir * npp->r_pi[i] * row->rii; |
---|
| 724 | } |
---|
| 725 | if (row->stat == GLP_BS) |
---|
| 726 | row->dual = 0.0; |
---|
| 727 | else if (row->stat == GLP_NL) |
---|
| 728 | { xassert(row->type == GLP_LO || row->type == GLP_DB); |
---|
| 729 | row->prim = row->lb; |
---|
| 730 | } |
---|
| 731 | else if (row->stat == GLP_NU) |
---|
| 732 | { xassert(row->type == GLP_UP || row->type == GLP_DB); |
---|
| 733 | row->prim = row->ub; |
---|
| 734 | } |
---|
| 735 | else if (row->stat == GLP_NF) |
---|
| 736 | { xassert(row->type == GLP_FR); |
---|
| 737 | row->prim = 0.0; |
---|
| 738 | } |
---|
| 739 | else if (row->stat == GLP_NS) |
---|
| 740 | { xassert(row->type == GLP_FX); |
---|
| 741 | row->prim = row->lb; |
---|
| 742 | } |
---|
| 743 | else |
---|
| 744 | xassert(row != row); |
---|
| 745 | } |
---|
| 746 | for (j = 1; j <= orig->n; j++) |
---|
| 747 | { col = orig->col[j]; |
---|
| 748 | col->stat = npp->c_stat[j]; |
---|
| 749 | if (!npp->scaling) |
---|
| 750 | { col->prim = npp->c_value[j]; |
---|
| 751 | /*col->dual = dir * npp->c_dual[j];*/ |
---|
| 752 | } |
---|
| 753 | else |
---|
| 754 | { col->prim = npp->c_value[j] * col->sjj; |
---|
| 755 | /*col->dual = dir * npp->c_dual[j] / col->sjj;*/ |
---|
| 756 | } |
---|
| 757 | if (col->stat == GLP_BS) |
---|
| 758 | col->dual = 0.0; |
---|
| 759 | #if 1 |
---|
| 760 | else if (col->stat == GLP_NL) |
---|
| 761 | { xassert(col->type == GLP_LO || col->type == GLP_DB); |
---|
| 762 | col->prim = col->lb; |
---|
| 763 | } |
---|
| 764 | else if (col->stat == GLP_NU) |
---|
| 765 | { xassert(col->type == GLP_UP || col->type == GLP_DB); |
---|
| 766 | col->prim = col->ub; |
---|
| 767 | } |
---|
| 768 | else if (col->stat == GLP_NF) |
---|
| 769 | { xassert(col->type == GLP_FR); |
---|
| 770 | col->prim = 0.0; |
---|
| 771 | } |
---|
| 772 | else if (col->stat == GLP_NS) |
---|
| 773 | { xassert(col->type == GLP_FX); |
---|
| 774 | col->prim = col->lb; |
---|
| 775 | } |
---|
| 776 | else |
---|
| 777 | xassert(col != col); |
---|
| 778 | #endif |
---|
| 779 | orig->obj_val += col->coef * col->prim; |
---|
| 780 | } |
---|
| 781 | #if 1 |
---|
| 782 | /* compute primal values of inactive rows */ |
---|
| 783 | for (i = 1; i <= orig->m; i++) |
---|
| 784 | { row = orig->row[i]; |
---|
| 785 | if (row->stat == GLP_BS) |
---|
| 786 | { GLPAIJ *aij; |
---|
| 787 | double temp; |
---|
| 788 | temp = 0.0; |
---|
| 789 | for (aij = row->ptr; aij != NULL; aij = aij->r_next) |
---|
| 790 | temp += aij->val * aij->col->prim; |
---|
| 791 | row->prim = temp; |
---|
| 792 | } |
---|
| 793 | } |
---|
| 794 | /* compute reduced costs of active columns */ |
---|
| 795 | for (j = 1; j <= orig->n; j++) |
---|
| 796 | { col = orig->col[j]; |
---|
| 797 | if (col->stat != GLP_BS) |
---|
| 798 | { GLPAIJ *aij; |
---|
| 799 | double temp; |
---|
| 800 | temp = col->coef; |
---|
| 801 | for (aij = col->ptr; aij != NULL; aij = aij->c_next) |
---|
| 802 | temp -= aij->val * aij->row->dual; |
---|
| 803 | col->dual = temp; |
---|
| 804 | } |
---|
| 805 | } |
---|
| 806 | #endif |
---|
| 807 | } |
---|
| 808 | else if (npp->sol == GLP_IPT) |
---|
| 809 | { /* store interior-point solution */ |
---|
| 810 | orig->ipt_stat = npp->t_stat; |
---|
| 811 | orig->ipt_obj = orig->c0; |
---|
| 812 | for (i = 1; i <= orig->m; i++) |
---|
| 813 | { row = orig->row[i]; |
---|
| 814 | if (!npp->scaling) |
---|
| 815 | { /*row->pval = npp->r_prim[i];*/ |
---|
| 816 | row->dval = dir * npp->r_pi[i]; |
---|
| 817 | } |
---|
| 818 | else |
---|
| 819 | { /*row->pval = npp->r_prim[i] / row->rii;*/ |
---|
| 820 | row->dval = dir * npp->r_pi[i] * row->rii; |
---|
| 821 | } |
---|
| 822 | } |
---|
| 823 | for (j = 1; j <= orig->n; j++) |
---|
| 824 | { col = orig->col[j]; |
---|
| 825 | if (!npp->scaling) |
---|
| 826 | { col->pval = npp->c_value[j]; |
---|
| 827 | /*col->dval = dir * npp->c_dual[j];*/ |
---|
| 828 | } |
---|
| 829 | else |
---|
| 830 | { col->pval = npp->c_value[j] * col->sjj; |
---|
| 831 | /*col->dval = dir * npp->c_dual[j] / col->sjj;*/ |
---|
| 832 | } |
---|
| 833 | orig->ipt_obj += col->coef * col->pval; |
---|
| 834 | } |
---|
| 835 | #if 1 |
---|
| 836 | /* compute row primal values */ |
---|
| 837 | for (i = 1; i <= orig->m; i++) |
---|
| 838 | { row = orig->row[i]; |
---|
| 839 | { GLPAIJ *aij; |
---|
| 840 | double temp; |
---|
| 841 | temp = 0.0; |
---|
| 842 | for (aij = row->ptr; aij != NULL; aij = aij->r_next) |
---|
| 843 | temp += aij->val * aij->col->pval; |
---|
| 844 | row->pval = temp; |
---|
| 845 | } |
---|
| 846 | } |
---|
| 847 | /* compute column dual values */ |
---|
| 848 | for (j = 1; j <= orig->n; j++) |
---|
| 849 | { col = orig->col[j]; |
---|
| 850 | { GLPAIJ *aij; |
---|
| 851 | double temp; |
---|
| 852 | temp = col->coef; |
---|
| 853 | for (aij = col->ptr; aij != NULL; aij = aij->c_next) |
---|
| 854 | temp -= aij->val * aij->row->dval; |
---|
| 855 | col->dval = temp; |
---|
| 856 | } |
---|
| 857 | } |
---|
| 858 | #endif |
---|
| 859 | } |
---|
| 860 | else if (npp->sol == GLP_MIP) |
---|
| 861 | { /* store MIP solution */ |
---|
| 862 | xassert(!npp->scaling); |
---|
| 863 | orig->mip_stat = npp->i_stat; |
---|
| 864 | orig->mip_obj = orig->c0; |
---|
| 865 | #if 0 |
---|
| 866 | for (i = 1; i <= orig->m; i++) |
---|
| 867 | { row = orig->row[i]; |
---|
| 868 | /*row->mipx = npp->r_prim[i];*/ |
---|
| 869 | } |
---|
| 870 | #endif |
---|
| 871 | for (j = 1; j <= orig->n; j++) |
---|
| 872 | { col = orig->col[j]; |
---|
| 873 | col->mipx = npp->c_value[j]; |
---|
| 874 | if (col->kind == GLP_IV) |
---|
| 875 | xassert(col->mipx == floor(col->mipx)); |
---|
| 876 | orig->mip_obj += col->coef * col->mipx; |
---|
| 877 | } |
---|
| 878 | #if 1 |
---|
| 879 | /* compute row primal values */ |
---|
| 880 | for (i = 1; i <= orig->m; i++) |
---|
| 881 | { row = orig->row[i]; |
---|
| 882 | { GLPAIJ *aij; |
---|
| 883 | double temp; |
---|
| 884 | temp = 0.0; |
---|
| 885 | for (aij = row->ptr; aij != NULL; aij = aij->r_next) |
---|
| 886 | temp += aij->val * aij->col->mipx; |
---|
| 887 | row->mipx = temp; |
---|
| 888 | } |
---|
| 889 | } |
---|
| 890 | #endif |
---|
| 891 | } |
---|
| 892 | else |
---|
| 893 | xassert(npp != npp); |
---|
| 894 | return; |
---|
| 895 | } |
---|
| 896 | |
---|
| 897 | void npp_delete_wksp(NPP *npp) |
---|
| 898 | { /* delete LP/MIP preprocessor workspace */ |
---|
| 899 | if (npp->pool != NULL) |
---|
| 900 | dmp_delete_pool(npp->pool); |
---|
| 901 | if (npp->stack != NULL) |
---|
| 902 | dmp_delete_pool(npp->stack); |
---|
| 903 | if (npp->row_ref != NULL) |
---|
| 904 | xfree(npp->row_ref); |
---|
| 905 | if (npp->col_ref != NULL) |
---|
| 906 | xfree(npp->col_ref); |
---|
| 907 | if (npp->r_stat != NULL) |
---|
| 908 | xfree(npp->r_stat); |
---|
| 909 | #if 0 |
---|
| 910 | if (npp->r_prim != NULL) |
---|
| 911 | xfree(npp->r_prim); |
---|
| 912 | #endif |
---|
| 913 | if (npp->r_pi != NULL) |
---|
| 914 | xfree(npp->r_pi); |
---|
| 915 | if (npp->c_stat != NULL) |
---|
| 916 | xfree(npp->c_stat); |
---|
| 917 | if (npp->c_value != NULL) |
---|
| 918 | xfree(npp->c_value); |
---|
| 919 | #if 0 |
---|
| 920 | if (npp->c_dual != NULL) |
---|
| 921 | xfree(npp->c_dual); |
---|
| 922 | #endif |
---|
| 923 | xfree(npp); |
---|
| 924 | return; |
---|
| 925 | } |
---|
| 926 | |
---|
| 927 | /* eof */ |
---|