/[ascend]/trunk/ascend4/solver/slv0.c
ViewVC logotype

Contents of /trunk/ascend4/solver/slv0.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations) (download) (as text)
Fri Nov 5 21:21:36 2004 UTC (18 years, 6 months ago) by aw0a
File MIME type: text/x-csrc
File size: 106392 byte(s)
corrected runaway minor loop problem exposed by Helder
1 /*
2 * SLV: Ascend Nonlinear Solver
3 * by Karl Michael Westerberg
4 * Created: 2/6/90
5 * Version: $Revision: 1.33 $
6 * Version control file: $RCSfile: slv0.c,v $
7 * Date last modified: $Date: 2000/01/25 02:27:16 $
8 * Last modified by: $Author: ballan $
9 *
10 * This file is part of the SLV solver.
11 *
12 * Copyright (C) 1990 Karl Michael Westerberg
13 * Copyright (C) 1993 Joseph Zaher
14 * Copyright (C) 1994 Joseph Zaher, Benjamin Andrew Allan
15 *
16 * The SLV solver is free software; you can redistribute
17 * it and/or modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation; either version 2 of the
19 * License, or (at your option) any later version.
20 *
21 * The SLV solver is distributed in hope that it will be
22 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with the program; if not, write to the Free Software Foundation,
28 * Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named
29 * COPYING. COPYING is found in ../compiler.
30 *
31 */
32
33 #include <stdarg.h>
34 #include "utilities/ascConfig.h"
35 #include "utilities/ascMalloc.h"
36 #include "utilities/ascPanic.h"
37 #include "general/list.h"
38 #include "utilities/set.h"
39 #include "general/tm_time.h"
40 #include "utilities/mem.h"
41 #include "solver/mtx.h"
42 #include "solver/linsol.h"
43 #include "solver/linsolqr.h"
44 #include "solver/slv_types.h"
45 #include "solver/var.h"
46 #include "solver/rel.h"
47 #include "solver/discrete.h"
48 #include "solver/conditional.h"
49 #include "solver/logrel.h"
50 #include "solver/bnd.h"
51 #include "solver/calc.h"
52 #include "solver/relman.h"
53 #include "solver/slv_common.h"
54 #include "solver/slv_client.h"
55 #include "solver/slv0.h"
56 #if !defined(STATIC_SLV) && !defined(DYNAMIC_SLV)
57 /* do nothing */
58 int slv0_register(SlvFunctionsT *f)
59 {
60 (void)f; /* stop gcc whine about unused parameter */
61
62 FPRINTF(stderr,"Slv not compiled in this ASCEND IV.\n");
63 return 1;
64 }
65 #else /* either STATIC_SLV or DYNAMIC_SLV is defined */
66 #ifdef DYNAMIC_SLV
67 /* do dynamic loading stuff. yeah, right */
68 #else /* following is used if STATIC_SLV is defined */
69
70
71 #define KILL 0
72 /* code that needs to be deleted compiles only with kill = 1 */
73 #define DEBUG TRUE
74
75 #define slv0_solver_name "Slv" /* Solver's name. don't mess with the caps!*/
76 #define slv0_solver_number 0 /* Solver's number */
77
78 #define SLV0(s) ((slv0_system_t)(s))
79
80 #define slv0_IA_SIZE 2
81 #define slv0_RA_SIZE 0
82 #define slv0_CA_SIZE 0
83 #define slv0_VA_SIZE 0
84
85 /* subscripts for ia */
86 #define SP0_LIFDS 0
87 #define SP0_SAVLIN 1
88
89 /*********************************************************************\
90 Subparameters implemented: (value/meaning)
91 sp.ia[SP0_LIFDS] 0=>do not show full detail info for singletons
92 1=>do (this value ignored if detailed solve info not on.
93 sp.ia[SP0_SAVLIN] 0=>do not append linearizations arising in the newton
94 scheme to the file SlvLinsol.dat.
95 1=>do.
96 \*********************************************************************/
97 struct update_data {
98 int jacobian; /* Countdown on jacobian updating */
99 int weights; /* Countdown on weights updating */
100 int nominals; /* Countdown on nominals updating */
101 };
102
103 struct jacobian_data {
104 linsol_system_t sys; /* Linear system */
105 mtx_matrix_t mtx; /* Transpose gradient of residuals */
106 real64 *rhs; /* RHS from linear system */
107 unsigned *varpivots; /* Pivoted variables */
108 unsigned *relpivots; /* Pivoted relations */
109 unsigned *subregions; /* Set of subregion indeces */
110 mtx_region_t reg; /* Current block region */
111 int32 rank; /* Numerical rank of the jacobian */
112 boolean accurate; /* ? Recalculate matrix */
113 boolean singular; /* ? Can matrix be inverted */
114 };
115
116 struct hessian_data {
117 struct vector_data Bs; /* Product of B and s */
118 struct vector_data y; /* Difference in stationaries */
119 real64 ys; /* inner product of y and s */
120 real64 sBs; /* inner product of s and Bs */
121 struct hessian_data *next; /* previous iteration data */
122 };
123
124 struct reduced_data {
125 real64 **mtx; /* Dense matrix */
126 real64 *ZBs; /* Reduced Bs */
127 real64 *Zy; /* Reduced y */
128 int32 order; /* Degrees of freedom */
129 boolean accurate; /* Ready to re-compute ? */
130 };
131
132 struct slv0_system_structure {
133
134 /**
135 *** Problem definition
136 **/
137 slv_system_t slv; /* slv_system_t back-link */
138 struct rel_relation *obj; /* Objective function: NULL = none */
139 struct var_variable **vlist; /* Variable list (NULL terminated) */
140 struct var_variable **vlist_user; /* User vlist (NULL=determine) */
141 struct rel_relation **rlist; /* Relation list (NULL terminated) */
142 struct rel_relation **rlist_user; /* User rlist (NULL = none) */
143 struct ExtRelCache **erlist; /* External relations cache list */
144 struct ExtRelCache **erlist_user; /* User erlist (NULL = none) */
145
146 /**
147 *** Solver information
148 **/
149 int integrity; /* ? Has the system been created */
150 slv_parameters_t p; /* Parameters */
151 slv_status_t s; /* Status (as of iteration end) */
152 struct update_data update; /* Jacobian frequency counters */
153 int32 cap; /* Order of matrix/vectors */
154 int32 rank; /* Symbolic rank of problem */
155 int32 vused; /* Free and incident variables */
156 int32 vtot; /* length of varlist */
157 int32 bused; /* Included boundaries */
158 int32 rused; /* Included relations */
159 int32 rtot; /* length of varlist */
160 double clock; /* CPU time */
161 int iarray[slv0_IA_SIZE];
162
163 /**
164 *** Calculated data (scaled)
165 **/
166 struct jacobian_data J; /* linearized system */
167 struct hessian_data *B; /* Curvature information */
168 struct reduced_data ZBZ; /* Reduced hessian */
169
170 struct vector_data nominals; /* Variable nominals */
171 struct vector_data weights; /* Relation weights */
172 struct vector_data variables; /* Variable values */
173 struct vector_data residuals; /* Relation residuals */
174 struct vector_data gradient; /* Objective gradient */
175 struct vector_data multipliers; /* Relation multipliers */
176 struct vector_data stationary; /* Lagrange gradient */
177 struct vector_data gamma; /* Feasibility steepest descent */
178 struct vector_data Jgamma; /* Product of J and gamma */
179 struct vector_data newton; /* Dependent variables */
180 struct vector_data Bnewton; /* Product of B and newton */
181 struct vector_data nullspace; /* Independent variables */
182 struct vector_data varstep1; /* 1st order in variables */
183 struct vector_data Bvarstep1; /* Product of B and varstep1 */
184 struct vector_data varstep2; /* 2nd order in variables */
185 struct vector_data Bvarstep2; /* Product of B and varstep2 */
186 struct vector_data mulstep1; /* 1st order in multipliers */
187 struct vector_data mulstep2; /* 2nd order in multipliers */
188 struct vector_data varstep; /* Step in variables */
189 struct vector_data mulstep; /* Step in multipliers */
190
191 real64 objective; /* Objective function evaluation */
192 real64 phi; /* Unconstrained minimizer */
193 real64 maxstep; /* Maximum step size allowed */
194 real64 progress; /* Steepest directional derivative */
195 };
196
197
198 /**
199 *** Integrity checks
200 *** ----------------
201 *** check_system(sys)
202 **/
203
204 #define OK ((int)813028392)
205 #define DESTROYED ((int)103289182)
206 static int check_system(sys)
207 slv0_system_t sys;
208 /**
209 *** Checks sys for NULL and for integrity.
210 **/
211 {
212 if( sys == NULL ) {
213 FPRINTF(stderr,"ERROR: (slv0) check_system\n");
214 FPRINTF(stderr," NULL system handle.\n");
215 return 1;
216 }
217
218 switch( sys->integrity ) {
219 case OK:
220 return 0;
221 case DESTROYED:
222 FPRINTF(stderr,"ERROR: (slv0) check_system\n");
223 FPRINTF(stderr," System was recently destroyed.\n");
224 return 1;
225 default:
226 FPRINTF(stderr,"ERROR: (slv0) check_system\n");
227 FPRINTF(stderr," System reused or never allocated.\n");
228 return 1;
229 }
230 }
231
232
233 /**
234 *** General input/output routines
235 *** -----------------------------
236 *** print_var_name(out,sys,var)
237 *** print_bnd_name(out,sys,bnd)
238 *** print_rel_name(out,sys,rel)
239 **/
240
241 #define print_var_name(a,b,c) slv_print_var_name((a),(b)->slv,(c))
242 #define print_rel_name(a,b,c) slv_print_rel_name((a),(b)->slv,(c))
243 #define print_bnd_name(a,b,c) slv_print_bnd_name((a),(c))
244
245 /**
246 *** Debug output routines
247 *** ---------------------
248 *** debug_delimiter(fp)
249 *** debug_out_vector(fp,vec)
250 *** debug_out_var_values(fp,sys)
251 *** debug_out_rel_residuals(fp,sys)
252 *** debug_out_jacobian(fp,sys)
253 *** debug_out_hessian(fp,sys)
254 *** debug_write_array(fp,real64 *,length)
255 **/
256
257 static void debug_delimiter(fp)
258 FILE *fp;
259 /**
260 *** Outputs a hyphenated line.
261 **/
262 {
263 int i;
264 for( i=0; i<60; i++ ) PUTC('-',fp);
265 PUTC('\n',fp);
266 }
267
268
269 static void debug_out_vector(fp,sys,vec)
270 FILE *fp;
271 slv0_system_t sys;
272 struct vector_data *vec;
273 /**
274 *** Outputs a vector.
275 **/
276 {
277 int32 ndx;
278 FPRINTF(fp,"Norm = %g, Accurate = %s, Vector range = %d to %d\n",
279 calc_sqrt_D0(vec->norm2), vec->accurate?"TRUE":"FALSE",
280 vec->rng->low,vec->rng->high);
281 FPRINTF(fp,"Vector --> ");
282 for( ndx=vec->rng->low ; ndx<=vec->rng->high ; ++ndx )
283 FPRINTF(fp, "%g ", vec->vec[ndx]);
284 PUTC('\n',fp);
285 }
286
287 static void debug_out_var_values(fp,sys)
288 FILE *fp;
289 slv0_system_t sys;
290 /**
291 *** Outputs all variable values in current block.
292 **/
293 {
294 int32 col;
295 int32 orig_col;
296
297 FPRINTF(fp,"Var values --> ");
298 for( col = sys->J.reg.col.low; col <= sys->J.reg.col.high ; col++ ) {
299 struct var_variable *var;
300 orig_col = mtx_col_to_org(sys->J.mtx,col);
301 var = sys->vlist[orig_col];
302 /* print_var_name(fp,sys,var); **** KAA_DEBUG */
303 FPRINTF(fp,"x[%d] = %12.8f\n", orig_col, var_value(var));
304 }
305 PUTC('\n',fp);
306 }
307
308 static void debug_out_rel_residuals(fp,sys)
309 FILE *fp;
310 slv0_system_t sys;
311 /**
312 *** Outputs all relation residuals in current block.
313 **/
314 {
315 int32 row;
316
317 FPRINTF(fp,"Rel residuals --> ");
318 for( row = sys->J.reg.row.low; row <= sys->J.reg.row.high ; row++ ) {
319 struct rel_relation *rel;
320 rel = sys->rlist[mtx_row_to_org(sys->J.mtx,row)];
321 print_rel_name(fp,sys,rel);
322 FPRINTF(fp,"=%g ",rel_residual(rel));
323 }
324 PUTC('\n',fp);
325 }
326
327 static void debug_out_jacobian(fp,sys)
328 FILE *fp;
329 slv0_system_t sys;
330 /**
331 *** Outputs permutation and values of the nonzero elements in the
332 *** the jacobian matrix.
333 **/
334 {
335 mtx_coord_t nz;
336 real64 value;
337
338 nz.row = sys->J.reg.row.low;
339 for( ; nz.row <= sys->J.reg.row.high; ++(nz.row) ) {
340 FPRINTF(fp," Row %d (rel %d)\n",
341 nz.row,
342 mtx_row_to_org(sys->J.mtx,nz.row));
343 nz.col = mtx_FIRST;
344 while( value = mtx_next_in_row(sys->J.mtx,&nz,&(sys->J.reg.col)),
345 nz.col != mtx_LAST )
346 FPRINTF(fp," Col %d (var %d) has value %g\n",
347 nz.col, mtx_col_to_org(sys->J.mtx,nz.col), value);
348 }
349 }
350
351 static void debug_out_hessian(fp,sys)
352 FILE *fp;
353 slv0_system_t sys;
354 /**
355 *** Outputs permutation and values of the nonzero elements in the
356 *** reduced hessian matrix.
357 **/
358 {
359 mtx_coord_t nz;
360
361 for( nz.row = 0; nz.row < sys->ZBZ.order; nz.row++ ) {
362 nz.col = nz.row + sys->J.reg.col.high + 1 - sys->ZBZ.order;
363 FPRINTF(fp," ZBZ[%d (var %d)] = ",
364 nz.row, mtx_col_to_org(sys->J.mtx,nz.col));
365 for( nz.col = 0; nz.col < sys->ZBZ.order; nz.col++ )
366 FPRINTF(fp,"%10g ",sys->ZBZ.mtx[nz.row][nz.col]);
367 PUTC('\n',fp);
368 }
369 }
370
371
372
373 static void debug_write_array(FILE *fp,real64 *vec, int32 length)
374 {
375 int32 i;
376 for (i=0; i< length;i++)
377 FPRINTF(fp,"%.20g\n",vec[i]);
378 }
379
380
381 static char savlinfilename[]="SlvLinsol.dat. \0";
382 static char savlinfilebase[]="SlvLinsol.dat.\0";
383 static int savlinnum=0;
384 /** The number to postfix to savlinfilebase. increases with file accesses. **/
385
386 /**
387 *** Array/vector operations
388 *** ----------------------------
389 *** destroy_array(p)
390 *** create_array(len,type)
391 *** zero_array(arr,len,type)
392 ***
393 *** zero_vector(vec)
394 *** copy_vector(vec1,vec2)
395 *** prod = inner_product(vec1,vec2)
396 *** norm2 = square_norm(vec)
397 *** matrix_product(mtx,vec,prod,scale,transpose)
398 **/
399
400 #define destroy_array(p) \
401 if( (p) != NULL ) ascfree((p))
402 #define create_array(len,type) \
403 ((len) > 0 ? (type *)ascmalloc((len)*sizeof(type)) : NULL)
404 #define create_zero_array(len,type) \
405 ((len) > 0 ? (type *)asccalloc((len),sizeof(type)) : NULL)
406 #define zero_array(arr,nelts,type) \
407 mem_zero_byte_cast((arr),0,(nelts)*sizeof(type))
408 /* Zeros an array of nelts objects, each having given type. */
409
410 #define zero_vector(v) slv_zero_vector(v)
411 #define copy_vector(v,t) slv_copy_vector((v),(t))
412 #define inner_product(v,u) slv_inner_product((v),(u))
413 #define square_norm(v) slv_square_norm(v)
414 #define matrix_product(m,v,p,s,t) slv_matrix_product((m),(v),(p),(s),(t))
415
416 /**
417 *** Calculation routines
418 *** --------------------
419 *** ok = calc_objective(sys)
420 *** ok = calc_residuals(sys)
421 *** ok = calc_J(sys)
422 *** calc_nominals(sys)
423 *** calc_weights(sys)
424 *** scale_J(sys)
425 *** scale_variables(sys)
426 *** scale_residuals(sys)
427 *** ok = calc_gradient(sys)
428 *** calc_B(sys)
429 *** calc_ZBZ(sys)
430 *** calc_pivots(sys)
431 *** calc_rhs(sys)
432 *** calc_multipliers(sys)
433 *** calc_stationary(sys)
434 *** calc_newton(sys)
435 *** calc_Bnewton(sys)
436 *** calc_nullspace(sys)
437 *** calc_gamma(sys)
438 *** calc_Jgamma(sys)
439 *** calc_varstep1(sys)
440 *** calc_Bvarstep1(sys)
441 *** calc_varstep2(sys)
442 *** calc_Bvarstep2(sys)
443 *** calc_mulstep1(sys)
444 *** calc_mulstep2(sys)
445 *** calc_varstep(sys)
446 *** calc_mulstep(sys)
447 *** calc_phi(sys)
448 **/
449
450 #define UPDATE_JACOBIAN 1 /* Update jacobian this often */
451 #define UPDATE_WEIGHTS 1 /* Update weights this often */
452 #define UPDATE_NOMINALS 1000 /* Update nominals this often */
453 #define TOO_SMALL 1e-8
454 #define TOWARD_BOUNDS 0.95
455
456
457 #define OPTIMIZING(sys) ((sys)->ZBZ.order > 0)
458
459 static boolean calc_objective(sys)
460 slv0_system_t sys;
461 /**
462 *** Evaluate the objective function.
463 **/
464 {
465 calc_ok = TRUE;
466 Asc_SignalHandlerPush(SIGFPE,SIG_IGN);
467 sys->objective = (sys->obj ? relman_eval(sys->obj,&calc_ok) : 0.0);
468 Asc_SignalHandlerPop(SIGFPE,SIG_IGN);
469 return calc_ok;
470 }
471
472 static boolean calc_inequalities(sys)
473 slv0_system_t sys;
474 /**
475 *** Calculates all of the residuals of included inequalities.
476 *** Returns true iff (calculations preceded without error and
477 *** all inequalities are satisfied.)
478 **/
479 {
480 struct rel_relation **rp;
481 boolean satisfied=TRUE;
482 static rel_filter_t rfilter;
483 rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE);
484 rfilter.matchvalue = (REL_INCLUDED | REL_ACTIVE);
485
486 calc_ok = TRUE;
487 Asc_SignalHandlerPush(SIGFPE,SIG_IGN);
488 for (rp=sys->rlist;*rp != NULL; rp++) {
489 if (rel_apply_filter(*rp,&rfilter)) {
490 relman_eval(*rp,&calc_ok);
491 satisfied=
492 satisfied && relman_calc_satisfied(*rp,sys->p.tolerance.feasible);
493 }
494 }
495 Asc_SignalHandlerPop(SIGFPE,SIG_IGN);
496 return (calc_ok && satisfied);
497 }
498
499 static boolean calc_residuals(sys)
500 slv0_system_t sys;
501 /**
502 *** Calculates all of the residuals in the current block and computes
503 *** the residual norm for block status. Returns true iff calculations
504 *** preceded without error.
505 **/
506 {
507 int32 row;
508 struct rel_relation *rel;
509 double time0;
510
511 if( sys->residuals.accurate )
512 return TRUE;
513
514 calc_ok = TRUE;
515 row = sys->residuals.rng->low;
516 time0=tm_cpu_time();
517 Asc_SignalHandlerPush(SIGFPE,SIG_IGN);
518 for( ; row <= sys->residuals.rng->high; row++ ) {
519 rel = sys->rlist[mtx_row_to_org(sys->J.mtx,row)];
520 #if DEBUG
521 if (!rel) {
522 int r;
523 r=mtx_row_to_org(sys->J.mtx,row);
524 FPRINTF(stderr,"NULL relation found !!\n");
525 FPRINTF(stderr,"at row %d rel %d in calc_residuals\n",(int)row,r);
526 FFLUSH(stderr);
527 }
528 #endif
529 sys->residuals.vec[row] = relman_eval(rel,&calc_ok);
530 /*
531 FPRINTF(stderr,"RESIDUAL[%d] = %12.8g\n",
532 mtx_row_to_org(sys->J.mtx,row), sys->residuals.vec[row]);
533 FFLUSH(stderr);
534 */
535
536 relman_calc_satisfied(rel,sys->p.tolerance.feasible);
537 }
538 Asc_SignalHandlerPop(SIGFPE,SIG_IGN);
539 sys->s.block.functime += (tm_cpu_time() -time0);
540 sys->s.block.funcs++;
541 square_norm( &(sys->residuals) );
542 sys->s.block.residual = calc_sqrt_D0(sys->residuals.norm2);
543 return(calc_ok);
544 }
545
546
547 static boolean calc_J(sys)
548 slv0_system_t sys;
549 /**
550 *** Calculates the current block of the jacobian.
551 *** It is initially unscaled.
552 **/
553 {
554 int32 row;
555 var_filter_t vfilter;
556 double time0;
557
558 if( sys->J.accurate )
559 return TRUE;
560
561 calc_ok = TRUE;
562 vfilter.matchbits = (VAR_INBLOCK | VAR_ACTIVE);
563 vfilter.matchvalue = (VAR_INBLOCK | VAR_ACTIVE);
564 /* vfilter.fixed = var_ignore;
565 vfilter.incident = var_ignore;
566 vfilter.in_block = var_true; */
567 time0=tm_cpu_time();
568 mtx_clear_region(sys->J.mtx,&(sys->J.reg));
569 for( row = sys->J.reg.row.low; row <= sys->J.reg.row.high; row++ ) {
570 struct rel_relation *rel;
571 rel = sys->rlist[mtx_row_to_org(sys->J.mtx,row)];
572 relman_diffs(rel,&vfilter,sys->J.mtx);
573 }
574 sys->s.block.jactime += (tm_cpu_time() - time0);
575 sys->s.block.jacs++;
576
577 if( --(sys->update.nominals) <= 0 )
578 sys->nominals.accurate = FALSE;
579 if( --(sys->update.weights) <= 0 )
580 sys->weights.accurate = FALSE;
581
582 linsol_matrix_was_changed(sys->J.sys);
583 return(calc_ok);
584 }
585
586
587 static void calc_nominals(sys)
588 slv0_system_t sys;
589 /**
590 *** Retrieves the nominal values of all of the block variables,
591 *** insuring that they are all strictly positive.
592 **/
593 {
594 int32 col;
595
596 if( sys->nominals.accurate )
597 return;
598
599 col = sys->nominals.rng->low;
600 for( ; col <= sys->nominals.rng->high; col++ ) {
601 struct var_variable *var;
602 real64 n;
603 var = sys->vlist[mtx_col_to_org(sys->J.mtx,col)];
604 n = var_nominal(var);
605 if( n <= 0.0 ) {
606 FILE *fp = MIF(sys);
607 if( n == 0.0 ) {
608 n = TOO_SMALL;
609 FPRINTF(fp,"ERROR: (slv0) calc_nominals\n");
610 FPRINTF(fp," Variable ");
611 print_var_name(fp,sys,var);
612 FPRINTF(fp," \nhas nominal value of zero.\n");
613 FPRINTF(fp," Resetting to %g.\n",n);
614 var_set_nominal(var,n);
615 } else {
616 n = -n;
617 FPRINTF(fp,"ERROR: (slv0) calc_nominals\n");
618 FPRINTF(fp," Variable ");
619 print_var_name(fp,sys,var);
620 FPRINTF(fp," \nhas negative nominal value.\n");
621 FPRINTF(fp," Resetting to %g.\n",n);
622 var_set_nominal(var,n);
623 }
624 }
625 sys->nominals.vec[col] = n;
626 }
627 square_norm( &(sys->nominals) );
628 sys->update.nominals = UPDATE_NOMINALS;
629 sys->nominals.accurate = TRUE;
630 }
631
632
633 static void calc_weights(sys)
634 slv0_system_t sys;
635 /**
636 *** Calculates the weights of all of the block relations
637 *** to scale the rows of the Jacobian.
638 **/
639 {
640 mtx_coord_t nz;
641
642 if( sys->weights.accurate )
643 return;
644
645 nz.row = sys->weights.rng->low;
646 for( ; nz.row <= sys->weights.rng->high; (nz.row)++ ) {
647 real64 sum;
648 sum=mtx_sum_sqrs_in_row(sys->J.mtx,nz.row,&(sys->J.reg.col));
649 sys->weights.vec[nz.row] = (sum>0.0) ? 1.0/calc_sqrt_D0(sum) : 1.0;
650 }
651 square_norm( &(sys->weights) );
652 sys->update.weights = UPDATE_WEIGHTS;
653 sys->residuals.accurate = FALSE;
654 sys->weights.accurate = TRUE;
655 }
656
657
658 static void scale_J(sys)
659 slv0_system_t sys;
660 /**
661 *** Scales the jacobian.
662 **/
663 {
664 int32 row;
665 int32 col;
666
667 if( sys->J.accurate )
668 return;
669
670 calc_nominals(sys);
671
672 for( col=sys->J.reg.col.low; col <= sys->J.reg.col.high; col++ )
673 mtx_mult_col(sys->J.mtx,col,sys->nominals.vec[col],&(sys->J.reg.row));
674
675 calc_weights(sys);
676 for( row=sys->J.reg.row.low; row <= sys->J.reg.row.high; row++ )
677 mtx_mult_row(sys->J.mtx,row,sys->weights.vec[row],&(sys->J.reg.col));
678
679 sys->update.jacobian = UPDATE_JACOBIAN;
680 sys->J.accurate = TRUE;
681 sys->J.singular = FALSE; /* yet to be determined */
682 #if DEBUG
683 FPRINTF(LIF(sys),"\nJacobian: \n");
684 debug_out_jacobian(LIF(sys),sys);
685 #endif
686 }
687
688
689 static void scale_variables(sys)
690 slv0_system_t sys;
691 {
692 int32 col;
693
694 if( sys->variables.accurate )
695 return;
696
697 col = sys->variables.rng->low;
698 for( ; col <= sys->variables.rng->high; col++ ) {
699 struct var_variable *var = sys->vlist[mtx_col_to_org(sys->J.mtx,col)];
700 sys->variables.vec[col] = var_value(var)/sys->nominals.vec[col];
701 }
702 square_norm( &(sys->variables) );
703 sys->variables.accurate = TRUE;
704 #if DEBUG
705 FPRINTF(LIF(sys),"Variables: ");
706 debug_out_vector(LIF(sys),sys,&(sys->variables));
707 #endif
708 }
709
710
711 static void scale_residuals(sys)
712 slv0_system_t sys;
713 /**
714 *** Scales the previously calculated residuals.
715 **/
716 {
717 int32 row;
718
719 if( sys->residuals.accurate )
720 return;
721
722 row = sys->residuals.rng->low;
723 for( ; row <= sys->residuals.rng->high; row++ ) {
724 struct rel_relation *rel = sys->rlist[mtx_row_to_org(sys->J.mtx,row)];
725 sys->residuals.vec[row] = rel_residual(rel)*sys->weights.vec[row];
726 }
727 square_norm( &(sys->residuals) );
728 sys->residuals.accurate = TRUE;
729 #if DEBUG
730 FPRINTF(LIF(sys),"Residuals: ");
731 debug_out_vector(LIF(sys),sys,&(sys->residuals));
732 #endif
733 }
734
735 static boolean calc_gradient(sys)
736 slv0_system_t sys;
737 /**
738 *** Calculate scaled gradient of the objective function.
739 **/
740 {
741 if( sys->gradient.accurate )
742 return TRUE;
743
744 calc_ok = TRUE;
745 if ( !OPTIMIZING(sys) ) {
746 zero_vector(&(sys->gradient));
747 sys->gradient.norm2 = 0.0;
748 } else {
749 struct var_variable **vp,**tmp;
750 var_filter_t vfilter;
751 vfilter.matchbits = (VAR_INBLOCK | VAR_ACTIVE);
752 vfilter.matchvalue = (VAR_INBLOCK | VAR_ACTIVE);
753 /* vfilter.fixed = var_ignore;
754 vfilter.incident = var_ignore;
755 vfilter.in_block = var_true; */
756 zero_vector(&(sys->gradient));
757 #if 0 /* this needs to be reimplemented */
758 for( vp=tmp=expr_incidence_list(sys->obj,NULL) ; *vp != NULL ; ++vp ) {
759 int32 col;
760 col = mtx_org_to_col(sys->J.mtx,var_sindex(*vp));
761 if( var_apply_filter(*vp,&vfilter) )
762 sys->gradient.vec[col] = sys->nominals.vec[col]*
763 exprman_diff(sys->obj,*vp);
764 }
765 ascfree(tmp);
766 square_norm( &(sys->gradient) );
767 #else
768 Asc_Panic(2, "calc_gradient",
769 "need to reimplemnt objective eval slv0\n");
770 #endif
771 }
772 sys->gradient.accurate = TRUE;
773 #if DEBUG
774 FPRINTF(LIF(sys),"Gradient: ");
775 debug_out_vector(LIF(sys),sys,&(sys->gradient));
776 #endif
777 return calc_ok;
778 }
779
780
781 static void create_update(sys)
782 slv0_system_t sys;
783 /**
784 *** Create a new hessian_data structure for storing
785 *** latest update information.
786 **/
787 {
788 struct hessian_data *update;
789
790 if( !OPTIMIZING(sys) )
791 return;
792
793 update = (struct hessian_data *)ascmalloc(sizeof(struct hessian_data));
794 update->y.vec = create_array(sys->cap,real64);
795 update->y.rng = &(sys->J.reg.col);
796 update->y.accurate = FALSE;
797 update->Bs.vec = create_array(sys->cap,real64);
798 update->Bs.rng = &(sys->J.reg.col);
799 update->Bs.accurate = FALSE;
800 update->next = sys->B;
801 sys->B = update;
802 }
803
804
805 #define POSITIVE_DEFINITE 1.0e-2
806 static void calc_B(sys)
807 slv0_system_t sys;
808 /**
809 *** Computes a rank 2 BFGS update to the hessian matrix
810 *** B which accumulates curvature.
811 **/
812 {
813 if( sys->s.block.iteration > 1 )
814 create_update(sys);
815 else
816 if( sys->B ) {
817 struct hessian_data *update;
818 for( update=sys->B; update != NULL; ) {
819 struct hessian_data *handle;
820 handle = update;
821 update = update->next;
822 destroy_array(handle->y.vec);
823 destroy_array(handle->Bs.vec);
824 ascfree(handle);
825 }
826 sys->B = NULL;
827 }
828
829 if( sys->B ) {
830 real64 theta;
831 /**
832 *** The y vector
833 **/
834 if( !sys->B->y.accurate ) {
835 int32 col;
836 matrix_product(sys->J.mtx, &(sys->multipliers),
837 &(sys->B->y), 1.0, TRUE);
838 col = sys->B->y.rng->low;
839 for( ; col <= sys->B->y.rng->high; col++ )
840 sys->B->y.vec[col] += sys->gradient.vec[col] -
841 sys->stationary.vec[col];
842 square_norm( &(sys->B->y) );
843 sys->B->y.accurate = TRUE;
844 }
845
846 /**
847 *** The Bs vector
848 **/
849 if( !sys->B->Bs.accurate ) {
850 struct hessian_data *update;
851 copy_vector(&(sys->varstep),&(sys->B->Bs));
852 for( update=sys->B->next; update != NULL; update = update->next ) {
853 int32 col;
854 real64 ys = inner_product( &(update->y),&(sys->varstep) );
855 real64 sBs = inner_product( &(update->Bs),&(sys->varstep) );
856 col = sys->B->Bs.rng->low;
857 for( ; col<=sys->B->Bs.rng->high; col++) {
858 sys->B->Bs.vec[col] += update->ys > 0.0 ?
859 (update->y.vec[col])*ys/update->ys : 0.0;
860 sys->B->Bs.vec[col] -= update->sBs > 0.0 ?
861 (update->Bs.vec[col])*sBs/update->sBs : 0.0;
862 }
863 }
864 square_norm( &(sys->B->Bs) );
865 sys->B->Bs.accurate = TRUE;
866 }
867
868 sys->B->ys = inner_product( &(sys->B->y),&(sys->varstep) );
869 sys->B->sBs = inner_product( &(sys->B->Bs),&(sys->varstep) );
870
871 if( sys->B->ys == 0.0 && sys->B->sBs == 0.0 ) theta = 0.0;
872 else theta = sys->B->ys < POSITIVE_DEFINITE*sys->B->sBs ?
873 (1.0-POSITIVE_DEFINITE)*sys->B->sBs/(sys->B->sBs - sys->B->ys):1.0;
874 #if DEBUG
875 FPRINTF(LIF(sys),"ys, sBs, PD, theta = %g, %g, %g, %g\n",
876 sys->B->ys,
877 sys->B->sBs,
878 POSITIVE_DEFINITE,
879 theta);
880 #endif
881 if( theta < 1.0 ) {
882 int32 col;
883 col = sys->B->y.rng->low;
884 for( ; col <= sys->B->y.rng->high; col++ )
885 sys->B->y.vec[col] = theta*sys->B->y.vec[col] +
886 (1.0-theta)*sys->B->Bs.vec[col];
887 square_norm( &(sys->B->y) );
888 sys->B->ys = theta*sys->B->ys + (1.0-theta)*sys->B->sBs;
889 }
890 }
891 }
892 #undef POSITIVE_DEFINITE
893
894
895 static void calc_pivots(sys)
896 slv0_system_t sys;
897 /**
898 *** Obtain the equations and variables which
899 *** are able to be pivoted.
900 **/
901 {
902 linsol_system_t lsys = sys->J.sys;
903 FILE *fp = LIF(sys);
904 #undef KAA_DEBUG
905 #ifdef KAA_DEBUG
906 double time1 = tm_cpu_time();
907 linsol_invert(lsys,&(sys->J.reg));
908 time1 = tm_cpu_time() - time1;
909 FPRINTF(stdout,"Time to invert block = %g seconds\n",time1);
910 #else
911 linsol_invert(lsys,&(sys->J.reg));
912 #endif
913
914 set_null(sys->J.relpivots,sys->cap);
915 set_null(sys->J.varpivots,sys->cap);
916 linsol_get_pivot_sets(lsys,sys->J.relpivots,sys->J.varpivots);
917 sys->J.rank = linsol_rank(lsys);
918 sys->J.singular = FALSE;
919 if( sys->J.rank < sys->J.reg.row.high-sys->J.reg.row.low+1 ) {
920 int32 row;
921 sys->J.singular = TRUE;
922 for( row=sys->J.reg.row.low; row <= sys->J.reg.row.high ; row++ ) {
923 int32 org_row;
924 org_row = mtx_row_to_org(sys->J.mtx,row);
925 if( !set_is_member(sys->J.relpivots,org_row) ) {
926 struct rel_relation *rel;
927 rel = sys->rlist[org_row];
928 FPRINTF(fp,"%-40s ---> ","Relation not pivoted");
929 print_rel_name(fp,sys,rel);
930 PUTC('\n',fp);
931
932 /**
933 *** assign zeros to the corresponding weights
934 *** so that subsequent calls to "scale_residuals"
935 *** will only measure the pivoted equations.
936 **/
937 sys->weights.vec[row] = 0.0;
938 sys->residuals.vec[row] = 0.0;
939 sys->residuals.accurate = FALSE;
940 mtx_mult_row(sys->J.mtx,row,0.0,&(sys->J.reg.col));
941 }
942 }
943 if( !sys->residuals.accurate ) {
944 square_norm( &(sys->residuals) );
945 sys->residuals.accurate = TRUE;
946 sys->update.weights = 0; /* re-compute weights next iteration. */
947 }
948 }
949 if( sys->J.rank < sys->J.reg.col.high-sys->J.reg.col.low+1 ) {
950 int32 col;
951 for( col=sys->J.reg.col.low; col <= sys->J.reg.col.high ; col++ ) {
952 int32 org_col;
953 org_col = mtx_col_to_org(sys->J.mtx,col);
954 if( !set_is_member(sys->J.varpivots,org_col) ) {
955 struct var_variable *var;
956 var = sys->vlist[org_col];
957 FPRINTF(fp,"%-40s ---> ","Variable not pivoted");
958 print_var_name(fp,sys,var);
959 PUTC('\n',fp);
960 /**
961 *** If we're not optimizing (everything should be
962 *** pivotable) or this was one of the dependent variables,
963 *** consider this variable as if it were fixed.
964 **/
965 if( col <= sys->J.reg.col.high - sys->ZBZ.order )
966 mtx_mult_col(sys->J.mtx,col,0.0,&(sys->J.reg.row));
967 }
968 }
969 }
970 FPRINTF(fp,"%-40s ---> %d (%s)\n","Jacobian rank", sys->J.rank,
971 sys->J.singular ? "deficient":"full");
972 if (sys->p.output.less_important) {
973 FPRINTF(LIF(sys),"%-40s ---> %g\n","Smallest pivot",
974 linsol_smallest_pivot(sys->J.sys));
975 }
976 }
977
978
979 static void calc_ZBZ(sys)
980 slv0_system_t sys;
981 /**
982 *** Updates the reduced hessian matrix.
983 **/
984 {
985 mtx_coord_t nz;
986
987 if( sys->ZBZ.accurate ) return;
988
989 for( nz.row = 0; nz.row < sys->ZBZ.order; nz.row++ ) {
990 for( nz.col = 0; nz.col <= nz.row; nz.col++ ) {
991 int32 col, depr, depc;
992 col = nz.row+sys->J.reg.col.high+1-sys->ZBZ.order;
993 depr = mtx_col_to_org(sys->J.mtx,col);
994 col = nz.col+sys->J.reg.col.high+1-sys->ZBZ.order;
995 depc = mtx_col_to_org(sys->J.mtx,col);
996 sys->ZBZ.mtx[nz.row][nz.col] = (nz.row==nz.col ? 1.0 : 0.0);
997 col = sys->J.reg.col.low;
998 for( ; col <= sys->J.reg.col.high - sys->ZBZ.order; col++ ) {
999 int32 ind = mtx_col_to_org(sys->J.mtx,col);
1000 if( set_is_member(sys->J.varpivots,ind) )
1001 sys->ZBZ.mtx[nz.row][nz.col] +=
1002 (-linsol_org_col_dependency(sys->J.sys,depr,ind))*
1003 (-linsol_org_col_dependency(sys->J.sys,depc,ind));
1004 }
1005 if( nz.row != nz.col )
1006 sys->ZBZ.mtx[nz.col][nz.row] =
1007 sys->ZBZ.mtx[nz.row][nz.col];
1008 }
1009 }
1010 if( OPTIMIZING(sys) ) {
1011 struct hessian_data *update;
1012 for( update=sys->B; update != NULL; update = update->next ) {
1013 mtx_coord_t nz;
1014 for( nz.row=0; nz.row < sys->ZBZ.order; nz.row++ ) {
1015 int32 col, dep;
1016 col = nz.row + sys->J.reg.col.high + 1 - sys->ZBZ.order;
1017 dep = mtx_col_to_org(sys->J.mtx,col);
1018 sys->ZBZ.Zy[nz.row] = update->y.vec[col];
1019 sys->ZBZ.ZBs[nz.row] = update->Bs.vec[col];
1020 col = sys->J.reg.col.low;
1021 for( ; col <= sys->J.reg.col.high - sys->ZBZ.order; col++ ) {
1022 int32 ind = mtx_col_to_org(sys->J.mtx,col);
1023 if( set_is_member(sys->J.varpivots,ind) ) {
1024 sys->ZBZ.Zy[nz.row] += update->y.vec[col]*
1025 (-linsol_org_col_dependency(sys->J.sys,dep,ind));
1026 sys->ZBZ.ZBs[nz.row] += update->Bs.vec[col]*
1027 (-linsol_org_col_dependency(sys->J.sys,dep,ind));
1028 }
1029 }
1030 for( nz.col=0; nz.col <= nz.row; nz.col++ ) {
1031 sys->ZBZ.mtx[nz.row][nz.col] += update->ys > 0.0 ?
1032 sys->ZBZ.Zy[nz.row]*sys->ZBZ.Zy[nz.col]/update->ys : 0.0;
1033 sys->ZBZ.mtx[nz.row][nz.col] -= update->sBs > 0.0 ?
1034 sys->ZBZ.ZBs[nz.row]*sys->ZBZ.ZBs[nz.col]/update->sBs : 0.0;
1035 if( nz.row != nz.col )
1036 sys->ZBZ.mtx[nz.col][nz.row] =
1037 sys->ZBZ.mtx[nz.row][nz.col];
1038 }
1039 }
1040 }
1041 }
1042 sys->ZBZ.accurate = TRUE;
1043 #if DEBUG
1044 FPRINTF(LIF(sys),"\nReduced Hessian: \n");
1045 debug_out_hessian(LIF(sys),sys);
1046 #endif
1047 }
1048
1049
1050 static void calc_rhs(sys,vec,scalar,transpose)
1051 slv0_system_t sys;
1052 struct vector_data *vec;
1053 real64 scalar;
1054 boolean transpose;
1055 /**
1056 *** Calculates just the jacobian RHS. This function should be used to
1057 *** supplement calculation of the jacobian. The vector vec must
1058 *** already be calculated and scaled so as to simply be added to the
1059 *** rhs. Caller is responsible for initially zeroing the rhs vector.
1060 **/
1061 {
1062 if( transpose ) { /* vec is indexed by col */
1063 int32 col;
1064 for( col=vec->rng->low; col<=vec->rng->high; col++ )
1065 sys->J.rhs[mtx_col_to_org(sys->J.mtx,col)] +=
1066 scalar*vec->vec[col];
1067
1068 } else { /* vec is indexed by row */
1069 int32 row;
1070 for( row=vec->rng->low; row<=vec->rng->high; row++ )
1071 sys->J.rhs[mtx_row_to_org(sys->J.mtx,row)] +=
1072 scalar*vec->vec[row];
1073 }
1074 linsol_rhs_was_changed(sys->J.sys,sys->J.rhs);
1075 }
1076
1077
1078 static void calc_multipliers(sys)
1079 slv0_system_t sys;
1080 /**
1081 *** Computes the lagrange multipliers for the equality constraints.
1082 **/
1083 {
1084 if( sys->multipliers.accurate )
1085 return;
1086
1087 if ( !OPTIMIZING(sys) ) {
1088 zero_vector(&(sys->multipliers));
1089 sys->multipliers.norm2 = 0.0;
1090 } else {
1091 linsol_system_t lsys = sys->J.sys;
1092 int32 row;
1093 sys->J.rhs = linsol_get_rhs(lsys,0);
1094 mem_zero_byte_cast(sys->J.rhs,0.0,sys->cap*sizeof(real64));
1095 calc_rhs(sys, &(sys->gradient), -1.0, TRUE );
1096 linsol_solve(lsys,sys->J.rhs);
1097 row = sys->multipliers.rng->low;
1098 for( ; row <= sys->multipliers.rng->high; row++ ) {
1099 struct rel_relation *rel = sys->rlist[mtx_row_to_org(sys->J.mtx,row)];
1100 sys->multipliers.vec[row] = linsol_var_value
1101 (lsys,sys->J.rhs,mtx_row_to_org(sys->J.mtx,row));
1102 rel_set_multiplier(rel,sys->multipliers.vec[row]*
1103 sys->weights.vec[row]);
1104
1105 }
1106 if (sys->iarray[SP0_SAVLIN]) {
1107 FILE *ldat;
1108 int32 ov;
1109 sprintf(savlinfilename,"%s%d",savlinfilebase,savlinnum++);
1110 ldat=fopen(savlinfilename,"w");
1111 FPRINTF(ldat,
1112 "================= multipliersrhs (orgcoled) itn %d =====\n",
1113 sys->s.iteration);
1114 debug_write_array(ldat,sys->J.rhs,sys->cap);
1115 FPRINTF(ldat,
1116 "================= multipliers (orgrowed) ============\n");
1117 for(ov=0 ; ov < sys->cap; ov++ )
1118 FPRINTF(ldat,"%.20g\n",linsol_var_value(lsys,sys->J.rhs,ov));
1119 fclose(ldat);
1120 }
1121 square_norm( &(sys->multipliers) );
1122 }
1123 sys->multipliers.accurate = TRUE;
1124 #if DEBUG
1125 FPRINTF(LIF(sys),"Multipliers: ");
1126 debug_out_vector(LIF(sys),sys,&(sys->multipliers));
1127 #endif
1128 }
1129
1130
1131 static void calc_stationary(sys)
1132 slv0_system_t sys;
1133 /**
1134 *** Computes the gradient of the lagrangian which
1135 *** should be zero at the optimum solution.
1136 **/
1137 {
1138 if( sys->stationary.accurate )
1139 return;
1140
1141 if ( !OPTIMIZING(sys) ) {
1142 zero_vector(&(sys->stationary));
1143 sys->stationary.norm2 = 0.0;
1144 } else {
1145 int32 col;
1146 matrix_product(sys->J.mtx, &(sys->multipliers),
1147 &(sys->stationary), 1.0, TRUE);
1148 col = sys->stationary.rng->low;
1149 for( ; col <= sys->stationary.rng->high; col++ )
1150 sys->stationary.vec[col] += sys->gradient.vec[col];
1151 square_norm( &(sys->stationary) );
1152 }
1153 sys->stationary.accurate = TRUE;
1154 #if DEBUG
1155 FPRINTF(LIF(sys),"Stationary: ");
1156 debug_out_vector(LIF(sys),sys,&(sys->stationary));
1157 #endif
1158 }
1159
1160
1161 static void calc_gamma(sys)
1162 slv0_system_t sys;
1163 /**
1164 *** Calculate the gamma vector.
1165 **/
1166 {
1167 if( sys->gamma.accurate )
1168 return;
1169
1170 matrix_product(sys->J.mtx, &(sys->residuals),
1171 &(sys->gamma), -1.0, TRUE);
1172 square_norm( &(sys->gamma) );
1173 sys->gamma.accurate = TRUE;
1174
1175 #if DEBUG
1176 FPRINTF(LIF(sys),"Gamma: ");
1177 debug_out_vector(LIF(sys),sys,&(sys->gamma));
1178 #endif
1179 }
1180
1181 static void calc_Jgamma(sys)
1182 slv0_system_t sys;
1183 /**
1184 *** Calculate the Jgamma vector.
1185 **/
1186 {
1187 if( sys->Jgamma.accurate )
1188 return;
1189
1190 matrix_product(sys->J.mtx, &(sys->gamma),
1191 &(sys->Jgamma), 1.0, FALSE);
1192 square_norm( &(sys->Jgamma) );
1193 sys->Jgamma.accurate = TRUE;
1194 #if DEBUG
1195 FPRINTF(LIF(sys),"Jgamma: ");
1196 debug_out_vector(LIF(sys),sys,&(sys->Jgamma));
1197 #endif
1198 }
1199
1200
1201 static void calc_newton(sys)
1202 slv0_system_t sys;
1203 /**
1204 *** Computes a step to solve the linearized equations.
1205 **/
1206 {
1207 linsol_system_t lsys = sys->J.sys;
1208 int32 col;
1209
1210 if( sys->newton.accurate )
1211 return;
1212
1213 sys->J.rhs = linsol_get_rhs(lsys,1);
1214 mem_zero_byte_cast(sys->J.rhs,0.0,sys->cap*sizeof(real64));
1215 calc_rhs(sys, &(sys->residuals), -1.0, FALSE);
1216 linsol_solve(lsys,sys->J.rhs);
1217 col = sys->newton.rng->low;
1218 for( ; col <= sys->newton.rng->high; col++ )
1219 sys->newton.vec[col] = linsol_var_value
1220 (lsys,sys->J.rhs,mtx_col_to_org(sys->J.mtx,col));
1221 if (sys->iarray[SP0_SAVLIN]) {
1222 FILE *ldat;
1223 int32 ov;
1224 sprintf(savlinfilename,"%s%d",savlinfilebase,savlinnum++);
1225 ldat=fopen(savlinfilename,"w");
1226 FPRINTF(ldat,"================= resids (orgrowed) itn %d =====\n",
1227 sys->s.iteration);
1228 debug_write_array(ldat,sys->J.rhs,sys->cap);
1229 FPRINTF(ldat,"================= vars (orgcoled) ============\n");
1230 for(ov=0 ; ov < sys->cap; ov++ )
1231 FPRINTF(ldat,"%.20g\n",linsol_var_value(lsys,sys->J.rhs,ov));
1232 fclose(ldat);
1233 }
1234 square_norm( &(sys->newton) );
1235 sys->newton.accurate = TRUE;
1236 #if DEBUG
1237 FPRINTF(LIF(sys),"Newton: ");
1238 debug_out_vector(LIF(sys),sys,&(sys->newton));
1239 #endif
1240 }
1241
1242
1243 static void calc_Bnewton(sys)
1244 slv0_system_t sys;
1245 /**
1246 *** Computes an update to the product B and newton.
1247 **/
1248 {
1249 if( sys->Bnewton.accurate )
1250 return;
1251
1252 if ( !OPTIMIZING(sys) ) {
1253 zero_vector(&(sys->Bnewton));
1254 sys->Bnewton.norm2 = 0.0;
1255 } else {
1256 struct hessian_data *update;
1257 copy_vector(&(sys->newton),&(sys->Bnewton));
1258 for( update=sys->B; update != NULL; update = update->next ) {
1259 int32 col;
1260 real64 yn = inner_product( &(update->y),&(sys->newton) );
1261 real64 sBn = inner_product( &(update->Bs),&(sys->newton) );
1262 col = sys->Bnewton.rng->low;
1263 for( ; col <= sys->Bnewton.rng->high; col++ ) {
1264 sys->Bnewton.vec[col] += update->ys > 0.0 ?
1265 (update->y.vec[col])*yn/update->ys : 0.0;
1266 sys->Bnewton.vec[col] -= update->sBs > 0.0 ?
1267 (update->Bs.vec[col])*sBn/update->sBs : 0.0;
1268 }
1269 }
1270 square_norm( &(sys->Bnewton) );
1271 }
1272 sys->Bnewton.accurate = TRUE;
1273 #if DEBUG
1274 FPRINTF(LIF(sys),"Bnewton: ");
1275 debug_out_vector(LIF(sys),sys,&(sys->Bnewton));
1276 #endif
1277 }
1278
1279
1280 static void calc_nullspace(sys)
1281 slv0_system_t sys;
1282 /**
1283 *** Calculate the nullspace move.
1284 **/
1285 {
1286 if( sys->nullspace.accurate )
1287 return;
1288
1289 if( !OPTIMIZING(sys) ) {
1290 zero_vector(&(sys->nullspace));
1291 sys->nullspace.norm2 = 0.0;
1292 } else {
1293 mtx_coord_t nz;
1294 zero_vector(&(sys->nullspace));
1295 for( nz.row=0; nz.row < sys->ZBZ.order; nz.row++ ) {
1296 int32 col, dep, ndx;
1297 col = nz.row+sys->J.reg.col.high+1-sys->ZBZ.order;
1298 dep = mtx_col_to_org(sys->J.mtx,col);
1299 sys->nullspace.vec[col] = -sys->stationary.vec[col] -
1300 sys->Bnewton.vec[col];
1301 ndx = sys->J.reg.col.low;
1302 for( ; ndx <= sys->J.reg.col.high - sys->ZBZ.order; ndx++ ) {
1303 int32 ind = mtx_col_to_org(sys->J.mtx,ndx);
1304 if( set_is_member(sys->J.varpivots,ind) )
1305 sys->nullspace.vec[col] -=
1306 (sys->stationary.vec[ndx] + sys->Bnewton.vec[ndx])*
1307 (-linsol_org_col_dependency(sys->J.sys,dep,ind));
1308 }
1309 }
1310 /**
1311 *** Must invert ZBZ first. It's symmetric so
1312 *** can find Cholesky factors. Essentially, find
1313 *** the "square root" of the matrix such that
1314 ***
1315 *** T
1316 *** L U = U U = ZBZ, where U is an upper triangular
1317 *** matrix.
1318 **/
1319 for( nz.row = 0; nz.row < sys->ZBZ.order; nz.row++ ) {
1320 for( nz.col = nz.row; nz.col < sys->ZBZ.order; nz.col++ ) {
1321 int32 col;
1322 for( col = 0; col < nz.row; col++ )
1323 sys->ZBZ.mtx[nz.row][nz.col] -=
1324 sys->ZBZ.mtx[nz.row][col]*
1325 sys->ZBZ.mtx[col][nz.col];
1326 if( nz.row == nz.col )
1327 sys->ZBZ.mtx[nz.row][nz.col] =
1328 calc_sqrt_D0(sys->ZBZ.mtx[nz.row][nz.col]);
1329 else {
1330 sys->ZBZ.mtx[nz.row][nz.col] /=
1331 sys->ZBZ.mtx[nz.row][nz.row];
1332 sys->ZBZ.mtx[nz.col][nz.row] =
1333 sys->ZBZ.mtx[nz.row][nz.col];
1334 }
1335 }
1336 }
1337 #if DEBUG
1338 FPRINTF(LIF(sys),"\nInverse Reduced Hessian: \n");
1339 debug_out_hessian(LIF(sys),sys);
1340 #endif
1341 /**
1342 *** forward substitute
1343 **/
1344 for( nz.row = 0; nz.row < sys->ZBZ.order; nz.row++ ) {
1345 int32 offset = sys->J.reg.col.high+1-sys->ZBZ.order;
1346 for( nz.col = 0; nz.col < nz.row; nz.col++ ) {
1347 sys->nullspace.vec[nz.row+offset] -=
1348 sys->nullspace.vec[nz.col+offset]*
1349 sys->ZBZ.mtx[nz.row][nz.col];
1350 }
1351 sys->nullspace.vec[nz.row+offset] /=
1352 sys->ZBZ.mtx[nz.row][nz.row];
1353 }
1354
1355 /**
1356 *** backward substitute
1357 **/
1358 for( nz.row = sys->ZBZ.order-1; nz.row >= 0; nz.row-- ) {
1359 int32 offset = sys->J.reg.col.high+1-sys->ZBZ.order;
1360 for( nz.col = nz.row+1; nz.col < sys->ZBZ.order; nz.col++ ) {
1361 sys->nullspace.vec[nz.row+offset] -=
1362 sys->nullspace.vec[nz.col+offset]*
1363 sys->ZBZ.mtx[nz.row][nz.col];
1364 }
1365 sys->nullspace.vec[nz.row+offset] /=
1366 sys->ZBZ.mtx[nz.row][nz.row];
1367 }
1368 square_norm( &(sys->nullspace) );
1369 }
1370 sys->nullspace.accurate = TRUE;
1371 #if DEBUG
1372 FPRINTF(LIF(sys),"Nullspace: ");
1373 debug_out_vector(LIF(sys),sys,&(sys->nullspace));
1374 #endif
1375 }
1376
1377 static void calc_varstep1(sys)
1378 slv0_system_t sys;
1379 /**
1380 *** Calculate the 1st order descent direction for phi
1381 *** in the variables.
1382 **/
1383 {
1384 if( sys->varstep1.accurate )
1385 return;
1386
1387 if( !OPTIMIZING(sys) ) {
1388 copy_vector(&(sys->gamma),&(sys->varstep1));
1389 sys->varstep1.norm2 = sys->gamma.norm2;
1390 } else {
1391 int32 col;
1392 col = sys->varstep1.rng->low;
1393 for( ; col <= sys->varstep1.rng->high; col++ )
1394 sys->varstep1.vec[col] = sys->p.rho*sys->gamma.vec[col] -
1395 sys->stationary.vec[col];
1396 square_norm( &(sys->varstep1) );
1397 }
1398 sys->varstep1.accurate = TRUE;
1399 #if DEBUG
1400 FPRINTF(LIF(sys),"Varstep1: ");
1401 debug_out_vector(LIF(sys),sys,&(sys->varstep1));
1402 #endif
1403 }
1404
1405
1406 static void calc_Bvarstep1(sys)
1407 slv0_system_t sys;
1408 /**
1409 *** Computes an update to the product B and varstep1.
1410 **/
1411 {
1412 if( sys->Bvarstep1.accurate )
1413 return;
1414
1415 if ( !OPTIMIZING(sys) ) {
1416 zero_vector(&(sys->Bvarstep1));
1417 sys->Bvarstep1.norm2 = 0.0;
1418 } else {
1419 struct hessian_data *update;
1420 copy_vector(&(sys->varstep1),&(sys->Bvarstep1));
1421 for( update=sys->B; update != NULL; update = update->next ) {
1422 int32 col;
1423 real64 yv = inner_product( &(update->y),&(sys->varstep1) );
1424 real64 sBv = inner_product( &(update->Bs),&(sys->varstep1) );
1425 col = sys->Bvarstep1.rng->low;
1426 for( ; col <= sys->Bvarstep1.rng->high; col++ ) {
1427 sys->Bvarstep1.vec[col] += update->ys > 0.0 ?
1428 (update->y.vec[col])*yv/update->ys : 0.0;
1429 sys->Bvarstep1.vec[col] -= update->sBs > 0.0 ?
1430 (update->Bs.vec[col])*sBv/update->sBs : 0.0;
1431 }
1432 }
1433 square_norm( &(sys->Bvarstep1) );
1434 }
1435 sys->Bvarstep1.accurate = TRUE;
1436 #if DEBUG
1437 FPRINTF(LIF(sys),"Bvarstep1: ");
1438 debug_out_vector(LIF(sys),sys,&(sys->Bvarstep1));
1439 #endif
1440 }
1441
1442
1443 static void calc_varstep2(sys)
1444 slv0_system_t sys;
1445 /**
1446 *** Calculate the 2nd order descent direction for phi
1447 *** in the variables.
1448 **/
1449 {
1450 if( sys->varstep2.accurate )
1451 return;
1452
1453 if( !OPTIMIZING(sys) ) {
1454 copy_vector(&(sys->newton),&(sys->varstep2));
1455 sys->varstep2.norm2 = sys->newton.norm2;
1456 } else {
1457 int32 col;
1458 col = sys->varstep2.rng->low;
1459 for( ; col <= sys->varstep2.rng->high - sys->ZBZ.order ; ++col ) {
1460 int32 dep;
1461 int32 ind = mtx_col_to_org(sys->J.mtx,col);
1462 sys->varstep2.vec[col] = sys->newton.vec[col];
1463 if( set_is_member(sys->J.varpivots,ind) ) {
1464 dep = sys->varstep2.rng->high + 1 - sys->ZBZ.order;
1465 for( ; dep <= sys->varstep2.rng->high; dep++ )
1466 sys->varstep2.vec[col] += sys->nullspace.vec[dep]*
1467 (-linsol_org_col_dependency(sys->J.sys,dep,ind));
1468 }
1469 }
1470 col = sys->varstep2.rng->high + 1 - sys->ZBZ.order;
1471 for( ; col <= sys->varstep2.rng->high; ++col )
1472 sys->varstep2.vec[col] = sys->nullspace.vec[col] +
1473 sys->newton.vec[col];
1474 square_norm( &(sys->varstep2) );
1475 }
1476 sys->varstep2.accurate = TRUE;
1477 #if DEBUG
1478 FPRINTF(LIF(sys),"Varstep2: ");
1479 debug_out_vector(LIF(sys),sys,&(sys->varstep2));
1480 #endif
1481 }
1482
1483
1484 static void calc_Bvarstep2(sys)
1485 slv0_system_t sys;
1486 /**
1487 *** Computes an update to the product B and varstep2.
1488 **/
1489 {
1490 if( sys->Bvarstep2.accurate )
1491 return;
1492
1493 if ( !OPTIMIZING(sys) ) {
1494 zero_vector(&(sys->Bvarstep2));
1495 sys->Bvarstep2.norm2 = 0.0;
1496 } else {
1497 struct hessian_data *update;
1498 copy_vector(&(sys->varstep2),&(sys->Bvarstep2));
1499 for( update=sys->B; update != NULL; update = update->next ) {
1500 int32 col;
1501 real64 yv = inner_product( &(update->y),&(sys->varstep2) );
1502 real64 sBv = inner_product( &(update->Bs),&(sys->varstep2) );
1503 col = sys->Bvarstep2.rng->low;
1504 for( ; col <= sys->Bvarstep2.rng->high; col++ ) {
1505 sys->Bvarstep2.vec[col] += update->ys > 0.0 ?
1506 (update->y.vec[col])*yv/update->ys : 0.0;
1507 sys->Bvarstep2.vec[col] -= update->sBs > 0.0 ?
1508 (update->Bs.vec[col])*sBv/update->sBs : 0.0;
1509 }
1510 }
1511 square_norm( &(sys->Bvarstep2) );
1512 }
1513 sys->Bvarstep2.accurate = TRUE;
1514 #if DEBUG
1515 FPRINTF(LIF(sys),"Bvarstep2: ");
1516 debug_out_vector(LIF(sys),sys,&(sys->Bvarstep2));
1517 #endif
1518 }
1519
1520
1521 static void calc_mulstep1(sys)
1522 slv0_system_t sys;
1523 /**
1524 *** Calculate the negative gradient direction of phi in the
1525 *** multipliers.
1526 **/
1527 {
1528 if( sys->mulstep1.accurate )
1529 return;
1530
1531 if( !OPTIMIZING(sys) ) {
1532 zero_vector(&(sys->mulstep1));
1533 sys->mulstep1.norm2 = 0.0;
1534 } else {
1535 int32 row;
1536 row = sys->mulstep1.rng->low;
1537 for( ; row <= sys->mulstep1.rng->high; row++ )
1538 sys->mulstep1.vec[row] = -sys->residuals.vec[row];
1539 square_norm( &(sys->mulstep1) );
1540 }
1541 sys->mulstep1.accurate = TRUE;
1542 #if DEBUG
1543 FPRINTF(LIF(sys),"Mulstep1: ");
1544 debug_out_vector(LIF(sys),sys,&(sys->mulstep1));
1545 #endif
1546 }
1547
1548
1549 static void calc_mulstep2(sys)
1550 slv0_system_t sys;
1551 /**
1552 *** Calculate the mulstep2 direction of phi in the
1553 *** multipliers.
1554 **/
1555 {
1556 if( sys->mulstep2.accurate )
1557 return;
1558
1559 if( !OPTIMIZING(sys) ) {
1560 zero_vector(&(sys->mulstep2));
1561 sys->mulstep2.norm2 = 0.0;
1562 } else {
1563 linsol_system_t lsys = sys->J.sys;
1564 int32 row;
1565 sys->J.rhs = linsol_get_rhs(lsys,2);
1566 mem_zero_byte_cast(sys->J.rhs,0.0,sys->cap*sizeof(real64));
1567 calc_rhs(sys, &(sys->Bvarstep2), -1.0, TRUE);
1568 calc_rhs(sys, &(sys->stationary), -1.0, TRUE);
1569 linsol_solve(lsys,sys->J.rhs);
1570 row = sys->mulstep2.rng->low;
1571 for( ; row <= sys->mulstep2.rng->high; row++ )
1572 sys->mulstep2.vec[row] = linsol_var_value
1573 (lsys,sys->J.rhs,mtx_row_to_org(sys->J.mtx,row));
1574 if (sys->iarray[SP0_SAVLIN]) {
1575 FILE *ldat;
1576 int32 ov;
1577 sprintf(savlinfilename,"%s%d",savlinfilebase,savlinnum++);
1578 ldat=fopen(savlinfilename,"w");
1579 FPRINTF(ldat,
1580 "================= mulstep2rhs (orgcoled) itn %d =======\n",
1581 sys->s.iteration);
1582 debug_write_array(ldat,sys->J.rhs,sys->cap);
1583 FPRINTF(ldat,
1584 "================= mulstep2vars (orgrowed) ============\n");
1585 for(ov=0 ; ov < sys->cap; ov++ )
1586 FPRINTF(ldat,"%.20g\n",linsol_var_value(lsys,sys->J.rhs,ov));
1587 fclose(ldat);
1588 }
1589 square_norm( &(sys->mulstep2) );
1590 }
1591 sys->mulstep2.accurate = TRUE;
1592 #if DEBUG
1593 FPRINTF(LIF(sys),"Mulstep2: ");
1594 debug_out_vector(LIF(sys),sys,&(sys->mulstep2));
1595 #endif
1596 }
1597
1598
1599 static void calc_phi(sys)
1600 slv0_system_t sys;
1601 /**
1602 *** Computes the global minimizing function Phi.
1603 **/
1604 {
1605 if( !OPTIMIZING(sys) )
1606 sys->phi = 0.5*sys->residuals.norm2;
1607 else {
1608 sys->phi = sys->objective;
1609 sys->phi += inner_product( &(sys->multipliers),&(sys->residuals) );
1610 sys->phi += 0.5*sys->p.rho*sys->residuals.norm2;
1611 }
1612 }
1613
1614
1615 /**
1616 *** OK. Here's where we compute the actual step to be taken. It will
1617 *** be some linear combination of the 1st order and 2nd order steps.
1618 **/
1619
1620 typedef real64 sym_2x2_t[3]; /* Stores symmetric 2x2 matrices */
1621
1622 struct parms_t {
1623 real64 low,high,guess; /* Used to search for parameter */
1624 };
1625
1626 struct calc_step_vars {
1627 sym_2x2_t coef1, coef2;
1628 real64 rhs[2]; /* RHS for 2x2 system */
1629 struct parms_t parms;
1630 real64 alpha1, alpha2;
1631 real64 error; /* Error between step norm and sys->maxstep */
1632 };
1633
1634 static void calc_2x2_system(sys,vars)
1635 slv0_system_t sys;
1636 struct calc_step_vars *vars;
1637 /**
1638 *** Calculates 2x2 system (coef1,coef2,rhs).
1639 **/
1640 {
1641 vars->coef1[0] = (2.0*sys->phi/sys->newton.norm2)*
1642 calc_sqrt_D0(sys->newton.norm2)/calc_sqrt_D0(sys->gamma.norm2);
1643 vars->coef1[1] = 1.0;
1644 vars->coef1[2] = (sys->Jgamma.norm2/sys->gamma.norm2)*
1645 calc_sqrt_D0(sys->newton.norm2)/calc_sqrt_D0(sys->gamma.norm2);
1646
1647 vars->coef2[0] = 1.0;
1648 vars->coef2[1] = 2.0*sys->phi/
1649 calc_sqrt_D0(sys->newton.norm2)/calc_sqrt_D0(sys->gamma.norm2);
1650 vars->coef2[2] = 1.0;
1651
1652 vars->rhs[0] = 2.0*sys->phi/
1653 sys->maxstep/calc_sqrt_D0(sys->gamma.norm2);
1654 vars->rhs[1] = calc_sqrt_D0(sys->newton.norm2)/sys->maxstep;
1655 }
1656
1657 static void coefs_from_parm(sys,vars)
1658 slv0_system_t sys;
1659 struct calc_step_vars *vars;
1660 /**
1661 *** Determines alpha1 and alpha2 from the parameter (guess).
1662 **/
1663 {
1664 #define DETZERO (1e-8)
1665
1666 sym_2x2_t coef; /* Actual coefficient matrix */
1667 real64 det; /* Determinant of coefficient matrix */
1668 int i;
1669
1670 for( i=0 ; i<3 ; ++i ) coef[i] =
1671 vars->coef1[i] + vars->parms.guess * vars->coef2[i];
1672 det = coef[0]*coef[2] - coef[1]*coef[1];
1673 if( det < 0.0 )
1674 FPRINTF(MIF(sys),"%-40s ---> %g\n",
1675 " Unexpected negative determinant!",det);
1676 if( det <= DETZERO ) {
1677 /**
1678 *** varstep2 and varstep1 are essentially parallel:
1679 *** adjust length of either
1680 **/
1681 vars->alpha2 = 0.0;
1682 vars->alpha1 = 1.0;
1683 } else {
1684 vars->alpha2 = (vars->rhs[0]*coef[2] - vars->rhs[1]*coef[1])/det;
1685 vars->alpha1 = (vars->rhs[1]*coef[0] - vars->rhs[0]*coef[1])/det;
1686 }
1687 #undef DETZERO
1688 }
1689
1690 static real64 step_norm2(sys,vars)
1691 slv0_system_t sys;
1692 struct calc_step_vars *vars;
1693 /**
1694 *** Computes step vector length based on 1st order and 2nd order
1695 *** vectors and their coefficients.
1696 **/
1697 {
1698 return sys->maxstep*sys->maxstep*
1699 (vars->alpha2 * vars->alpha2 +
1700 vars->alpha2 * vars->alpha1 * sys->phi/
1701 calc_sqrt_D0(sys->varstep2.norm2 + sys->mulstep2.norm2)/
1702 calc_sqrt_D0(sys->varstep1.norm2 + sys->mulstep1.norm2) +
1703 vars->alpha1 * vars->alpha1);
1704 }
1705
1706 static void adjust_parms(sys,vars)
1707 slv0_system_t sys;
1708 struct calc_step_vars *vars;
1709 /**
1710 *** Re-guesses the parameters based on
1711 *** step size vs. target value.
1712 **/
1713 {
1714 vars->error = (calc_sqrt_D0(step_norm2(sys,vars))/sys->maxstep) - 1.0;
1715 if( vars->error > 0.0 ) {
1716 /* Increase parameter (to decrease step length) */
1717 vars->parms.low = vars->parms.guess;
1718 vars->parms.guess = (vars->parms.high>3.0*vars->parms.guess)
1719 ? 2.0*vars->parms.guess
1720 : 0.5*(vars->parms.low + vars->parms.high);
1721 } else {
1722 /* Decrease parameter (to increase step norm) */
1723 vars->parms.high = vars->parms.guess;
1724 vars->parms.guess = 0.5*(vars->parms.low + vars->parms.high);
1725 }
1726 }
1727
1728 static void compute_step(sys,vars)
1729 slv0_system_t sys;
1730 struct calc_step_vars *vars;
1731 /**
1732 *** Computes the step based on the coefficients in vars.
1733 **/
1734 {
1735 int32 row,col;
1736 real64 tot1_norm2, tot2_norm2;
1737
1738 tot1_norm2 = sys->varstep1.norm2 + sys->mulstep1.norm2;
1739 tot2_norm2 = sys->varstep2.norm2 + sys->mulstep2.norm2;
1740 if( !sys->varstep.accurate ) {
1741 for( col=sys->varstep.rng->low ; col<=sys->varstep.rng->high ; ++col )
1742 if( (vars->alpha2 == 1.0) && (vars->alpha1 == 0.0) ) {
1743 sys->varstep.vec[col] = sys->maxstep *
1744 sys->varstep2.vec[col]/calc_sqrt_D0(tot2_norm2);
1745 } else if( (vars->alpha2 == 0.0) && (vars->alpha1 == 1.0) ) {
1746 sys->varstep.vec[col] = sys->maxstep *
1747 sys->varstep1.vec[col]/calc_sqrt_D0(tot1_norm2);
1748 } else if( (vars->alpha2 != 0.0) && (vars->alpha1 != 0.0) ) {
1749 sys->varstep.vec[col] = sys->maxstep*
1750 (
1751 vars->alpha2*sys->varstep2.vec[col]/calc_sqrt_D0(tot2_norm2) +
1752 vars->alpha1*sys->varstep1.vec[col]/calc_sqrt_D0(tot1_norm2)
1753 );
1754 }
1755 sys->varstep.accurate = TRUE;
1756 }
1757 if( !sys->mulstep.accurate ) {
1758 for( row=sys->mulstep.rng->low ; row<=sys->mulstep.rng->high ; ++row )
1759 if( (vars->alpha2 == 1.0) && (vars->alpha1 == 0.0) ) {
1760 sys->mulstep.vec[row] = sys->maxstep *
1761 sys->mulstep2.vec[row]/calc_sqrt_D0(tot2_norm2);
1762 } else if( (vars->alpha2 == 0.0) && (vars->alpha1 == 1.0) ) {
1763 sys->mulstep.vec[row] = sys->maxstep *
1764 sys->mulstep1.vec[row]/calc_sqrt_D0(tot1_norm2);
1765 } else if( (vars->alpha2 != 0.0) && (vars->alpha1 != 0.0) ) {
1766 sys->mulstep.vec[row] = sys->maxstep*
1767 (
1768 vars->alpha2*sys->mulstep2.vec[row]/calc_sqrt_D0(tot2_norm2) +
1769 vars->alpha1*sys->mulstep1.vec[row]/calc_sqrt_D0(tot1_norm2)
1770 );
1771 }
1772 sys->mulstep.accurate = TRUE;
1773 }
1774 #if DEBUG
1775 FPRINTF(LIF(sys),"Varstep: ");
1776 debug_out_vector(LIF(sys),sys,&(sys->varstep));
1777 FPRINTF(LIF(sys),"Mulstep: ");
1778 debug_out_vector(LIF(sys),sys,&(sys->mulstep));
1779 #endif
1780 }
1781
1782
1783 static void calc_step(sys, minor)
1784 slv0_system_t sys;
1785 int minor;
1786 /**
1787 *** Calculates step vector, based on sys->maxstep, and the varstep2/
1788 *** varstep1 and mulstep2/mulstep1 vectors. Nothing is assumed to be
1789 *** calculated, except the weights and the jacobian (scaled). Also,
1790 *** the step is not checked for legitimacy.
1791 *** NOTE: the step is scaled.
1792 **/
1793 {
1794 #define STEPSIZEERR_MAX 1e-4
1795 /* Step size must be determined this precisely */
1796 #define PARMRNG_MIN 1e-12
1797 /* OR parameter range must be this narrow to exit */
1798
1799 struct calc_step_vars vars;
1800 real64 tot1_norm2, tot2_norm2;
1801
1802 if( sys->varstep.accurate && sys->mulstep.accurate )
1803 return;
1804 if (sys->p.output.less_important) {
1805 FPRINTF(LIF(sys),"\n%-40s ---> %d\n", " Step trial",minor);
1806 }
1807
1808 tot1_norm2 = sys->varstep1.norm2 + sys->mulstep1.norm2;
1809 tot2_norm2 = sys->varstep2.norm2 + sys->mulstep2.norm2;
1810 if( (tot1_norm2 == 0.0) && (tot2_norm2 == 0.0) ) {
1811 /* Take no step at all */
1812 vars.alpha1 = 0.0;
1813 vars.alpha2 = 0.0;
1814 sys->maxstep = 0.0;
1815 sys->varstep.norm2 = 0.0;
1816 sys->mulstep.norm2 = 0.0;
1817
1818 } else if( (tot2_norm2 > 0.0) && OPTIMIZING(sys) ) {
1819 /* Stay in varstep2 direction */
1820 vars.alpha1 = 0.0;
1821 vars.alpha2 = 1.0;
1822 sys->maxstep = MIN(sys->maxstep,calc_sqrt_D0(tot2_norm2));
1823 sys->varstep.norm2 = calc_sqr_D0(sys->maxstep)*
1824 sys->varstep2.norm2/tot2_norm2;
1825 sys->mulstep.norm2 = calc_sqr_D0(sys->maxstep)*
1826 sys->mulstep2.norm2/tot2_norm2;
1827
1828 } else if( (tot2_norm2>0.0)&&(calc_sqrt_D0(tot2_norm2)<=sys->maxstep) ) {
1829 /* Attempt step in varstep2 direction */
1830 vars.alpha1 = 0.0;
1831 vars.alpha2 = 1.0;
1832 sys->maxstep = calc_sqrt_D0(tot2_norm2);
1833 sys->varstep.norm2 = calc_sqr_D0(sys->maxstep)*
1834 sys->varstep2.norm2/tot2_norm2;
1835 sys->mulstep.norm2 = calc_sqr_D0(sys->maxstep)*
1836 sys->mulstep2.norm2/tot2_norm2;
1837
1838 } else if( (tot2_norm2==0.0 || sys->s.block.current_size==1) &&
1839 (tot1_norm2 > 0.0) ) {
1840 /* Attempt step in varstep1 direction */
1841 vars.alpha1 = 1.0;
1842 vars.alpha2 = 0.0;
1843 if ( (sys->gamma.norm2/sys->Jgamma.norm2)*
1844 calc_sqrt_D0(sys->gamma.norm2) <= sys->maxstep )
1845 sys->maxstep = (sys->gamma.norm2/sys->Jgamma.norm2)*
1846 calc_sqrt_D0(sys->gamma.norm2);
1847 sys->varstep.norm2 = calc_sqr_D0(sys->maxstep)*
1848 sys->varstep1.norm2/tot1_norm2;
1849 sys->mulstep.norm2 = calc_sqr_D0(sys->maxstep)*
1850 sys->mulstep1.norm2/tot1_norm2;
1851
1852 } else {
1853 /* Attempt step in varstep1-varstep2 direction */
1854 vars.parms.low = 0.0;
1855 vars.parms.high = MAXDOUBLE;
1856 vars.parms.guess = 1.0;
1857 calc_2x2_system(sys,&vars);
1858 do {
1859 coefs_from_parm(sys, &vars);
1860 adjust_parms(sys, &vars);
1861 } while( fabs(vars.error) > STEPSIZEERR_MAX &&
1862 vars.parms.high - vars.parms.low > PARMRNG_MIN );
1863 if (sys->p.output.less_important) {
1864 FPRINTF(LIF(sys),"%-40s ---> %g\n",
1865 " parameter high", vars.parms.high);
1866 FPRINTF(LIF(sys),"%-40s ---> %g\n",
1867 " parameter low", vars.parms.low);
1868 FPRINTF(LIF(sys),"%-40s ---> %g\n",
1869 " Error in step length", vars.error);
1870 }
1871 sys->varstep.norm2 = step_norm2(sys, &vars);
1872 sys->mulstep.norm2 = 0.0;
1873 }
1874
1875 if (sys->p.output.less_important) {
1876 FPRINTF(LIF(sys),"%-40s ---> %g\n", " Alpha1 coefficient (normalized)",
1877 vars.alpha1);
1878 FPRINTF(LIF(sys),"%-40s ---> %g\n", " Alpha2 coefficient (normalized)",
1879 vars.alpha2);
1880 }
1881 compute_step(sys,&vars);
1882 return;
1883
1884 #undef STEPSIZEERR_MAX
1885 #undef PARMRNG_MIN
1886 }
1887
1888
1889
1890 /**
1891 *** Variable values maintenance
1892 *** ---------------------------
1893 *** restore_variables(sys)
1894 *** coef = required_coef_to_stay_inbounds(sys)
1895 *** apply_step(sys,coef)
1896 *** step_accepted(sys)
1897 *** change_maxstep(sys,maxstep)
1898 **/
1899
1900 static void restore_variables(sys)
1901 slv0_system_t sys;
1902 /**
1903 *** Restores the values of the variables before applying
1904 *** a step.
1905 **/
1906 {
1907 int32 col;
1908
1909 for( col = sys->J.reg.col.low; col <= sys->J.reg.col.high; col++ ) {
1910 struct var_variable *var = sys->vlist[mtx_col_to_org(sys->J.mtx,col)];
1911 var_set_value(var,sys->variables.vec[col]*sys->nominals.vec[col]);
1912 }
1913 }
1914
1915
1916 static real64 required_coef_to_stay_inbounds(sys)
1917 slv0_system_t sys;
1918 /**
1919 *** Calculates the maximum fraction of the step which can be
1920 *** taken without going out of bounds. If the entire step can be
1921 *** taken, 1.0 is returned. Otherwise a value less than 1 is
1922 *** returned. It is assumed that the current variable values
1923 *** are within their bounds. The step must be calculated.
1924 **/
1925 {
1926 real64 mincoef;
1927 int32 col;
1928
1929 if( sys->p.ignore_bounds )
1930 return(1.0);
1931
1932 mincoef = 1.0;
1933 for( col=sys->varstep.rng->low; col <= sys->varstep.rng->high; col++ ) {
1934 struct var_variable *var;
1935 real64 coef,dx,val,bnd;
1936 var = sys->vlist[mtx_col_to_org(sys->J.mtx,col)];
1937 coef = 1.0;
1938 dx = sys->varstep.vec[col] * sys->nominals.vec[col];
1939 bnd = var_upper_bound(var);
1940 if( (val=var_value(var)) + dx > bnd )
1941 coef = MIN((bnd-val)/dx, 1.0);
1942 bnd = var_lower_bound(var);
1943 if( val + dx < bnd )
1944 coef = MIN((bnd-val)/dx, 1.0);
1945 if( coef < mincoef )
1946 mincoef = coef;
1947 }
1948 return(mincoef);
1949 }
1950
1951
1952 #define TRUNCATE FALSE /* override projection */
1953 static void apply_step(sys)
1954 slv0_system_t sys;
1955 /**
1956 *** Adds sys->varstep to the variable values in block: projecting
1957 *** near bounds.
1958 **/
1959 {
1960 FILE *lif = LIF(sys);
1961 int nproj = 0;
1962 real64 bounds_coef = 1.0;
1963 int32 col;
1964
1965 if (TRUNCATE && (!sys->p.ignore_bounds))
1966 bounds_coef = required_coef_to_stay_inbounds(sys);
1967
1968 for( col=sys->varstep.rng->low; col <= sys->varstep.rng->high; col++ ) {
1969 struct var_variable *var;
1970 real64 dx,val,bnd;
1971 var = sys->vlist[mtx_col_to_org(sys->J.mtx,col)];
1972 dx = sys->nominals.vec[col]*sys->varstep.vec[col];
1973 val = var_value(var);
1974 if (bounds_coef < 1.0) {
1975 dx = dx*TOWARD_BOUNDS*bounds_coef;
1976 sys->varstep.vec[col] = dx/sys->nominals.vec[col];
1977 } else {
1978 if( !sys->p.ignore_bounds ) {
1979 if( val + dx > (bnd=var_upper_bound(var)) ) {
1980 dx = TOWARD_BOUNDS*(bnd-val);
1981 sys->varstep.vec[col] = dx/sys->nominals.vec[col];
1982 if (sys->p.output.less_important) {
1983 FPRINTF(lif,"%-40s ---> ",
1984 " Variable projected to upper bound");
1985 print_var_name(lif,sys,var); PUTC('\n',lif);
1986 }
1987 ++nproj;
1988 } else if( val + dx < (bnd=var_lower_bound(var)) ) {
1989 dx = TOWARD_BOUNDS*(bnd-val);
1990 sys->varstep.vec[col] = dx/sys->nominals.vec[col];
1991 if (sys->p.output.less_important) {
1992 FPRINTF(lif,"%-40s ---> ",
1993 " Variable projected to lower bound");
1994 print_var_name(lif,sys,var); PUTC('\n',lif);
1995 }
1996 ++nproj;
1997 }
1998 }
1999 }
2000 var_set_value(var,val+dx);
2001 }
2002
2003 if( !sys->p.ignore_bounds ) {
2004 if (nproj > 0) {
2005 square_norm(&(sys->varstep));
2006 sys->progress = calc_sqrt_D0
2007 (calc_sqrt_D0((sys->varstep.norm2 + sys->mulstep.norm2)*
2008 (sys->varstep1.norm2 + sys->mulstep1.norm2)));
2009 if (sys->p.output.less_important) {
2010 FPRINTF(lif,"%-40s ---> %g\n", " Projected step length (scaled)",
2011 calc_sqrt_D0(sys->varstep.norm2 + sys->mulstep.norm2));
2012 FPRINTF(lif,"%-40s ---> %g\n",
2013 " Projected progress", sys->progress);
2014 }
2015 }
2016 if (bounds_coef < 1.0) {
2017 square_norm(&(sys->varstep));
2018 if (sys->p.output.less_important) {
2019 FPRINTF(lif,"%-40s ---> %g\n",
2020 " Truncated step length (scaled)",
2021 calc_sqrt_D0(sys->varstep.norm2 + sys->mulstep.norm2));
2022 }
2023 sys->progress = calc_sqrt_D0
2024 (calc_sqrt_D0((sys->varstep.norm2 + sys->mulstep.norm2)*
2025 (sys->varstep1.norm2 + sys->mulstep1.norm2)));
2026 (calc_sqrt_D0(sys->varstep.norm2*sys->varstep1.norm2));
2027 if (sys->p.output.less_important) {
2028 FPRINTF(lif,"%-40s ---> %g\n",
2029 " Truncated progress", sys->progress);
2030 }
2031 }
2032 }
2033
2034 /* Allow weighted residuals to be recalculated at new point */
2035 sys->residuals.accurate = FALSE;
2036
2037 return;
2038 }
2039 #undef TRUNCATE
2040
2041 static void step_accepted(sys)
2042 slv0_system_t sys;
2043 /**
2044 *** This function should be called when the step is accepted.
2045 **/
2046 {
2047 /* Maintain update status on jacobian and weights */
2048 if (--(sys->update.jacobian) <= 0)
2049 sys->J.accurate = FALSE;
2050
2051 sys->ZBZ.accurate = FALSE;
2052 sys->variables.accurate = FALSE;
2053 sys->gradient.accurate = FALSE;
2054 sys->multipliers.accurate = FALSE;
2055 sys->stationary.accurate = FALSE;
2056 sys->newton.accurate = FALSE;
2057 sys->Bnewton.accurate = FALSE;
2058 sys->nullspace.accurate = FALSE;
2059 sys->gamma.accurate = FALSE;
2060 sys->Jgamma.accurate = FALSE;
2061 sys->varstep1.accurate = FALSE;
2062 sys->Bvarstep1.accurate = FALSE;
2063 sys->varstep2.accurate = FALSE;
2064 sys->Bvarstep2.accurate = FALSE;
2065 sys->mulstep1.accurate = FALSE;
2066 sys->mulstep2.accurate = FALSE;
2067 sys->varstep.accurate = FALSE;
2068 sys->mulstep.accurate = FALSE;
2069
2070 if( !OPTIMIZING(sys) ) {
2071 sys->ZBZ.accurate = TRUE;
2072 sys->gradient.accurate = TRUE;
2073 sys->multipliers.accurate = TRUE;
2074 sys->stationary.accurate = TRUE;
2075 sys->Bnewton.accurate = TRUE;
2076 sys->nullspace.accurate = TRUE;
2077 sys->Bvarstep1.accurate = TRUE;
2078 sys->Bvarstep2.accurate = TRUE;
2079 }
2080 }
2081
2082 static void change_maxstep(sys,maxstep)
2083 slv0_system_t sys;
2084 real64 maxstep;
2085 /**
2086 *** This function changes sys->maxstep to the given number and should be
2087 *** called whenever sys->maxstep is to be changed.
2088 **/
2089 {
2090 sys->maxstep = maxstep;
2091 sys->varstep.accurate = FALSE;
2092 if( OPTIMIZING(sys) ) sys->mulstep.accurate = FALSE;
2093 }
2094
2095
2096
2097 /**
2098 *** Block routines
2099 *** --------------
2100 *** feas = block_feasible(sys)
2101 *** insure_bounds(sys,var)
2102 *** move_to_next_block(sys)
2103 *** find_next_unconverged_block(sys)
2104 **/
2105
2106 static boolean block_feasible(sys)
2107 slv0_system_t sys;
2108 /**
2109 *** Returns TRUE if the current block is feasible, FALSE otherwise.
2110 *** It is assumed that the residuals have been computed.
2111 **/
2112 {
2113 int32 row;
2114
2115 if( !sys->s.calc_ok )
2116 return(FALSE);
2117
2118 for( row = sys->J.reg.row.low; row <= sys->J.reg.row.high; row++ ) {
2119 struct rel_relation *rel = sys->rlist[mtx_row_to_org(sys->J.mtx,row)];
2120 if( !rel_satisfied(rel) ) return FALSE;
2121 }
2122 return TRUE;
2123 }
2124
2125 static void insure_bounds(sys,var)
2126 slv0_system_t sys;
2127 struct var_variable *var;
2128 /**
2129 *** Insures that the variable value is within its bounds.
2130 **/
2131 {
2132 real64 val,low,high;
2133 FILE *mif = MIF(sys);
2134
2135 if( sys->p.ignore_bounds )
2136 return;
2137
2138 low = var_lower_bound(var);
2139 high = var_upper_bound(var);
2140 val = var_value(var);
2141 if( low > high ) {
2142 FPRINTF(mif,"Bounds for variable ");
2143 print_var_name(mif,sys,var);
2144 FPRINTF(mif," are inconsistent [%g,%g].\n",low,high);
2145 FPRINTF(mif,"Bounds will be swapped.\n");
2146 var_set_upper_bound(var, low);
2147 var_set_lower_bound(var, high);
2148 low = var_lower_bound(var);
2149 high = var_upper_bound(var);
2150 }
2151
2152 if( low > val ) {
2153 FPRINTF(mif,"Variable ");
2154 print_var_name(mif,sys,var);
2155 FPRINTF(mif," was initialized below its lower bound.\n");
2156 FPRINTF(mif,"It will be moved to its lower bound.\n");
2157 var_set_value(var, low);
2158 } else if( val > high ) {
2159 FPRINTF(mif,"Variable ");
2160 print_var_name(mif,sys,var);
2161 FPRINTF(mif," was initialized above its upper bound.\n");
2162 FPRINTF(mif,"It will be moved to its upper bound.\n");
2163 var_set_value(var, high);
2164 }
2165 }
2166
2167 static void move_to_next_block(sys)
2168 slv0_system_t sys;
2169 /**
2170 *** Moves on to the next block, updating all of the solver information.
2171 *** To move to the first block, set sys->s.block.current_block to -1 before
2172 *** calling. If already at the last block, then sys->s.block.current_block
2173 *** will equal the number of blocks and the system will be declared
2174 *** converged. Otherwise, the residuals for the new block will be computed
2175 *** and sys->s.calc_ok set according.
2176 **/
2177 {
2178 #ifdef KAA_DEBUG
2179 int32 klowcol, khighcol;
2180 int32 klowrow, khighrow;
2181 struct rel_relation *krel;
2182 struct var_variable *kvar;
2183 double ktime =0;
2184 int k, ktmp;
2185 #endif
2186
2187 /* sys->clock = tm_cpu_time(); */
2188
2189 if( sys->s.block.current_block >= 0 ) {
2190
2191 int32 row;
2192 int32 col;
2193 int32 ci;
2194 struct var_variable *var;
2195 struct rel_relation *rel;
2196
2197 /* Record cost accounting info here. */
2198 ci=sys->s.block.current_block;
2199 sys->s.cost[ci].size=sys->s.block.current_size;
2200 sys->s.cost[ci].iterations=sys->s.block.iteration;
2201 sys->s.cost[ci].funcs=sys->s.block.funcs;
2202 sys->s.cost[ci].jacs=sys->s.block.jacs;
2203 sys->s.cost[ci].functime=sys->s.block.functime;
2204 sys->s.cost[ci].jactime=sys->s.block.jactime;
2205 sys->s.cost[ci].time=sys->s.block.cpu_elapsed;
2206 sys->s.cost[ci].resid=sys->s.block.residual;
2207
2208 #undef KAA_DEBUG
2209 #ifdef KAA_DEBUG
2210 if (sys->s.block.current_size>1) {
2211 FPRINTF(stderr,"Block %d took %d iterations\n",
2212 sys->s.block.current_block,sys->s.block.iteration);
2213 }
2214 #endif /* KAA_DEBUG */
2215
2216 /* De-initialize previous block */
2217 if (sys->p.output.less_important && (sys->s.block.current_size >1 ||
2218 sys->iarray[SP0_LIFDS])) {
2219 FPRINTF(LIF(sys),"Block %d converged.\n",
2220 sys->s.block.current_block);
2221 }
2222 for( col=sys->J.reg.col.low; col <= sys->J.reg.col.high; col++ ) {
2223 var = sys->vlist[mtx_col_to_org(sys->J.mtx,col)];
2224 var_set_in_block(var,FALSE);
2225 }
2226 for( row=sys->J.reg.row.low; row <= sys->J.reg.row.high; row++ ) {
2227 rel = sys->rlist[mtx_row_to_org(sys->J.mtx,row)];
2228 rel_set_in_block(rel,FALSE);
2229 }
2230 sys->s.block.previous_total_size += sys->s.block.current_size;
2231 }
2232
2233 sys->s.block.current_block += 1;
2234 if( sys->s.block.current_block < sys->s.block.number_of ) {
2235 int32 row;
2236 int32 col;
2237 boolean ok;
2238
2239 /* Initialize next block */
2240 if( OPTIMIZING(sys) )
2241 mtx_region(&(sys->J.reg), 0, sys->rank-1, 0, sys->vused-1 );
2242 else
2243 mtx_block(sys->J.mtx,sys->s.block.current_block,&(sys->J.reg));
2244
2245 row = sys->J.reg.row.high - sys->J.reg.row.low + 1;
2246 col = sys->J.reg.col.high - sys->J.reg.col.low + 1;
2247 sys->s.block.current_size = MAX(row,col);
2248
2249 sys->s.block.iteration = 0;
2250 sys->s.block.funcs = 0;
2251 sys->s.block.jacs = 0;
2252 sys->s.block.cpu_elapsed = 0.0;
2253 sys->s.block.functime = 0.0;
2254 sys->s.block.jactime = 0.0;
2255
2256 /*************************************************************************/
2257 for( col=sys->J.reg.col.low; col <= sys->J.reg.col.high; col++ ) {
2258 struct var_variable *var;
2259 var = sys->vlist[mtx_col_to_org(sys->J.mtx,col)];
2260 var_set_in_block(var,TRUE);
2261 insure_bounds(sys,var);
2262 }
2263 for( row=sys->J.reg.row.low; row <= sys->J.reg.row.high; row++ ) {
2264 struct rel_relation *rel;
2265 rel = sys->rlist[mtx_row_to_org(sys->J.mtx,row)];
2266 rel_set_in_block(rel,TRUE);
2267 }
2268 /* REORDER */
2269 if( sys->s.block.current_size > 1L )
2270 linsol_reorder(sys->J.sys,&(sys->J.reg));
2271
2272 if(sys->p.output.less_important && (sys->iarray[SP0_LIFDS] ||
2273 sys->s.block.current_size > 1)) {
2274 debug_delimiter(LIF(sys));
2275 debug_delimiter(LIF(sys));
2276 }
2277 if(sys->p.output.less_important && sys->iarray[SP0_LIFDS]) {
2278 FPRINTF(LIF(sys),"\n%-40s ---> %d in [%d..%d]\n",
2279 "Current block number", sys->s.block.current_block,
2280 0, sys->s.block.number_of-1);
2281 FPRINTF(LIF(sys),"%-40s ---> %d\n", "Current block size",
2282 sys->s.block.current_size);
2283 }
2284 sys->s.calc_ok = TRUE;
2285
2286 if( !(ok = calc_objective(sys)) )
2287 FPRINTF(MIF(sys),"Objective calculation errors detected.\n");
2288 if(sys->p.output.less_important && sys->obj) {
2289 FPRINTF(LIF(sys),"%-40s ---> %g\n", "Objective", sys->objective);
2290 }
2291 sys->s.calc_ok = sys->s.calc_ok && ok;
2292
2293 sys->residuals.accurate = FALSE;
2294 if( !(ok = calc_residuals(sys)) )
2295 FPRINTF(MIF(sys),"Residual calculation errors detected.\n");
2296 if(sys->p.output.less_important && (sys->s.block.current_size >1 ||
2297 sys->iarray[SP0_LIFDS])) {
2298 FPRINTF(LIF(sys),"%-40s ---> %g\n", "Residual norm (unscaled)",
2299 sys->s.block.residual);
2300 }
2301 sys->s.calc_ok = sys->s.calc_ok && ok;
2302
2303 /* Must be updated as soon as required */
2304 sys->J.accurate = FALSE;
2305 sys->update.weights = 0;
2306 sys->update.nominals = 0;
2307 sys->ZBZ.accurate = FALSE;
2308 sys->variables.accurate = FALSE;
2309 sys->gradient.accurate = FALSE;
2310 sys->multipliers.accurate = FALSE;
2311 sys->stationary.accurate = FALSE;
2312 sys->newton.accurate = FALSE;
2313 sys->Bnewton.accurate = FALSE;
2314 sys->nullspace.accurate = FALSE;
2315 sys->gamma.accurate = FALSE;
2316 sys->Jgamma.accurate = FALSE;
2317 sys->varstep1.accurate = FALSE;
2318 sys->Bvarstep1.accurate = FALSE;
2319 sys->varstep2.accurate = FALSE;
2320 sys->Bvarstep2.accurate = FALSE;
2321 sys->mulstep1.accurate = FALSE;
2322 sys->mulstep2.accurate = FALSE;
2323 sys->varstep.accurate = FALSE;
2324 sys->mulstep.accurate = FALSE;
2325
2326 if( !OPTIMIZING(sys) ) {
2327 sys->ZBZ.accurate = TRUE;
2328 sys->gradient.accurate = TRUE;
2329 sys->multipliers.accurate = TRUE;
2330 sys->stationary.accurate = TRUE;
2331 sys->Bnewton.accurate = TRUE;
2332 sys->nullspace.accurate = TRUE;
2333 sys->Bvarstep1.accurate = TRUE;
2334 sys->Bvarstep2.accurate = TRUE;
2335 }
2336
2337 } else {
2338 boolean ok;
2339 /**
2340 *** Before we claim convergence, we must check if we left behind
2341 *** some unassigned relations. If and only if they happen to be
2342 *** satisfied at the current point, convergence has been obtained.
2343 ***
2344 *** Also insures that all included relations have valid residuals.
2345 *** Included inequalities will have correct residuals.
2346 *** Unsatisfied included inequalities cause inconsistency.
2347 ***
2348 *** This of course ignores that fact an objective function might
2349 *** be present. Then, feasibility isn't enough, is it now.
2350 **/
2351 if( sys->s.struct_singular ) {
2352 /* black box w/singletons provoking bug here, maybe */
2353 sys->s.block.current_size = sys->rused - sys->rank;
2354 if(sys->p.output.less_important) {
2355 debug_delimiter(LIF(sys));
2356 FPRINTF(LIF(sys),"%-40s ---> %d\n", "Unassigned Relations",
2357 sys->s.block.current_size);
2358 }
2359 sys->J.reg.row.low = sys->J.reg.col.low = sys->rank;
2360 sys->J.reg.row.high = sys->J.reg.col.high = sys->rused - 1;
2361 sys->residuals.accurate = FALSE;
2362 if( !(ok=calc_residuals(sys)) )
2363 FPRINTF(MIF(sys),"Residual calculation errors detected.\n");
2364 if(sys->p.output.less_important) {
2365 FPRINTF(LIF(sys),"%-40s ---> %g\n", "Residual norm (unscaled)",
2366 sys->s.block.residual);
2367 }
2368 if( block_feasible(sys) ) {
2369 if(sys->p.output.less_important) {
2370 FPRINTF(LIF(sys),"\nUnassigned relations ok. You lucked out.\n");
2371 }
2372 sys->s.converged = TRUE;
2373 } else {
2374 if(sys->p.output.less_important) {
2375 FPRINTF(LIF(sys),"\nProblem inconsistent: %s.\n",
2376 "Unassigned relations not satisfied");
2377 }
2378 sys->s.inconsistent = TRUE;
2379 }
2380 if(sys->p.output.less_important) {
2381 debug_delimiter(LIF(sys));
2382 }
2383 } else {
2384 sys->s.converged = TRUE;
2385 }
2386 /* nearly done checking. Must verify included inequalities if
2387 we think equalities are ok. */
2388 if (sys->s.converged) {
2389 sys->s.inconsistent=(!calc_inequalities(sys));
2390 }
2391 }
2392 }
2393
2394 static void find_next_unconverged_block(sys)
2395 slv0_system_t sys;
2396 /**
2397 *** Moves to next unconverged block, assuming that the current block has
2398 *** converged (or is -1, to start).
2399 **/
2400 {
2401 do {
2402 move_to_next_block(sys);
2403 } while( !sys->s.converged && block_feasible(sys) && !OPTIMIZING(sys) );
2404 }
2405
2406
2407 /**
2408 *** Iteration begin/end routines
2409 *** ----------------------------
2410 *** iteration_begins(sys)
2411 *** iteration_ends(sys)
2412 **/
2413
2414 static void iteration_begins(sys)
2415 slv0_system_t sys;
2416 /**
2417 *** Prepares sys for entering an iteration, increasing the iteration counts
2418 *** and starting the clock.
2419 **/
2420 {
2421 sys->clock = tm_cpu_time();
2422 ++(sys->s.block.iteration);
2423 ++(sys->s.iteration);
2424 if(sys->p.output.less_important&& (sys->s.block.current_size >1 ||
2425 sys->iarray[SP0_LIFDS])) {
2426 FPRINTF(LIF(sys),"\n%-40s ---> %d\n",
2427 "Iteration", sys->s.block.iteration);
2428 FPRINTF(LIF(sys),"%-40s ---> %d\n",
2429 "Total iteration", sys->s.iteration);
2430 }
2431 }
2432
2433 static void iteration_ends(sys)
2434 slv0_system_t sys;
2435 /**
2436 *** Prepares sys for exiting an iteration, stopping the clock and recording
2437 *** the cpu time.
2438 **/
2439 {
2440 double cpu_elapsed; /* elapsed this iteration */
2441
2442 cpu_elapsed = (double)(tm_cpu_time() - sys->clock);
2443 sys->s.block.cpu_elapsed += cpu_elapsed;
2444 sys->s.cpu_elapsed += cpu_elapsed;
2445 if(sys->p.output.less_important && (sys->s.block.current_size >1 ||
2446 sys->iarray[SP0_LIFDS])) {
2447 FPRINTF(LIF(sys),"%-40s ---> %g\n",
2448 "Elapsed time", sys->s.block.cpu_elapsed);
2449 FPRINTF(LIF(sys),"%-40s ---> %g\n",
2450 "Total elapsed time", sys->s.cpu_elapsed);
2451 }
2452 }
2453
2454 static void update_status(sys)
2455 slv0_system_t sys;
2456 /**
2457 *** Updates the solver status.
2458 **/
2459 {
2460 boolean unsuccessful;
2461
2462 if( !sys->s.converged ) {
2463 sys->s.time_limit_exceeded =
2464 abs(sys->s.block.cpu_elapsed >= sys->p.time_limit);
2465 sys->s.iteration_limit_exceeded =
2466 abs(sys->s.block.iteration >= sys->p.iteration_limit);
2467 }
2468
2469 unsuccessful = sys->s.diverged || sys->s.inconsistent ||
2470 sys->s.iteration_limit_exceeded || sys->s.time_limit_exceeded;
2471
2472 sys->s.ready_to_solve =abs( !unsuccessful && !sys->s.converged);
2473 sys->s.ok = abs(!unsuccessful &&
2474 sys->s.calc_ok && !sys->s.struct_singular);
2475 }
2476
2477 /**
2478 *** External routines
2479 *** -----------------
2480 *** See slv.h
2481 **/
2482
2483 static SlvClientToken slv0_create(slv_system_t server, int *statusindex)
2484 {
2485 slv0_system_t sys;
2486 FILE *fplif, *fpmif;
2487
2488 fpmif = stderr; /* will set up a proper file handle eventually */
2489 fplif = fpmif;
2490
2491 sys = (slv0_system_t)ascmalloc( sizeof(struct slv0_system_structure) );
2492 if (sys==NULL) {
2493 *statusindex = 1;
2494 return sys;
2495 }
2496 mem_zero_byte_cast(sys,0,sizeof(struct slv0_system_structure));
2497 sys->integrity = OK;
2498 sys->p.output.more_important = stdout;
2499 sys->p.output.less_important = NULL;
2500 sys->p.tolerance.pivot = 0.1; /* scaled */
2501 sys->p.tolerance.singular = 1e-12; /* scaled */
2502 sys->p.tolerance.feasible = 1e-8; /* unscaled */
2503 sys->p.tolerance.stationary = 1e-8; /* scaled */
2504 sys->p.tolerance.termination = 1e-12; /* scaled */
2505 sys->p.time_limit = 1500.0;
2506 sys->p.iteration_limit = 100;
2507 sys->p.partition = TRUE;
2508 sys->p.ignore_bounds = FALSE;
2509 sys->p.whose = slv0_solver_number;
2510 sys->p.rho = 1.0;
2511 sys->p.sp.iap=&(sys->iarray[0]); /* all defaults in iarray are 0 */
2512 sys->s.ok = TRUE;
2513 sys->s.calc_ok = TRUE;
2514 sys->s.costsize = 0;
2515 sys->s.cost = NULL; /*redundant, but sanity preserving */
2516
2517 return(sys);
2518 }
2519
2520 static void destroy_matrices(sys)
2521 slv0_system_t sys;
2522 {
2523 if( sys->J.sys ) {
2524 int count = linsol_number_of_rhs(sys->J.sys)-1;
2525 for( ; count >= 0; count-- )
2526 destroy_array(linsol_get_rhs(sys->J.sys,count));
2527 mtx_destroy(linsol_get_matrix(sys->J.sys));
2528 linsol_destroy(sys->J.sys);
2529 if( sys->J.relpivots ) set_destroy( sys->J.relpivots );
2530 if( sys->J.varpivots ) set_destroy( sys->J.varpivots );
2531 sys->J.sys = NULL;
2532 }
2533 if( sys->B ) {
2534 struct hessian_data *update;
2535 for( update=sys->B; update != NULL; ) {
2536 struct hessian_data *handle;
2537 handle = update;
2538 update = update->next;
2539 destroy_array(handle->y.vec);
2540 destroy_array(handle->Bs.vec);
2541 ascfree(handle);
2542 }
2543 sys->B = NULL;
2544 }
2545 if( sys->ZBZ.order > 0 ) {
2546 int i;
2547 for( i = 0; i < sys->ZBZ.order; i++ )
2548 destroy_array(sys->ZBZ.mtx[i]);
2549 destroy_array(sys->ZBZ.mtx);
2550 destroy_array(sys->ZBZ.ZBs);
2551 destroy_array(sys->ZBZ.Zy);
2552 sys->ZBZ.order = 0;
2553 }
2554 }
2555
2556 static void destroy_vectors(sys)
2557 slv0_system_t sys;
2558 {
2559 destroy_array(sys->nominals.vec);
2560 destroy_array(sys->weights.vec);
2561 destroy_array(sys->variables.vec);
2562 destroy_array(sys->residuals.vec);
2563 destroy_array(sys->gradient.vec);
2564 destroy_array(sys->multipliers.vec);
2565 destroy_array(sys->stationary.vec);
2566 destroy_array(sys->newton.vec);
2567 destroy_array(sys->Bnewton.vec);
2568 destroy_array(sys->nullspace.vec);
2569 destroy_array(sys->gamma.vec);
2570 destroy_array(sys->Jgamma.vec);
2571 destroy_array(sys->varstep1.vec);
2572 destroy_array(sys->Bvarstep1.vec);
2573 destroy_array(sys->varstep2.vec);
2574 destroy_array(sys->Bvarstep2.vec);
2575 destroy_array(sys->mulstep1.vec);
2576 destroy_array(sys->mulstep2.vec);
2577 destroy_array(sys->varstep.vec);
2578 destroy_array(sys->mulstep.vec);
2579 }
2580
2581 static void slv0_closefiles(sys)
2582 slv0_system_t sys;
2583 {
2584 return;
2585 }
2586
2587 static void slv0_set_var_list(slv0_system_t sys,struct var_variable **vlist)
2588 {
2589 static struct var_variable *empty_list[] = {NULL};
2590 check_system(sys);
2591 if( sys->vlist_user == NULL )
2592 if( sys->vlist != NULL && pl_length(sys->vlist) > 0 )
2593 ascfree( (POINTER)(sys->vlist) );
2594 sys->vlist_user = vlist;
2595 sys->vlist = (vlist==NULL ? empty_list : vlist);
2596 sys->s.ready_to_solve = FALSE;
2597 }
2598
2599 static struct var_variable **slv0_get_var_list(sys)
2600 slv0_system_t sys;
2601 {
2602 check_system(sys);
2603 return( sys->vlist_user );
2604 }
2605
2606 static void slv0_set_rel_list(slv0_system_t sys, struct rel_relation **rlist)
2607 {
2608 static struct rel_relation *empty_list[] = {NULL};
2609 check_system(sys);
2610 sys->rlist_user = rlist;
2611 sys->rlist = (rlist==NULL ? empty_list : rlist);
2612 sys->s.ready_to_solve = FALSE;
2613 }
2614
2615 static struct rel_relation **slv0_get_rel_list(sys)
2616 slv0_system_t sys;
2617 {
2618 check_system(sys);
2619 return( sys->rlist_user );
2620 }
2621
2622 static int slv0_count_vars(sys,vfilter)
2623 slv0_system_t sys;
2624 var_filter_t *vfilter;
2625 {
2626 struct var_variable **vp;
2627 int32 count = 0;
2628 check_system(sys);
2629 for( vp=sys->vlist; *vp != NULL; vp++ )
2630 if( var_apply_filter(*vp,vfilter) ) ++count;
2631 return( count );
2632 }
2633
2634 static int slv0_count_rels(slv0_system_t sys,rel_filter_t *rfilter)
2635 {
2636 struct rel_relation **rp;
2637 int32 count = 0;
2638 check_system(sys);
2639 for( rp=sys->rlist; *rp != NULL; rp++ )
2640 if( rel_apply_filter(*rp,rfilter) ) ++count;
2641 return( count );
2642 }
2643
2644 static int slv0_eligible_solver(slv_system_t server)
2645 {
2646 struct rel_relation **rp;
2647 for( rp=slv_get_solvers_rel_list(server); *rp != NULL ; ++rp ) {
2648 if( rel_less(*rp) || rel_greater(*rp) ) return(FALSE);
2649 }
2650 return(TRUE);
2651 }
2652
2653 static void slv0_get_parameters(slv_system_t server, SlvClientToken asys,
2654 slv_parameters_t *parameters)
2655 {
2656 slv0_system_t sys;
2657 sys = SLV0(asys);
2658 if (check_system(sys)) return;
2659 mem_copy_cast(&(sys->p),parameters,sizeof(slv_parameters_t));
2660 }
2661
2662 static void slv0_set_parameters(slv_system_t server, SlvClientToken asys,
2663 slv_parameters_t *parameters)
2664 {
2665 slv0_system_t sys;
2666 sys = SLV0(asys);
2667 if (check_system(sys)) return;
2668 mem_copy_cast(parameters,&(sys->p),sizeof(slv_parameters_t));
2669 }
2670
2671 static void slv0_get_status(slv_system_t server, SlvClientToken asys,
2672 slv_status_t *status)
2673 {
2674 slv0_system_t sys;
2675 sys = SLV0(asys);
2676 if (check_system(sys)) return;
2677 mem_copy_cast(&(sys->s),status,sizeof(slv_status_t));
2678 }
2679
2680 static linsolqr_system_t slv0_get_linsolqr_sys(slv_system_t server,
2681 SlvClientToken asys)
2682 {
2683 return NULL;
2684 }
2685
2686 static linsol_system_t slv0_get_linsol_sys(slv_system_t server,
2687 SlvClientToken asys)
2688 {
2689 slv0_system_t sys;
2690 sys = SLV0(asys);
2691 if (check_system(sys)) return NULL;
2692 return(sys->J.sys);
2693 }
2694
2695 static void sort_unassigned_rows(slv0_system_t sys) {
2696 /**
2697 *** Rearranges unassigned rows of the matrix as follows
2698 *** (note that unassigned rows may be from unassigned relations
2699 *** included or unincluded or empty rows that are unused):
2700 *** rows included && !assigned | rows of unincluded eqns | empty rows.
2701 *** Empty in this context means row unassociated with eqn, not whether
2702 *** there is incidence in that row.
2703 *** (mtx_output_assign no longer puts empties up into the 0 .. rtot-1
2704 *** region.)
2705 *** Joe correctly contends that this is a solver job and not an output
2706 *** assign postprocessing job mtx could do.
2707 *** (mtx_output assign does in fact leave unassigned rows _with_incidence
2708 *** up against the assigned region, but rows with no incidence
2709 *** are mixed up with unincluded rows.
2710 **/
2711 int32 i,j,k,rank,rinc,rtot,cap;
2712 mtx_matrix_t mtx;
2713 mtx=sys->J.mtx;
2714 rank=sys->rank;
2715 rinc=sys->rused;
2716 rtot=sys->rtot;
2717 cap=sys->cap;
2718 k=cap-1;
2719 j=rtot-1;
2720 /* now move all included but unassigned rows up against assigned rows */
2721 for (i=rank; i<rinc; i++) {
2722 if (!rel_included(sys->rlist[mtx_row_to_org(mtx,i)]) ||
2723 !rel_active(sys->rlist[mtx_row_to_org(mtx,i)]) ) {
2724 /* if unincluded found in range we will check for convergence ...*/
2725 while (!rel_included(sys->rlist[mtx_row_to_org(mtx,j)]) ||
2726 !rel_active(sys->rlist[mtx_row_to_org(mtx,j)]) ) j--;
2727 /* find last included row */
2728 if (j > i) mtx_swap_rows(mtx,i,j--);
2729 else FPRINTF(stderr,"Bug in slv0.c:sort_unassigned_rows\n");
2730 /* if this message is seen we would have swapped included into unincls
2731 an accounting error has taken place elsewhere in presolve*/
2732 }
2733 } /* all included but unassigned rows now against bottom of assigned region*/
2734 }
2735
2736 static void structural_analysis(slv_system_t server, slv0_system_t sys)
2737 /**
2738 *** Performs structural analysis on the system, setting the flags in
2739 *** status. The problem must be set up, the relation/variable list
2740 *** must be non-NULL, and their sizes must be in sys->s.v/r.total. The
2741 *** jacobian (linear) system must be created and have the correct order
2742 *** (stored in sys->cap). Everything else will be determined here.
2743 **/
2744 {
2745 struct var_variable **vp;
2746 var_filter_t vfilter;
2747 struct rel_relation **rp;
2748 rel_filter_t rfilter;
2749
2750 /**
2751 *** The server has marked incidenct flags already.
2752 **/
2753 /* count included equalities */
2754 rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE);
2755 rfilter.matchvalue = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE);
2756 sys->rused = slv_count_solvers_rels(server,&rfilter);
2757
2758 /* count free and incident vars */
2759 vfilter.matchbits = (VAR_FIXED | VAR_INCIDENT | VAR_SVAR | VAR_ACTIVE);
2760 vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ACTIVE);
2761 sys->vused = slv_count_solvers_vars(server,&vfilter);
2762
2763 /* Generate incidence matrix */
2764 mtx_clear(sys->J.mtx);
2765 for( rp = sys->rlist ; *rp != NULL ; ++rp )
2766 if( rel_apply_filter(*rp,&rfilter) ) {
2767 relman_get_incidence(*rp,&vfilter,sys->J.mtx);
2768 }
2769
2770 /* Symbolic analysis */
2771 sys->rtot = slv_get_num_solvers_rels(server);
2772 sys->vtot = slv_get_num_solvers_vars(server);
2773 mtx_output_assign(sys->J.mtx,sys->rtot,sys->vtot);
2774 /* symbolic rank is set */
2775 sys->rank = mtx_symbolic_rank(sys->J.mtx);
2776 sys->ZBZ.order = sys->obj ? (sys->vused - sys->rank) : 0;
2777 /* eventually we should let another client do this */
2778 if( sys->p.partition && !OPTIMIZING(sys) ) {
2779 mtx_partition(sys->J.mtx);
2780 }
2781 sort_unassigned_rows(sys);
2782
2783 /* Initialize Status */
2784 sys->s.over_defined = (sys->rused > sys->vused);
2785 sys->s.under_defined = (sys->rused < sys->vused);
2786 sys->s.struct_singular = (sys->rank < sys->rused);
2787 sys->s.block.number_of = mtx_number_of_blocks(sys->J.mtx);
2788 }
2789
2790 static void create_matrices(slv_system_t server, slv0_system_t sys)
2791 {
2792 sys->J.sys = linsol_create();
2793 sys->J.mtx = mtx_create();
2794 mtx_set_order(sys->J.mtx,sys->cap);
2795 linsol_set_matrix(sys->J.sys,sys->J.mtx);
2796 linsol_set_pivot_zero(sys->J.sys, sys->p.tolerance.singular);
2797 linsol_set_pivot_tolerance(sys->J.sys, sys->p.tolerance.pivot);
2798 /* rhs 0 for sys->multipliers */
2799 sys->J.rhs = create_array(sys->cap,real64);
2800 linsol_add_rhs(sys->J.sys,sys->J.rhs,TRUE);
2801 /* rhs 1 for sys->newton */
2802 sys->J.rhs = create_array(sys->cap,real64);
2803 linsol_add_rhs(sys->J.sys,sys->J.rhs,FALSE);
2804 /* rhs 2 for sys->mulstep2 */
2805 sys->J.rhs = create_array(sys->cap,real64);
2806 linsol_add_rhs(sys->J.sys,sys->J.rhs,TRUE);
2807 sys->J.relpivots = set_create(sys->cap);
2808 sys->J.varpivots = set_create(sys->cap);
2809
2810 structural_analysis(server,sys);
2811 sys->ZBZ.mtx = create_array(sys->ZBZ.order,real64 *);
2812 if( sys->ZBZ.mtx ) {
2813 int i;
2814 for( i=0; i<sys->ZBZ.order; i++ )
2815 sys->ZBZ.mtx[i] = create_array(sys->ZBZ.order,real64);
2816 }
2817 sys->ZBZ.ZBs = create_array(sys->ZBZ.order,real64);
2818 sys->ZBZ.Zy = create_array(sys->ZBZ.order,real64);
2819 }
2820
2821 static void create_vectors(sys)
2822 slv0_system_t sys;
2823 {
2824
2825 sys->nominals.vec = create_array(sys->cap,real64);
2826 sys->nominals.rng = &(sys->J.reg.col);
2827 sys->weights.vec = create_array(sys->cap,real64);
2828 sys->weights.rng = &(sys->J.reg.row);
2829 sys->variables.vec = create_array(sys->cap,real64);
2830 sys->variables.rng = &(sys->J.reg.col);
2831 sys->residuals.vec = create_array(sys->cap,real64);
2832 sys->residuals.rng = &(sys->J.reg.row);
2833 if( OPTIMIZING(sys) ) {
2834 sys->gradient.vec = create_array(sys->cap,real64);
2835 sys->gradient.rng = &(sys->J.reg.col);
2836 sys->multipliers.vec = create_array(sys->cap,real64);
2837 sys->multipliers.rng = &(sys->J.reg.row);
2838 sys->stationary.vec = create_array(sys->cap,real64);
2839