src/glpmpl03.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
alpar@1
     1
/* glpmpl03.c */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#define _GLPSTD_ERRNO
alpar@1
    26
#define _GLPSTD_STDIO
alpar@1
    27
#include "glpenv.h"
alpar@1
    28
#include "glpmpl.h"
alpar@1
    29
alpar@1
    30
/**********************************************************************/
alpar@1
    31
/* * *                   FLOATING-POINT NUMBERS                   * * */
alpar@1
    32
/**********************************************************************/
alpar@1
    33
alpar@1
    34
/*----------------------------------------------------------------------
alpar@1
    35
-- fp_add - floating-point addition.
alpar@1
    36
--
alpar@1
    37
-- This routine computes the sum x + y. */
alpar@1
    38
alpar@1
    39
double fp_add(MPL *mpl, double x, double y)
alpar@1
    40
{     if (x > 0.0 && y > 0.0 && x > + 0.999 * DBL_MAX - y ||
alpar@1
    41
          x < 0.0 && y < 0.0 && x < - 0.999 * DBL_MAX - y)
alpar@1
    42
         error(mpl, "%.*g + %.*g; floating-point overflow",
alpar@1
    43
            DBL_DIG, x, DBL_DIG, y);
alpar@1
    44
      return x + y;
alpar@1
    45
}
alpar@1
    46
alpar@1
    47
/*----------------------------------------------------------------------
alpar@1
    48
-- fp_sub - floating-point subtraction.
alpar@1
    49
--
alpar@1
    50
-- This routine computes the difference x - y. */
alpar@1
    51
alpar@1
    52
double fp_sub(MPL *mpl, double x, double y)
alpar@1
    53
{     if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y ||
alpar@1
    54
          x < 0.0 && y > 0.0 && x < - 0.999 * DBL_MAX + y)
alpar@1
    55
         error(mpl, "%.*g - %.*g; floating-point overflow",
alpar@1
    56
            DBL_DIG, x, DBL_DIG, y);
alpar@1
    57
      return x - y;
alpar@1
    58
}
alpar@1
    59
alpar@1
    60
/*----------------------------------------------------------------------
alpar@1
    61
-- fp_less - floating-point non-negative subtraction.
alpar@1
    62
--
alpar@1
    63
-- This routine computes the non-negative difference max(0, x - y). */
alpar@1
    64
alpar@1
    65
double fp_less(MPL *mpl, double x, double y)
alpar@1
    66
{     if (x < y) return 0.0;
alpar@1
    67
      if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y)
alpar@1
    68
         error(mpl, "%.*g less %.*g; floating-point overflow",
alpar@1
    69
            DBL_DIG, x, DBL_DIG, y);
alpar@1
    70
      return x - y;
alpar@1
    71
}
alpar@1
    72
alpar@1
    73
/*----------------------------------------------------------------------
alpar@1
    74
-- fp_mul - floating-point multiplication.
alpar@1
    75
--
alpar@1
    76
-- This routine computes the product x * y. */
alpar@1
    77
alpar@1
    78
double fp_mul(MPL *mpl, double x, double y)
alpar@1
    79
{     if (fabs(y) > 1.0 && fabs(x) > (0.999 * DBL_MAX) / fabs(y))
alpar@1
    80
         error(mpl, "%.*g * %.*g; floating-point overflow",
alpar@1
    81
            DBL_DIG, x, DBL_DIG, y);
alpar@1
    82
      return x * y;
alpar@1
    83
}
alpar@1
    84
alpar@1
    85
/*----------------------------------------------------------------------
alpar@1
    86
-- fp_div - floating-point division.
alpar@1
    87
--
alpar@1
    88
-- This routine computes the quotient x / y. */
alpar@1
    89
alpar@1
    90
double fp_div(MPL *mpl, double x, double y)
alpar@1
    91
{     if (fabs(y) < DBL_MIN)
alpar@1
    92
         error(mpl, "%.*g / %.*g; floating-point zero divide",
alpar@1
    93
            DBL_DIG, x, DBL_DIG, y);
alpar@1
    94
      if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
alpar@1
    95
         error(mpl, "%.*g / %.*g; floating-point overflow",
alpar@1
    96
            DBL_DIG, x, DBL_DIG, y);
alpar@1
    97
      return x / y;
alpar@1
    98
}
alpar@1
    99
alpar@1
   100
/*----------------------------------------------------------------------
alpar@1
   101
-- fp_idiv - floating-point quotient of exact division.
alpar@1
   102
--
alpar@1
   103
-- This routine computes the quotient of exact division x div y. */
alpar@1
   104
alpar@1
   105
double fp_idiv(MPL *mpl, double x, double y)
alpar@1
   106
{     if (fabs(y) < DBL_MIN)
alpar@1
   107
         error(mpl, "%.*g div %.*g; floating-point zero divide",
alpar@1
   108
            DBL_DIG, x, DBL_DIG, y);
alpar@1
   109
      if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
alpar@1
   110
         error(mpl, "%.*g div %.*g; floating-point overflow",
alpar@1
   111
            DBL_DIG, x, DBL_DIG, y);
alpar@1
   112
      x /= y;
alpar@1
   113
      return x > 0.0 ? floor(x) : x < 0.0 ? ceil(x) : 0.0;
alpar@1
   114
}
alpar@1
   115
alpar@1
   116
/*----------------------------------------------------------------------
alpar@1
   117
-- fp_mod - floating-point remainder of exact division.
alpar@1
   118
--
alpar@1
   119
-- This routine computes the remainder of exact division x mod y.
alpar@1
   120
--
alpar@1
   121
-- NOTE: By definition x mod y = x - y * floor(x / y). */
alpar@1
   122
alpar@1
   123
double fp_mod(MPL *mpl, double x, double y)
alpar@1
   124
{     double r;
alpar@1
   125
      xassert(mpl == mpl);
alpar@1
   126
      if (x == 0.0)
alpar@1
   127
         r = 0.0;
alpar@1
   128
      else if (y == 0.0)
alpar@1
   129
         r = x;
alpar@1
   130
      else
alpar@1
   131
      {  r = fmod(fabs(x), fabs(y));
alpar@1
   132
         if (r != 0.0)
alpar@1
   133
         {  if (x < 0.0) r = - r;
alpar@1
   134
            if (x > 0.0 && y < 0.0 || x < 0.0 && y > 0.0) r += y;
alpar@1
   135
         }
alpar@1
   136
      }
alpar@1
   137
      return r;
alpar@1
   138
}
alpar@1
   139
alpar@1
   140
/*----------------------------------------------------------------------
alpar@1
   141
-- fp_power - floating-point exponentiation (raise to power).
alpar@1
   142
--
alpar@1
   143
-- This routine computes the exponentiation x ** y. */
alpar@1
   144
alpar@1
   145
double fp_power(MPL *mpl, double x, double y)
alpar@1
   146
{     double r;
alpar@1
   147
      if (x == 0.0 && y <= 0.0 || x < 0.0 && y != floor(y))
alpar@1
   148
         error(mpl, "%.*g ** %.*g; result undefined",
alpar@1
   149
            DBL_DIG, x, DBL_DIG, y);
alpar@1
   150
      if (x == 0.0) goto eval;
alpar@1
   151
      if (fabs(x) > 1.0 && y > +1.0 &&
alpar@1
   152
            +log(fabs(x)) > (0.999 * log(DBL_MAX)) / y ||
alpar@1
   153
          fabs(x) < 1.0 && y < -1.0 &&
alpar@1
   154
            +log(fabs(x)) < (0.999 * log(DBL_MAX)) / y)
alpar@1
   155
         error(mpl, "%.*g ** %.*g; floating-point overflow",
alpar@1
   156
            DBL_DIG, x, DBL_DIG, y);
alpar@1
   157
      if (fabs(x) > 1.0 && y < -1.0 &&
alpar@1
   158
            -log(fabs(x)) < (0.999 * log(DBL_MAX)) / y ||
alpar@1
   159
          fabs(x) < 1.0 && y > +1.0 &&
alpar@1
   160
            -log(fabs(x)) > (0.999 * log(DBL_MAX)) / y)
alpar@1
   161
         r = 0.0;
alpar@1
   162
      else
alpar@1
   163
eval:    r = pow(x, y);
alpar@1
   164
      return r;
alpar@1
   165
}
alpar@1
   166
alpar@1
   167
/*----------------------------------------------------------------------
alpar@1
   168
-- fp_exp - floating-point base-e exponential.
alpar@1
   169
--
alpar@1
   170
-- This routine computes the base-e exponential e ** x. */
alpar@1
   171
alpar@1
   172
double fp_exp(MPL *mpl, double x)
alpar@1
   173
{     if (x > 0.999 * log(DBL_MAX))
alpar@1
   174
         error(mpl, "exp(%.*g); floating-point overflow", DBL_DIG, x);
alpar@1
   175
      return exp(x);
alpar@1
   176
}
alpar@1
   177
alpar@1
   178
/*----------------------------------------------------------------------
alpar@1
   179
-- fp_log - floating-point natural logarithm.
alpar@1
   180
--
alpar@1
   181
-- This routine computes the natural logarithm log x. */
alpar@1
   182
alpar@1
   183
double fp_log(MPL *mpl, double x)
alpar@1
   184
{     if (x <= 0.0)
alpar@1
   185
         error(mpl, "log(%.*g); non-positive argument", DBL_DIG, x);
alpar@1
   186
      return log(x);
alpar@1
   187
}
alpar@1
   188
alpar@1
   189
/*----------------------------------------------------------------------
alpar@1
   190
-- fp_log10 - floating-point common (decimal) logarithm.
alpar@1
   191
--
alpar@1
   192
-- This routine computes the common (decimal) logarithm lg x. */
alpar@1
   193
alpar@1
   194
double fp_log10(MPL *mpl, double x)
alpar@1
   195
{     if (x <= 0.0)
alpar@1
   196
         error(mpl, "log10(%.*g); non-positive argument", DBL_DIG, x);
alpar@1
   197
      return log10(x);
alpar@1
   198
}
alpar@1
   199
alpar@1
   200
/*----------------------------------------------------------------------
alpar@1
   201
-- fp_sqrt - floating-point square root.
alpar@1
   202
--
alpar@1
   203
-- This routine computes the square root x ** 0.5. */
alpar@1
   204
alpar@1
   205
double fp_sqrt(MPL *mpl, double x)
alpar@1
   206
{     if (x < 0.0)
alpar@1
   207
         error(mpl, "sqrt(%.*g); negative argument", DBL_DIG, x);
alpar@1
   208
      return sqrt(x);
alpar@1
   209
}
alpar@1
   210
alpar@1
   211
/*----------------------------------------------------------------------
alpar@1
   212
-- fp_sin - floating-point trigonometric sine.
alpar@1
   213
--
alpar@1
   214
-- This routine computes the trigonometric sine sin(x). */
alpar@1
   215
alpar@1
   216
double fp_sin(MPL *mpl, double x)
alpar@1
   217
{     if (!(-1e6 <= x && x <= +1e6))
alpar@1
   218
         error(mpl, "sin(%.*g); argument too large", DBL_DIG, x);
alpar@1
   219
      return sin(x);
alpar@1
   220
}
alpar@1
   221
alpar@1
   222
/*----------------------------------------------------------------------
alpar@1
   223
-- fp_cos - floating-point trigonometric cosine.
alpar@1
   224
--
alpar@1
   225
-- This routine computes the trigonometric cosine cos(x). */
alpar@1
   226
alpar@1
   227
double fp_cos(MPL *mpl, double x)
alpar@1
   228
{     if (!(-1e6 <= x && x <= +1e6))
alpar@1
   229
         error(mpl, "cos(%.*g); argument too large", DBL_DIG, x);
alpar@1
   230
      return cos(x);
alpar@1
   231
}
alpar@1
   232
alpar@1
   233
/*----------------------------------------------------------------------
alpar@1
   234
-- fp_atan - floating-point trigonometric arctangent.
alpar@1
   235
--
alpar@1
   236
-- This routine computes the trigonometric arctangent atan(x). */
alpar@1
   237
alpar@1
   238
double fp_atan(MPL *mpl, double x)
alpar@1
   239
{     xassert(mpl == mpl);
alpar@1
   240
      return atan(x);
alpar@1
   241
}
alpar@1
   242
alpar@1
   243
/*----------------------------------------------------------------------
alpar@1
   244
-- fp_atan2 - floating-point trigonometric arctangent.
alpar@1
   245
--
alpar@1
   246
-- This routine computes the trigonometric arctangent atan(y / x). */
alpar@1
   247
alpar@1
   248
double fp_atan2(MPL *mpl, double y, double x)
alpar@1
   249
{     xassert(mpl == mpl);
alpar@1
   250
      return atan2(y, x);
alpar@1
   251
}
alpar@1
   252
alpar@1
   253
/*----------------------------------------------------------------------
alpar@1
   254
-- fp_round - round floating-point value to n fractional digits.
alpar@1
   255
--
alpar@1
   256
-- This routine rounds given floating-point value x to n fractional
alpar@1
   257
-- digits with the formula:
alpar@1
   258
--
alpar@1
   259
--    round(x, n) = floor(x * 10^n + 0.5) / 10^n.
alpar@1
   260
--
alpar@1
   261
-- The parameter n is assumed to be integer. */
alpar@1
   262
alpar@1
   263
double fp_round(MPL *mpl, double x, double n)
alpar@1
   264
{     double ten_to_n;
alpar@1
   265
      if (n != floor(n))
alpar@1
   266
         error(mpl, "round(%.*g, %.*g); non-integer second argument",
alpar@1
   267
            DBL_DIG, x, DBL_DIG, n);
alpar@1
   268
      if (n <= DBL_DIG + 2)
alpar@1
   269
      {  ten_to_n = pow(10.0, n);
alpar@1
   270
         if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
alpar@1
   271
         {  x = floor(x * ten_to_n + 0.5);
alpar@1
   272
            if (x != 0.0) x /= ten_to_n;
alpar@1
   273
         }
alpar@1
   274
      }
alpar@1
   275
      return x;
alpar@1
   276
}
alpar@1
   277
alpar@1
   278
/*----------------------------------------------------------------------
alpar@1
   279
-- fp_trunc - truncate floating-point value to n fractional digits.
alpar@1
   280
--
alpar@1
   281
-- This routine truncates given floating-point value x to n fractional
alpar@1
   282
-- digits with the formula:
alpar@1
   283
--
alpar@1
   284
--                  ( floor(x * 10^n) / 10^n,  if x >= 0
alpar@1
   285
--    trunc(x, n) = <
alpar@1
   286
--                  ( ceil(x * 10^n) / 10^n,   if x < 0
alpar@1
   287
--
alpar@1
   288
-- The parameter n is assumed to be integer. */
alpar@1
   289
alpar@1
   290
double fp_trunc(MPL *mpl, double x, double n)
alpar@1
   291
{     double ten_to_n;
alpar@1
   292
      if (n != floor(n))
alpar@1
   293
         error(mpl, "trunc(%.*g, %.*g); non-integer second argument",
alpar@1
   294
            DBL_DIG, x, DBL_DIG, n);
alpar@1
   295
      if (n <= DBL_DIG + 2)
alpar@1
   296
      {  ten_to_n = pow(10.0, n);
alpar@1
   297
         if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
alpar@1
   298
         {  x = (x >= 0.0 ? floor(x * ten_to_n) : ceil(x * ten_to_n));
alpar@1
   299
            if (x != 0.0) x /= ten_to_n;
alpar@1
   300
         }
alpar@1
   301
      }
alpar@1
   302
      return x;
alpar@1
   303
}
alpar@1
   304
alpar@1
   305
/**********************************************************************/
alpar@1
   306
/* * *              PSEUDO-RANDOM NUMBER GENERATORS               * * */
alpar@1
   307
/**********************************************************************/
alpar@1
   308
alpar@1
   309
/*----------------------------------------------------------------------
alpar@1
   310
-- fp_irand224 - pseudo-random integer in the range [0, 2^24).
alpar@1
   311
--
alpar@1
   312
-- This routine returns a next pseudo-random integer (converted to
alpar@1
   313
-- floating-point) which is uniformly distributed between 0 and 2^24-1,
alpar@1
   314
-- inclusive. */
alpar@1
   315
alpar@1
   316
#define two_to_the_24 0x1000000
alpar@1
   317
alpar@1
   318
double fp_irand224(MPL *mpl)
alpar@1
   319
{     return
alpar@1
   320
         (double)rng_unif_rand(mpl->rand, two_to_the_24);
alpar@1
   321
}
alpar@1
   322
alpar@1
   323
/*----------------------------------------------------------------------
alpar@1
   324
-- fp_uniform01 - pseudo-random number in the range [0, 1).
alpar@1
   325
--
alpar@1
   326
-- This routine returns a next pseudo-random number which is uniformly
alpar@1
   327
-- distributed in the range [0, 1). */
alpar@1
   328
alpar@1
   329
#define two_to_the_31 ((unsigned int)0x80000000)
alpar@1
   330
alpar@1
   331
double fp_uniform01(MPL *mpl)
alpar@1
   332
{     return
alpar@1
   333
         (double)rng_next_rand(mpl->rand) / (double)two_to_the_31;
alpar@1
   334
}
alpar@1
   335
alpar@1
   336
/*----------------------------------------------------------------------
alpar@1
   337
-- fp_uniform - pseudo-random number in the range [a, b).
alpar@1
   338
--
alpar@1
   339
-- This routine returns a next pseudo-random number which is uniformly
alpar@1
   340
-- distributed in the range [a, b). */
alpar@1
   341
alpar@1
   342
double fp_uniform(MPL *mpl, double a, double b)
alpar@1
   343
{     double x;
alpar@1
   344
      if (a >= b)
alpar@1
   345
         error(mpl, "Uniform(%.*g, %.*g); invalid range",
alpar@1
   346
            DBL_DIG, a, DBL_DIG, b);
alpar@1
   347
      x = fp_uniform01(mpl);
alpar@1
   348
#if 0
alpar@1
   349
      x = a * (1.0 - x) + b * x;
alpar@1
   350
#else
alpar@1
   351
      x = fp_add(mpl, a * (1.0 - x), b * x);
alpar@1
   352
#endif
alpar@1
   353
      return x;
alpar@1
   354
}
alpar@1
   355
alpar@1
   356
/*----------------------------------------------------------------------
alpar@1
   357
-- fp_normal01 - Gaussian random variate with mu = 0 and sigma = 1.
alpar@1
   358
--
alpar@1
   359
-- This routine returns a Gaussian random variate with zero mean and
alpar@1
   360
-- unit standard deviation. The polar (Box-Mueller) method is used.
alpar@1
   361
--
alpar@1
   362
-- This code is a modified version of the routine gsl_ran_gaussian from
alpar@1
   363
-- the GNU Scientific Library Version 1.0. */
alpar@1
   364
alpar@1
   365
double fp_normal01(MPL *mpl)
alpar@1
   366
{     double x, y, r2;
alpar@1
   367
      do
alpar@1
   368
      {  /* choose x, y in uniform square (-1,-1) to (+1,+1) */
alpar@1
   369
         x = -1.0 + 2.0 * fp_uniform01(mpl);
alpar@1
   370
         y = -1.0 + 2.0 * fp_uniform01(mpl);
alpar@1
   371
         /* see if it is in the unit circle */
alpar@1
   372
         r2 = x * x + y * y;
alpar@1
   373
      } while (r2 > 1.0 || r2 == 0.0);
alpar@1
   374
      /* Box-Muller transform */
alpar@1
   375
      return y * sqrt(-2.0 * log (r2) / r2);
alpar@1
   376
}
alpar@1
   377
alpar@1
   378
/*----------------------------------------------------------------------
alpar@1
   379
-- fp_normal - Gaussian random variate with specified mu and sigma.
alpar@1
   380
--
alpar@1
   381
-- This routine returns a Gaussian random variate with mean mu and
alpar@1
   382
-- standard deviation sigma. */
alpar@1
   383
alpar@1
   384
double fp_normal(MPL *mpl, double mu, double sigma)
alpar@1
   385
{     double x;
alpar@1
   386
#if 0
alpar@1
   387
      x = mu + sigma * fp_normal01(mpl);
alpar@1
   388
#else
alpar@1
   389
      x = fp_add(mpl, mu, fp_mul(mpl, sigma, fp_normal01(mpl)));
alpar@1
   390
#endif
alpar@1
   391
      return x;
alpar@1
   392
}
alpar@1
   393
alpar@1
   394
/**********************************************************************/
alpar@1
   395
/* * *                SEGMENTED CHARACTER STRINGS                 * * */
alpar@1
   396
/**********************************************************************/
alpar@1
   397
alpar@1
   398
/*----------------------------------------------------------------------
alpar@1
   399
-- create_string - create character string.
alpar@1
   400
--
alpar@1
   401
-- This routine creates a segmented character string, which is exactly
alpar@1
   402
-- equivalent to specified character string. */
alpar@1
   403
alpar@1
   404
STRING *create_string
alpar@1
   405
(     MPL *mpl,
alpar@1
   406
      char buf[MAX_LENGTH+1]  /* not changed */
alpar@1
   407
)
alpar@1
   408
#if 0
alpar@1
   409
{     STRING *head, *tail;
alpar@1
   410
      int i, j;
alpar@1
   411
      xassert(buf != NULL);
alpar@1
   412
      xassert(strlen(buf) <= MAX_LENGTH);
alpar@1
   413
      head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
alpar@1
   414
      for (i = j = 0; ; i++)
alpar@1
   415
      {  if ((tail->seg[j++] = buf[i]) == '\0') break;
alpar@1
   416
         if (j == STRSEG_SIZE)
alpar@1
   417
tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING))), j = 0;
alpar@1
   418
      }
alpar@1
   419
      tail->next = NULL;
alpar@1
   420
      return head;
alpar@1
   421
}
alpar@1
   422
#else
alpar@1
   423
{     STRING *str;
alpar@1
   424
      xassert(strlen(buf) <= MAX_LENGTH);
alpar@1
   425
      str = dmp_get_atom(mpl->strings, strlen(buf)+1);
alpar@1
   426
      strcpy(str, buf);
alpar@1
   427
      return str;
alpar@1
   428
}
alpar@1
   429
#endif
alpar@1
   430
alpar@1
   431
/*----------------------------------------------------------------------
alpar@1
   432
-- copy_string - make copy of character string.
alpar@1
   433
--
alpar@1
   434
-- This routine returns an exact copy of segmented character string. */
alpar@1
   435
alpar@1
   436
STRING *copy_string
alpar@1
   437
(     MPL *mpl,
alpar@1
   438
      STRING *str             /* not changed */
alpar@1
   439
)
alpar@1
   440
#if 0
alpar@1
   441
{     STRING *head, *tail;
alpar@1
   442
      xassert(str != NULL);
alpar@1
   443
      head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
alpar@1
   444
      for (; str != NULL; str = str->next)
alpar@1
   445
      {  memcpy(tail->seg, str->seg, STRSEG_SIZE);
alpar@1
   446
         if (str->next != NULL)
alpar@1
   447
tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING)));
alpar@1
   448
      }
alpar@1
   449
      tail->next = NULL;
alpar@1
   450
      return head;
alpar@1
   451
}
alpar@1
   452
#else
alpar@1
   453
{     xassert(mpl == mpl);
alpar@1
   454
      return create_string(mpl, str);
alpar@1
   455
}
alpar@1
   456
#endif
alpar@1
   457
alpar@1
   458
/*----------------------------------------------------------------------
alpar@1
   459
-- compare_strings - compare one character string with another.
alpar@1
   460
--
alpar@1
   461
-- This routine compares one segmented character strings with another
alpar@1
   462
-- and returns the result of comparison as follows:
alpar@1
   463
--
alpar@1
   464
-- = 0 - both strings are identical;
alpar@1
   465
-- < 0 - the first string precedes the second one;
alpar@1
   466
-- > 0 - the first string follows the second one. */
alpar@1
   467
alpar@1
   468
int compare_strings
alpar@1
   469
(     MPL *mpl,
alpar@1
   470
      STRING *str1,           /* not changed */
alpar@1
   471
      STRING *str2            /* not changed */
alpar@1
   472
)
alpar@1
   473
#if 0
alpar@1
   474
{     int j, c1, c2;
alpar@1
   475
      xassert(mpl == mpl);
alpar@1
   476
      for (;; str1 = str1->next, str2 = str2->next)
alpar@1
   477
      {  xassert(str1 != NULL);
alpar@1
   478
         xassert(str2 != NULL);
alpar@1
   479
         for (j = 0; j < STRSEG_SIZE; j++)
alpar@1
   480
         {  c1 = (unsigned char)str1->seg[j];
alpar@1
   481
            c2 = (unsigned char)str2->seg[j];
alpar@1
   482
            if (c1 < c2) return -1;
alpar@1
   483
            if (c1 > c2) return +1;
alpar@1
   484
            if (c1 == '\0') goto done;
alpar@1
   485
         }
alpar@1
   486
      }
alpar@1
   487
done: return 0;
alpar@1
   488
}
alpar@1
   489
#else
alpar@1
   490
{     xassert(mpl == mpl);
alpar@1
   491
      return strcmp(str1, str2);
alpar@1
   492
}
alpar@1
   493
#endif
alpar@1
   494
alpar@1
   495
/*----------------------------------------------------------------------
alpar@1
   496
-- fetch_string - extract content of character string.
alpar@1
   497
--
alpar@1
   498
-- This routine returns a character string, which is exactly equivalent
alpar@1
   499
-- to specified segmented character string. */
alpar@1
   500
alpar@1
   501
char *fetch_string
alpar@1
   502
(     MPL *mpl,
alpar@1
   503
      STRING *str,            /* not changed */
alpar@1
   504
      char buf[MAX_LENGTH+1]  /* modified */
alpar@1
   505
)
alpar@1
   506
#if 0
alpar@1
   507
{     int i, j;
alpar@1
   508
      xassert(mpl == mpl);
alpar@1
   509
      xassert(buf != NULL);
alpar@1
   510
      for (i = 0; ; str = str->next)
alpar@1
   511
      {  xassert(str != NULL);
alpar@1
   512
         for (j = 0; j < STRSEG_SIZE; j++)
alpar@1
   513
            if ((buf[i++] = str->seg[j]) == '\0') goto done;
alpar@1
   514
      }
alpar@1
   515
done: xassert(strlen(buf) <= MAX_LENGTH);
alpar@1
   516
      return buf;
alpar@1
   517
}
alpar@1
   518
#else
alpar@1
   519
{     xassert(mpl == mpl);
alpar@1
   520
      return strcpy(buf, str);
alpar@1
   521
}
alpar@1
   522
#endif
alpar@1
   523
alpar@1
   524
/*----------------------------------------------------------------------
alpar@1
   525
-- delete_string - delete character string.
alpar@1
   526
--
alpar@1
   527
-- This routine deletes specified segmented character string. */
alpar@1
   528
alpar@1
   529
void delete_string
alpar@1
   530
(     MPL *mpl,
alpar@1
   531
      STRING *str             /* destroyed */
alpar@1
   532
)
alpar@1
   533
#if 0
alpar@1
   534
{     STRING *temp;
alpar@1
   535
      xassert(str != NULL);
alpar@1
   536
      while (str != NULL)
alpar@1
   537
      {  temp = str;
alpar@1
   538
         str = str->next;
alpar@1
   539
         dmp_free_atom(mpl->strings, temp, sizeof(STRING));
alpar@1
   540
      }
alpar@1
   541
      return;
alpar@1
   542
}
alpar@1
   543
#else
alpar@1
   544
{     dmp_free_atom(mpl->strings, str, strlen(str)+1);
alpar@1
   545
      return;
alpar@1
   546
}
alpar@1
   547
#endif
alpar@1
   548
alpar@1
   549
/**********************************************************************/
alpar@1
   550
/* * *                          SYMBOLS                           * * */
alpar@1
   551
/**********************************************************************/
alpar@1
   552
alpar@1
   553
/*----------------------------------------------------------------------
alpar@1
   554
-- create_symbol_num - create symbol of numeric type.
alpar@1
   555
--
alpar@1
   556
-- This routine creates a symbol, which has a numeric value specified
alpar@1
   557
-- as floating-point number. */
alpar@1
   558
alpar@1
   559
SYMBOL *create_symbol_num(MPL *mpl, double num)
alpar@1
   560
{     SYMBOL *sym;
alpar@1
   561
      sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
alpar@1
   562
      sym->num = num;
alpar@1
   563
      sym->str = NULL;
alpar@1
   564
      return sym;
alpar@1
   565
}
alpar@1
   566
alpar@1
   567
/*----------------------------------------------------------------------
alpar@1
   568
-- create_symbol_str - create symbol of abstract type.
alpar@1
   569
--
alpar@1
   570
-- This routine creates a symbol, which has an abstract value specified
alpar@1
   571
-- as segmented character string. */
alpar@1
   572
alpar@1
   573
SYMBOL *create_symbol_str
alpar@1
   574
(     MPL *mpl,
alpar@1
   575
      STRING *str             /* destroyed */
alpar@1
   576
)
alpar@1
   577
{     SYMBOL *sym;
alpar@1
   578
      xassert(str != NULL);
alpar@1
   579
      sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
alpar@1
   580
      sym->num = 0.0;
alpar@1
   581
      sym->str = str;
alpar@1
   582
      return sym;
alpar@1
   583
}
alpar@1
   584
alpar@1
   585
/*----------------------------------------------------------------------
alpar@1
   586
-- copy_symbol - make copy of symbol.
alpar@1
   587
--
alpar@1
   588
-- This routine returns an exact copy of symbol. */
alpar@1
   589
alpar@1
   590
SYMBOL *copy_symbol
alpar@1
   591
(     MPL *mpl,
alpar@1
   592
      SYMBOL *sym             /* not changed */
alpar@1
   593
)
alpar@1
   594
{     SYMBOL *copy;
alpar@1
   595
      xassert(sym != NULL);
alpar@1
   596
      copy = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
alpar@1
   597
      if (sym->str == NULL)
alpar@1
   598
      {  copy->num = sym->num;
alpar@1
   599
         copy->str = NULL;
alpar@1
   600
      }
alpar@1
   601
      else
alpar@1
   602
      {  copy->num = 0.0;
alpar@1
   603
         copy->str = copy_string(mpl, sym->str);
alpar@1
   604
      }
alpar@1
   605
      return copy;
alpar@1
   606
}
alpar@1
   607
alpar@1
   608
/*----------------------------------------------------------------------
alpar@1
   609
-- compare_symbols - compare one symbol with another.
alpar@1
   610
--
alpar@1
   611
-- This routine compares one symbol with another and returns the result
alpar@1
   612
-- of comparison as follows:
alpar@1
   613
--
alpar@1
   614
-- = 0 - both symbols are identical;
alpar@1
   615
-- < 0 - the first symbol precedes the second one;
alpar@1
   616
-- > 0 - the first symbol follows the second one.
alpar@1
   617
--
alpar@1
   618
-- Note that the linear order, in which symbols follow each other, is
alpar@1
   619
-- implementation-dependent. It may be not an alphabetical order. */
alpar@1
   620
alpar@1
   621
int compare_symbols
alpar@1
   622
(     MPL *mpl,
alpar@1
   623
      SYMBOL *sym1,           /* not changed */
alpar@1
   624
      SYMBOL *sym2            /* not changed */
alpar@1
   625
)
alpar@1
   626
{     xassert(sym1 != NULL);
alpar@1
   627
      xassert(sym2 != NULL);
alpar@1
   628
      /* let all numeric quantities precede all symbolic quantities */
alpar@1
   629
      if (sym1->str == NULL && sym2->str == NULL)
alpar@1
   630
      {  if (sym1->num < sym2->num) return -1;
alpar@1
   631
         if (sym1->num > sym2->num) return +1;
alpar@1
   632
         return 0;
alpar@1
   633
      }
alpar@1
   634
      if (sym1->str == NULL) return -1;
alpar@1
   635
      if (sym2->str == NULL) return +1;
alpar@1
   636
      return compare_strings(mpl, sym1->str, sym2->str);
alpar@1
   637
}
alpar@1
   638
alpar@1
   639
/*----------------------------------------------------------------------
alpar@1
   640
-- delete_symbol - delete symbol.
alpar@1
   641
--
alpar@1
   642
-- This routine deletes specified symbol. */
alpar@1
   643
alpar@1
   644
void delete_symbol
alpar@1
   645
(     MPL *mpl,
alpar@1
   646
      SYMBOL *sym             /* destroyed */
alpar@1
   647
)
alpar@1
   648
{     xassert(sym != NULL);
alpar@1
   649
      if (sym->str != NULL) delete_string(mpl, sym->str);
alpar@1
   650
      dmp_free_atom(mpl->symbols, sym, sizeof(SYMBOL));
alpar@1
   651
      return;
alpar@1
   652
}
alpar@1
   653
alpar@1
   654
/*----------------------------------------------------------------------
alpar@1
   655
-- format_symbol - format symbol for displaying or printing.
alpar@1
   656
--
alpar@1
   657
-- This routine converts specified symbol to a charater string, which
alpar@1
   658
-- is suitable for displaying or printing.
alpar@1
   659
--
alpar@1
   660
-- The resultant string is never longer than 255 characters. If it gets
alpar@1
   661
-- longer, it is truncated from the right and appended by dots. */
alpar@1
   662
alpar@1
   663
char *format_symbol
alpar@1
   664
(     MPL *mpl,
alpar@1
   665
      SYMBOL *sym             /* not changed */
alpar@1
   666
)
alpar@1
   667
{     char *buf = mpl->sym_buf;
alpar@1
   668
      xassert(sym != NULL);
alpar@1
   669
      if (sym->str == NULL)
alpar@1
   670
         sprintf(buf, "%.*g", DBL_DIG, sym->num);
alpar@1
   671
      else
alpar@1
   672
      {  char str[MAX_LENGTH+1];
alpar@1
   673
         int quoted, j, len;
alpar@1
   674
         fetch_string(mpl, sym->str, str);
alpar@1
   675
         if (!(isalpha((unsigned char)str[0]) || str[0] == '_'))
alpar@1
   676
            quoted = 1;
alpar@1
   677
         else
alpar@1
   678
         {  quoted = 0;
alpar@1
   679
            for (j = 1; str[j] != '\0'; j++)
alpar@1
   680
            {  if (!(isalnum((unsigned char)str[j]) ||
alpar@1
   681
                     strchr("+-._", (unsigned char)str[j]) != NULL))
alpar@1
   682
               {  quoted = 1;
alpar@1
   683
                  break;
alpar@1
   684
               }
alpar@1
   685
            }
alpar@1
   686
         }
alpar@1
   687
#        define safe_append(c) \
alpar@1
   688
            (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
alpar@1
   689
         buf[0] = '\0', len = 0;
alpar@1
   690
         if (quoted) safe_append('\'');
alpar@1
   691
         for (j = 0; str[j] != '\0'; j++)
alpar@1
   692
         {  if (quoted && str[j] == '\'') safe_append('\'');
alpar@1
   693
            safe_append(str[j]);
alpar@1
   694
         }
alpar@1
   695
         if (quoted) safe_append('\'');
alpar@1
   696
#        undef safe_append
alpar@1
   697
         buf[len] = '\0';
alpar@1
   698
         if (len == 255) strcpy(buf+252, "...");
alpar@1
   699
      }
alpar@1
   700
      xassert(strlen(buf) <= 255);
alpar@1
   701
      return buf;
alpar@1
   702
}
alpar@1
   703
alpar@1
   704
/*----------------------------------------------------------------------
alpar@1
   705
-- concat_symbols - concatenate one symbol with another.
alpar@1
   706
--
alpar@1
   707
-- This routine concatenates values of two given symbols and assigns
alpar@1
   708
-- the resultant character string to a new symbol, which is returned on
alpar@1
   709
-- exit. Both original symbols are destroyed. */
alpar@1
   710
alpar@1
   711
SYMBOL *concat_symbols
alpar@1
   712
(     MPL *mpl,
alpar@1
   713
      SYMBOL *sym1,           /* destroyed */
alpar@1
   714
      SYMBOL *sym2            /* destroyed */
alpar@1
   715
)
alpar@1
   716
{     char str1[MAX_LENGTH+1], str2[MAX_LENGTH+1];
alpar@1
   717
      xassert(MAX_LENGTH >= DBL_DIG + DBL_DIG);
alpar@1
   718
      if (sym1->str == NULL)
alpar@1
   719
         sprintf(str1, "%.*g", DBL_DIG, sym1->num);
alpar@1
   720
      else
alpar@1
   721
         fetch_string(mpl, sym1->str, str1);
alpar@1
   722
      if (sym2->str == NULL)
alpar@1
   723
         sprintf(str2, "%.*g", DBL_DIG, sym2->num);
alpar@1
   724
      else
alpar@1
   725
         fetch_string(mpl, sym2->str, str2);
alpar@1
   726
      if (strlen(str1) + strlen(str2) > MAX_LENGTH)
alpar@1
   727
      {  char buf[255+1];
alpar@1
   728
         strcpy(buf, format_symbol(mpl, sym1));
alpar@1
   729
         xassert(strlen(buf) < sizeof(buf));
alpar@1
   730
         error(mpl, "%s & %s; resultant symbol exceeds %d characters",
alpar@1
   731
            buf, format_symbol(mpl, sym2), MAX_LENGTH);
alpar@1
   732
      }
alpar@1
   733
      delete_symbol(mpl, sym1);
alpar@1
   734
      delete_symbol(mpl, sym2);
alpar@1
   735
      return create_symbol_str(mpl, create_string(mpl, strcat(str1,
alpar@1
   736
         str2)));
alpar@1
   737
}
alpar@1
   738
alpar@1
   739
/**********************************************************************/
alpar@1
   740
/* * *                          N-TUPLES                          * * */
alpar@1
   741
/**********************************************************************/
alpar@1
   742
alpar@1
   743
/*----------------------------------------------------------------------
alpar@1
   744
-- create_tuple - create n-tuple.
alpar@1
   745
--
alpar@1
   746
-- This routine creates a n-tuple, which initially has no components,
alpar@1
   747
-- i.e. which is 0-tuple. */
alpar@1
   748
alpar@1
   749
TUPLE *create_tuple(MPL *mpl)
alpar@1
   750
{     TUPLE *tuple;
alpar@1
   751
      xassert(mpl == mpl);
alpar@1
   752
      tuple = NULL;
alpar@1
   753
      return tuple;
alpar@1
   754
}
alpar@1
   755
alpar@1
   756
/*----------------------------------------------------------------------
alpar@1
   757
-- expand_tuple - append symbol to n-tuple.
alpar@1
   758
--
alpar@1
   759
-- This routine expands n-tuple appending to it a given symbol, which
alpar@1
   760
-- becomes its new last component. */
alpar@1
   761
alpar@1
   762
TUPLE *expand_tuple
alpar@1
   763
(     MPL *mpl,
alpar@1
   764
      TUPLE *tuple,           /* destroyed */
alpar@1
   765
      SYMBOL *sym             /* destroyed */
alpar@1
   766
)
alpar@1
   767
{     TUPLE *tail, *temp;
alpar@1
   768
      xassert(sym != NULL);
alpar@1
   769
      /* create a new component */
alpar@1
   770
      tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
alpar@1
   771
      tail->sym = sym;
alpar@1
   772
      tail->next = NULL;
alpar@1
   773
      /* and append it to the component list */
alpar@1
   774
      if (tuple == NULL)
alpar@1
   775
         tuple = tail;
alpar@1
   776
      else
alpar@1
   777
      {  for (temp = tuple; temp->next != NULL; temp = temp->next);
alpar@1
   778
         temp->next = tail;
alpar@1
   779
      }
alpar@1
   780
      return tuple;
alpar@1
   781
}
alpar@1
   782
alpar@1
   783
/*----------------------------------------------------------------------
alpar@1
   784
-- tuple_dimen - determine dimension of n-tuple.
alpar@1
   785
--
alpar@1
   786
-- This routine returns dimension of n-tuple, i.e. number of components
alpar@1
   787
-- in the n-tuple. */
alpar@1
   788
alpar@1
   789
int tuple_dimen
alpar@1
   790
(     MPL *mpl,
alpar@1
   791
      TUPLE *tuple            /* not changed */
alpar@1
   792
)
alpar@1
   793
{     TUPLE *temp;
alpar@1
   794
      int dim = 0;
alpar@1
   795
      xassert(mpl == mpl);
alpar@1
   796
      for (temp = tuple; temp != NULL; temp = temp->next) dim++;
alpar@1
   797
      return dim;
alpar@1
   798
}
alpar@1
   799
alpar@1
   800
/*----------------------------------------------------------------------
alpar@1
   801
-- copy_tuple - make copy of n-tuple.
alpar@1
   802
--
alpar@1
   803
-- This routine returns an exact copy of n-tuple. */
alpar@1
   804
alpar@1
   805
TUPLE *copy_tuple
alpar@1
   806
(     MPL *mpl,
alpar@1
   807
      TUPLE *tuple            /* not changed */
alpar@1
   808
)
alpar@1
   809
{     TUPLE *head, *tail;
alpar@1
   810
      if (tuple == NULL)
alpar@1
   811
         head = NULL;
alpar@1
   812
      else
alpar@1
   813
      {  head = tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
alpar@1
   814
         for (; tuple != NULL; tuple = tuple->next)
alpar@1
   815
         {  xassert(tuple->sym != NULL);
alpar@1
   816
            tail->sym = copy_symbol(mpl, tuple->sym);
alpar@1
   817
            if (tuple->next != NULL)
alpar@1
   818
tail = (tail->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
alpar@1
   819
         }
alpar@1
   820
         tail->next = NULL;
alpar@1
   821
      }
alpar@1
   822
      return head;
alpar@1
   823
}
alpar@1
   824
alpar@1
   825
/*----------------------------------------------------------------------
alpar@1
   826
-- compare_tuples - compare one n-tuple with another.
alpar@1
   827
--
alpar@1
   828
-- This routine compares two given n-tuples, which must have the same
alpar@1
   829
-- dimension (not checked for the sake of efficiency), and returns one
alpar@1
   830
-- of the following codes:
alpar@1
   831
--
alpar@1
   832
-- = 0 - both n-tuples are identical;
alpar@1
   833
-- < 0 - the first n-tuple precedes the second one;
alpar@1
   834
-- > 0 - the first n-tuple follows the second one.
alpar@1
   835
--
alpar@1
   836
-- Note that the linear order, in which n-tuples follow each other, is
alpar@1
   837
-- implementation-dependent. It may be not an alphabetical order. */
alpar@1
   838
alpar@1
   839
int compare_tuples
alpar@1
   840
(     MPL *mpl,
alpar@1
   841
      TUPLE *tuple1,          /* not changed */
alpar@1
   842
      TUPLE *tuple2           /* not changed */
alpar@1
   843
)
alpar@1
   844
{     TUPLE *item1, *item2;
alpar@1
   845
      int ret;
alpar@1
   846
      xassert(mpl == mpl);
alpar@1
   847
      for (item1 = tuple1, item2 = tuple2; item1 != NULL;
alpar@1
   848
           item1 = item1->next, item2 = item2->next)
alpar@1
   849
      {  xassert(item2 != NULL);
alpar@1
   850
         xassert(item1->sym != NULL);
alpar@1
   851
         xassert(item2->sym != NULL);
alpar@1
   852
         ret = compare_symbols(mpl, item1->sym, item2->sym);
alpar@1
   853
         if (ret != 0) return ret;
alpar@1
   854
      }
alpar@1
   855
      xassert(item2 == NULL);
alpar@1
   856
      return 0;
alpar@1
   857
}
alpar@1
   858
alpar@1
   859
/*----------------------------------------------------------------------
alpar@1
   860
-- build_subtuple - build subtuple of given n-tuple.
alpar@1
   861
--
alpar@1
   862
-- This routine builds subtuple, which consists of first dim components
alpar@1
   863
-- of given n-tuple. */
alpar@1
   864
alpar@1
   865
TUPLE *build_subtuple
alpar@1
   866
(     MPL *mpl,
alpar@1
   867
      TUPLE *tuple,           /* not changed */
alpar@1
   868
      int dim
alpar@1
   869
)
alpar@1
   870
{     TUPLE *head, *temp;
alpar@1
   871
      int j;
alpar@1
   872
      head = create_tuple(mpl);
alpar@1
   873
      for (j = 1, temp = tuple; j <= dim; j++, temp = temp->next)
alpar@1
   874
      {  xassert(temp != NULL);
alpar@1
   875
         head = expand_tuple(mpl, head, copy_symbol(mpl, temp->sym));
alpar@1
   876
      }
alpar@1
   877
      return head;
alpar@1
   878
}
alpar@1
   879
alpar@1
   880
/*----------------------------------------------------------------------
alpar@1
   881
-- delete_tuple - delete n-tuple.
alpar@1
   882
--
alpar@1
   883
-- This routine deletes specified n-tuple. */
alpar@1
   884
alpar@1
   885
void delete_tuple
alpar@1
   886
(     MPL *mpl,
alpar@1
   887
      TUPLE *tuple            /* destroyed */
alpar@1
   888
)
alpar@1
   889
{     TUPLE *temp;
alpar@1
   890
      while (tuple != NULL)
alpar@1
   891
      {  temp = tuple;
alpar@1
   892
         tuple = temp->next;
alpar@1
   893
         xassert(temp->sym != NULL);
alpar@1
   894
         delete_symbol(mpl, temp->sym);
alpar@1
   895
         dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
alpar@1
   896
      }
alpar@1
   897
      return;
alpar@1
   898
}
alpar@1
   899
alpar@1
   900
/*----------------------------------------------------------------------
alpar@1
   901
-- format_tuple - format n-tuple for displaying or printing.
alpar@1
   902
--
alpar@1
   903
-- This routine converts specified n-tuple to a character string, which
alpar@1
   904
-- is suitable for displaying or printing.
alpar@1
   905
--
alpar@1
   906
-- The resultant string is never longer than 255 characters. If it gets
alpar@1
   907
-- longer, it is truncated from the right and appended by dots. */
alpar@1
   908
alpar@1
   909
char *format_tuple
alpar@1
   910
(     MPL *mpl,
alpar@1
   911
      int c,
alpar@1
   912
      TUPLE *tuple            /* not changed */
alpar@1
   913
)
alpar@1
   914
{     TUPLE *temp;
alpar@1
   915
      int dim, j, len;
alpar@1
   916
      char *buf = mpl->tup_buf, str[255+1], *save;
alpar@1
   917
#     define safe_append(c) \
alpar@1
   918
         (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
alpar@1
   919
      buf[0] = '\0', len = 0;
alpar@1
   920
      dim = tuple_dimen(mpl, tuple);
alpar@1
   921
      if (c == '[' && dim > 0) safe_append('[');
alpar@1
   922
      if (c == '(' && dim > 1) safe_append('(');
alpar@1
   923
      for (temp = tuple; temp != NULL; temp = temp->next)
alpar@1
   924
      {  if (temp != tuple) safe_append(',');
alpar@1
   925
         xassert(temp->sym != NULL);
alpar@1
   926
         save = mpl->sym_buf;
alpar@1
   927
         mpl->sym_buf = str;
alpar@1
   928
         format_symbol(mpl, temp->sym);
alpar@1
   929
         mpl->sym_buf = save;
alpar@1
   930
         xassert(strlen(str) < sizeof(str));
alpar@1
   931
         for (j = 0; str[j] != '\0'; j++) safe_append(str[j]);
alpar@1
   932
      }
alpar@1
   933
      if (c == '[' && dim > 0) safe_append(']');
alpar@1
   934
      if (c == '(' && dim > 1) safe_append(')');
alpar@1
   935
#     undef safe_append
alpar@1
   936
      buf[len] = '\0';
alpar@1
   937
      if (len == 255) strcpy(buf+252, "...");
alpar@1
   938
      xassert(strlen(buf) <= 255);
alpar@1
   939
      return buf;
alpar@1
   940
}
alpar@1
   941
alpar@1
   942
/**********************************************************************/
alpar@1
   943
/* * *                       ELEMENTAL SETS                       * * */
alpar@1
   944
/**********************************************************************/
alpar@1
   945
alpar@1
   946
/*----------------------------------------------------------------------
alpar@1
   947
-- create_elemset - create elemental set.
alpar@1
   948
--
alpar@1
   949
-- This routine creates an elemental set, whose members are n-tuples of
alpar@1
   950
-- specified dimension. Being created the set is initially empty. */
alpar@1
   951
alpar@1
   952
ELEMSET *create_elemset(MPL *mpl, int dim)
alpar@1
   953
{     ELEMSET *set;
alpar@1
   954
      xassert(dim > 0);
alpar@1
   955
      set = create_array(mpl, A_NONE, dim);
alpar@1
   956
      return set;
alpar@1
   957
}
alpar@1
   958
alpar@1
   959
/*----------------------------------------------------------------------
alpar@1
   960
-- find_tuple - check if elemental set contains given n-tuple.
alpar@1
   961
--
alpar@1
   962
-- This routine finds given n-tuple in specified elemental set in order
alpar@1
   963
-- to check if the set contains that n-tuple. If the n-tuple is found,
alpar@1
   964
-- the routine returns pointer to corresponding array member. Otherwise
alpar@1
   965
-- null pointer is returned. */
alpar@1
   966
alpar@1
   967
MEMBER *find_tuple
alpar@1
   968
(     MPL *mpl,
alpar@1
   969
      ELEMSET *set,           /* not changed */
alpar@1
   970
      TUPLE *tuple            /* not changed */
alpar@1
   971
)
alpar@1
   972
{     xassert(set != NULL);
alpar@1
   973
      xassert(set->type == A_NONE);
alpar@1
   974
      xassert(set->dim == tuple_dimen(mpl, tuple));
alpar@1
   975
      return find_member(mpl, set, tuple);
alpar@1
   976
}
alpar@1
   977
alpar@1
   978
/*----------------------------------------------------------------------
alpar@1
   979
-- add_tuple - add new n-tuple to elemental set.
alpar@1
   980
--
alpar@1
   981
-- This routine adds given n-tuple to specified elemental set.
alpar@1
   982
--
alpar@1
   983
-- For the sake of efficiency this routine doesn't check whether the
alpar@1
   984
-- set already contains the same n-tuple or not. Therefore the calling
alpar@1
   985
-- program should use the routine find_tuple (if necessary) in order to
alpar@1
   986
-- make sure that the given n-tuple is not contained in the set, since
alpar@1
   987
-- duplicate n-tuples within the same set are not allowed. */
alpar@1
   988
alpar@1
   989
MEMBER *add_tuple
alpar@1
   990
(     MPL *mpl,
alpar@1
   991
      ELEMSET *set,           /* modified */
alpar@1
   992
      TUPLE *tuple            /* destroyed */
alpar@1
   993
)
alpar@1
   994
{     MEMBER *memb;
alpar@1
   995
      xassert(set != NULL);
alpar@1
   996
      xassert(set->type == A_NONE);
alpar@1
   997
      xassert(set->dim == tuple_dimen(mpl, tuple));
alpar@1
   998
      memb = add_member(mpl, set, tuple);
alpar@1
   999
      memb->value.none = NULL;
alpar@1
  1000
      return memb;
alpar@1
  1001
}
alpar@1
  1002
alpar@1
  1003
/*----------------------------------------------------------------------
alpar@1
  1004
-- check_then_add - check and add new n-tuple to elemental set.
alpar@1
  1005
--
alpar@1
  1006
-- This routine is equivalent to the routine add_tuple except that it
alpar@1
  1007
-- does check for duplicate n-tuples. */
alpar@1
  1008
alpar@1
  1009
MEMBER *check_then_add
alpar@1
  1010
(     MPL *mpl,
alpar@1
  1011
      ELEMSET *set,           /* modified */
alpar@1
  1012
      TUPLE *tuple            /* destroyed */
alpar@1
  1013
)
alpar@1
  1014
{     if (find_tuple(mpl, set, tuple) != NULL)
alpar@1
  1015
         error(mpl, "duplicate tuple %s detected", format_tuple(mpl,
alpar@1
  1016
            '(', tuple));
alpar@1
  1017
      return add_tuple(mpl, set, tuple);
alpar@1
  1018
}
alpar@1
  1019
alpar@1
  1020
/*----------------------------------------------------------------------
alpar@1
  1021
-- copy_elemset - make copy of elemental set.
alpar@1
  1022
--
alpar@1
  1023
-- This routine makes an exact copy of elemental set. */
alpar@1
  1024
alpar@1
  1025
ELEMSET *copy_elemset
alpar@1
  1026
(     MPL *mpl,
alpar@1
  1027
      ELEMSET *set            /* not changed */
alpar@1
  1028
)
alpar@1
  1029
{     ELEMSET *copy;
alpar@1
  1030
      MEMBER *memb;
alpar@1
  1031
      xassert(set != NULL);
alpar@1
  1032
      xassert(set->type == A_NONE);
alpar@1
  1033
      xassert(set->dim > 0);
alpar@1
  1034
      copy = create_elemset(mpl, set->dim);
alpar@1
  1035
      for (memb = set->head; memb != NULL; memb = memb->next)
alpar@1
  1036
         add_tuple(mpl, copy, copy_tuple(mpl, memb->tuple));
alpar@1
  1037
      return copy;
alpar@1
  1038
}
alpar@1
  1039
alpar@1
  1040
/*----------------------------------------------------------------------
alpar@1
  1041
-- delete_elemset - delete elemental set.
alpar@1
  1042
--
alpar@1
  1043
-- This routine deletes specified elemental set. */
alpar@1
  1044
alpar@1
  1045
void delete_elemset
alpar@1
  1046
(     MPL *mpl,
alpar@1
  1047
      ELEMSET *set            /* destroyed */
alpar@1
  1048
)
alpar@1
  1049
{     xassert(set != NULL);
alpar@1
  1050
      xassert(set->type == A_NONE);
alpar@1
  1051
      delete_array(mpl, set);
alpar@1
  1052
      return;
alpar@1
  1053
}
alpar@1
  1054
alpar@1
  1055
/*----------------------------------------------------------------------
alpar@1
  1056
-- arelset_size - compute size of "arithmetic" elemental set.
alpar@1
  1057
--
alpar@1
  1058
-- This routine computes the size of "arithmetic" elemental set, which
alpar@1
  1059
-- is specified in the form of arithmetic progression:
alpar@1
  1060
--
alpar@1
  1061
--    { t0 .. tf by dt }.
alpar@1
  1062
--
alpar@1
  1063
-- The size is computed using the formula:
alpar@1
  1064
--
alpar@1
  1065
--    n = max(0, floor((tf - t0) / dt) + 1). */
alpar@1
  1066
alpar@1
  1067
int arelset_size(MPL *mpl, double t0, double tf, double dt)
alpar@1
  1068
{     double temp;
alpar@1
  1069
      if (dt == 0.0)
alpar@1
  1070
         error(mpl, "%.*g .. %.*g by %.*g; zero stride not allowed",
alpar@1
  1071
            DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
alpar@1
  1072
      if (tf > 0.0 && t0 < 0.0 && tf > + 0.999 * DBL_MAX + t0)
alpar@1
  1073
         temp = +DBL_MAX;
alpar@1
  1074
      else if (tf < 0.0 && t0 > 0.0 && tf < - 0.999 * DBL_MAX + t0)
alpar@1
  1075
         temp = -DBL_MAX;
alpar@1
  1076
      else
alpar@1
  1077
         temp = tf - t0;
alpar@1
  1078
      if (fabs(dt) < 1.0 && fabs(temp) > (0.999 * DBL_MAX) * fabs(dt))
alpar@1
  1079
      {  if (temp > 0.0 && dt > 0.0 || temp < 0.0 && dt < 0.0)
alpar@1
  1080
            temp = +DBL_MAX;
alpar@1
  1081
         else
alpar@1
  1082
            temp = 0.0;
alpar@1
  1083
      }
alpar@1
  1084
      else
alpar@1
  1085
      {  temp = floor(temp / dt) + 1.0;
alpar@1
  1086
         if (temp < 0.0) temp = 0.0;
alpar@1
  1087
      }
alpar@1
  1088
      xassert(temp >= 0.0);
alpar@1
  1089
      if (temp > (double)(INT_MAX - 1))
alpar@1
  1090
         error(mpl, "%.*g .. %.*g by %.*g; set too large",
alpar@1
  1091
            DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
alpar@1
  1092
      return (int)(temp + 0.5);
alpar@1
  1093
}
alpar@1
  1094
alpar@1
  1095
/*----------------------------------------------------------------------
alpar@1
  1096
-- arelset_member - compute member of "arithmetic" elemental set.
alpar@1
  1097
--
alpar@1
  1098
-- This routine returns a numeric value of symbol, which is equivalent
alpar@1
  1099
-- to j-th member of given "arithmetic" elemental set specified in the
alpar@1
  1100
-- form of arithmetic progression:
alpar@1
  1101
--
alpar@1
  1102
--    { t0 .. tf by dt }.
alpar@1
  1103
--
alpar@1
  1104
-- The symbol value is computed with the formula:
alpar@1
  1105
--
alpar@1
  1106
--    j-th member = t0 + (j - 1) * dt,
alpar@1
  1107
--
alpar@1
  1108
-- The number j must satisfy to the restriction 1 <= j <= n, where n is
alpar@1
  1109
-- the set size computed by the routine arelset_size. */
alpar@1
  1110
alpar@1
  1111
double arelset_member(MPL *mpl, double t0, double tf, double dt, int j)
alpar@1
  1112
{     xassert(1 <= j && j <= arelset_size(mpl, t0, tf, dt));
alpar@1
  1113
      return t0 + (double)(j - 1) * dt;
alpar@1
  1114
}
alpar@1
  1115
alpar@1
  1116
/*----------------------------------------------------------------------
alpar@1
  1117
-- create_arelset - create "arithmetic" elemental set.
alpar@1
  1118
--
alpar@1
  1119
-- This routine creates "arithmetic" elemental set, which is specified
alpar@1
  1120
-- in the form of arithmetic progression:
alpar@1
  1121
--
alpar@1
  1122
--    { t0 .. tf by dt }.
alpar@1
  1123
--
alpar@1
  1124
-- Components of this set are 1-tuples. */
alpar@1
  1125
alpar@1
  1126
ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt)
alpar@1
  1127
{     ELEMSET *set;
alpar@1
  1128
      int j, n;
alpar@1
  1129
      set = create_elemset(mpl, 1);
alpar@1
  1130
      n = arelset_size(mpl, t0, tf, dt);
alpar@1
  1131
      for (j = 1; j <= n; j++)
alpar@1
  1132
      {  add_tuple
alpar@1
  1133
         (  mpl,
alpar@1
  1134
            set,
alpar@1
  1135
            expand_tuple
alpar@1
  1136
            (  mpl,
alpar@1
  1137
               create_tuple(mpl),
alpar@1
  1138
               create_symbol_num
alpar@1
  1139
               (  mpl,
alpar@1
  1140
                  arelset_member(mpl, t0, tf, dt, j)
alpar@1
  1141
               )
alpar@1
  1142
            )
alpar@1
  1143
         );
alpar@1
  1144
      }
alpar@1
  1145
      return set;
alpar@1
  1146
}
alpar@1
  1147
alpar@1
  1148
/*----------------------------------------------------------------------
alpar@1
  1149
-- set_union - union of two elemental sets.
alpar@1
  1150
--
alpar@1
  1151
-- This routine computes the union:
alpar@1
  1152
--
alpar@1
  1153
--    X U Y = { j | (j in X) or (j in Y) },
alpar@1
  1154
--
alpar@1
  1155
-- where X and Y are given elemental sets (destroyed on exit). */
alpar@1
  1156
alpar@1
  1157
ELEMSET *set_union
alpar@1
  1158
(     MPL *mpl,
alpar@1
  1159
      ELEMSET *X,             /* destroyed */
alpar@1
  1160
      ELEMSET *Y              /* destroyed */
alpar@1
  1161
)
alpar@1
  1162
{     MEMBER *memb;
alpar@1
  1163
      xassert(X != NULL);
alpar@1
  1164
      xassert(X->type == A_NONE);
alpar@1
  1165
      xassert(X->dim > 0);
alpar@1
  1166
      xassert(Y != NULL);
alpar@1
  1167
      xassert(Y->type == A_NONE);
alpar@1
  1168
      xassert(Y->dim > 0);
alpar@1
  1169
      xassert(X->dim == Y->dim);
alpar@1
  1170
      for (memb = Y->head; memb != NULL; memb = memb->next)
alpar@1
  1171
      {  if (find_tuple(mpl, X, memb->tuple) == NULL)
alpar@1
  1172
            add_tuple(mpl, X, copy_tuple(mpl, memb->tuple));
alpar@1
  1173
      }
alpar@1
  1174
      delete_elemset(mpl, Y);
alpar@1
  1175
      return X;
alpar@1
  1176
}
alpar@1
  1177
alpar@1
  1178
/*----------------------------------------------------------------------
alpar@1
  1179
-- set_diff - difference between two elemental sets.
alpar@1
  1180
--
alpar@1
  1181
-- This routine computes the difference:
alpar@1
  1182
--
alpar@1
  1183
--    X \ Y = { j | (j in X) and (j not in Y) },
alpar@1
  1184
--
alpar@1
  1185
-- where X and Y are given elemental sets (destroyed on exit). */
alpar@1
  1186
alpar@1
  1187
ELEMSET *set_diff
alpar@1
  1188
(     MPL *mpl,
alpar@1
  1189
      ELEMSET *X,             /* destroyed */
alpar@1
  1190
      ELEMSET *Y              /* destroyed */
alpar@1
  1191
)
alpar@1
  1192
{     ELEMSET *Z;
alpar@1
  1193
      MEMBER *memb;
alpar@1
  1194
      xassert(X != NULL);
alpar@1
  1195
      xassert(X->type == A_NONE);
alpar@1
  1196
      xassert(X->dim > 0);
alpar@1
  1197
      xassert(Y != NULL);
alpar@1
  1198
      xassert(Y->type == A_NONE);
alpar@1
  1199
      xassert(Y->dim > 0);
alpar@1
  1200
      xassert(X->dim == Y->dim);
alpar@1
  1201
      Z = create_elemset(mpl, X->dim);
alpar@1
  1202
      for (memb = X->head; memb != NULL; memb = memb->next)
alpar@1
  1203
      {  if (find_tuple(mpl, Y, memb->tuple) == NULL)
alpar@1
  1204
            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
alpar@1
  1205
      }
alpar@1
  1206
      delete_elemset(mpl, X);
alpar@1
  1207
      delete_elemset(mpl, Y);
alpar@1
  1208
      return Z;
alpar@1
  1209
}
alpar@1
  1210
alpar@1
  1211
/*----------------------------------------------------------------------
alpar@1
  1212
-- set_symdiff - symmetric difference between two elemental sets.
alpar@1
  1213
--
alpar@1
  1214
-- This routine computes the symmetric difference:
alpar@1
  1215
--
alpar@1
  1216
--    X (+) Y = (X \ Y) U (Y \ X),
alpar@1
  1217
--
alpar@1
  1218
-- where X and Y are given elemental sets (destroyed on exit). */
alpar@1
  1219
alpar@1
  1220
ELEMSET *set_symdiff
alpar@1
  1221
(     MPL *mpl,
alpar@1
  1222
      ELEMSET *X,             /* destroyed */
alpar@1
  1223
      ELEMSET *Y              /* destroyed */
alpar@1
  1224
)
alpar@1
  1225
{     ELEMSET *Z;
alpar@1
  1226
      MEMBER *memb;
alpar@1
  1227
      xassert(X != NULL);
alpar@1
  1228
      xassert(X->type == A_NONE);
alpar@1
  1229
      xassert(X->dim > 0);
alpar@1
  1230
      xassert(Y != NULL);
alpar@1
  1231
      xassert(Y->type == A_NONE);
alpar@1
  1232
      xassert(Y->dim > 0);
alpar@1
  1233
      xassert(X->dim == Y->dim);
alpar@1
  1234
      /* Z := X \ Y */
alpar@1
  1235
      Z = create_elemset(mpl, X->dim);
alpar@1
  1236
      for (memb = X->head; memb != NULL; memb = memb->next)
alpar@1
  1237
      {  if (find_tuple(mpl, Y, memb->tuple) == NULL)
alpar@1
  1238
            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
alpar@1
  1239
      }
alpar@1
  1240
      /* Z := Z U (Y \ X) */
alpar@1
  1241
      for (memb = Y->head; memb != NULL; memb = memb->next)
alpar@1
  1242
      {  if (find_tuple(mpl, X, memb->tuple) == NULL)
alpar@1
  1243
            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
alpar@1
  1244
      }
alpar@1
  1245
      delete_elemset(mpl, X);
alpar@1
  1246
      delete_elemset(mpl, Y);
alpar@1
  1247
      return Z;
alpar@1
  1248
}
alpar@1
  1249
alpar@1
  1250
/*----------------------------------------------------------------------
alpar@1
  1251
-- set_inter - intersection of two elemental sets.
alpar@1
  1252
--
alpar@1
  1253
-- This routine computes the intersection:
alpar@1
  1254
--
alpar@1
  1255
--    X ^ Y = { j | (j in X) and (j in Y) },
alpar@1
  1256
--
alpar@1
  1257
-- where X and Y are given elemental sets (destroyed on exit). */
alpar@1
  1258
alpar@1
  1259
ELEMSET *set_inter
alpar@1
  1260
(     MPL *mpl,
alpar@1
  1261
      ELEMSET *X,             /* destroyed */
alpar@1
  1262
      ELEMSET *Y              /* destroyed */
alpar@1
  1263
)
alpar@1
  1264
{     ELEMSET *Z;
alpar@1
  1265
      MEMBER *memb;
alpar@1
  1266
      xassert(X != NULL);
alpar@1
  1267
      xassert(X->type == A_NONE);
alpar@1
  1268
      xassert(X->dim > 0);
alpar@1
  1269
      xassert(Y != NULL);
alpar@1
  1270
      xassert(Y->type == A_NONE);
alpar@1
  1271
      xassert(Y->dim > 0);
alpar@1
  1272
      xassert(X->dim == Y->dim);
alpar@1
  1273
      Z = create_elemset(mpl, X->dim);
alpar@1
  1274
      for (memb = X->head; memb != NULL; memb = memb->next)
alpar@1
  1275
      {  if (find_tuple(mpl, Y, memb->tuple) != NULL)
alpar@1
  1276
            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
alpar@1
  1277
      }
alpar@1
  1278
      delete_elemset(mpl, X);
alpar@1
  1279
      delete_elemset(mpl, Y);
alpar@1
  1280
      return Z;
alpar@1
  1281
}
alpar@1
  1282
alpar@1
  1283
/*----------------------------------------------------------------------
alpar@1
  1284
-- set_cross - cross (Cartesian) product of two elemental sets.
alpar@1
  1285
--
alpar@1
  1286
-- This routine computes the cross (Cartesian) product:
alpar@1
  1287
--
alpar@1
  1288
--    X x Y = { (i,j) | (i in X) and (j in Y) },
alpar@1
  1289
--
alpar@1
  1290
-- where X and Y are given elemental sets (destroyed on exit). */
alpar@1
  1291
alpar@1
  1292
ELEMSET *set_cross
alpar@1
  1293
(     MPL *mpl,
alpar@1
  1294
      ELEMSET *X,             /* destroyed */
alpar@1
  1295
      ELEMSET *Y              /* destroyed */
alpar@1
  1296
)
alpar@1
  1297
{     ELEMSET *Z;
alpar@1
  1298
      MEMBER *memx, *memy;
alpar@1
  1299
      TUPLE *tuple, *temp;
alpar@1
  1300
      xassert(X != NULL);
alpar@1
  1301
      xassert(X->type == A_NONE);
alpar@1
  1302
      xassert(X->dim > 0);
alpar@1
  1303
      xassert(Y != NULL);
alpar@1
  1304
      xassert(Y->type == A_NONE);
alpar@1
  1305
      xassert(Y->dim > 0);
alpar@1
  1306
      Z = create_elemset(mpl, X->dim + Y->dim);
alpar@1
  1307
      for (memx = X->head; memx != NULL; memx = memx->next)
alpar@1
  1308
      {  for (memy = Y->head; memy != NULL; memy = memy->next)
alpar@1
  1309
         {  tuple = copy_tuple(mpl, memx->tuple);
alpar@1
  1310
            for (temp = memy->tuple; temp != NULL; temp = temp->next)
alpar@1
  1311
               tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
alpar@1
  1312
                  temp->sym));
alpar@1
  1313
            add_tuple(mpl, Z, tuple);
alpar@1
  1314
         }
alpar@1
  1315
      }
alpar@1
  1316
      delete_elemset(mpl, X);
alpar@1
  1317
      delete_elemset(mpl, Y);
alpar@1
  1318
      return Z;
alpar@1
  1319
}
alpar@1
  1320
alpar@1
  1321
/**********************************************************************/
alpar@1
  1322
/* * *                    ELEMENTAL VARIABLES                     * * */
alpar@1
  1323
/**********************************************************************/
alpar@1
  1324
alpar@1
  1325
/* (there are no specific routines for elemental variables) */
alpar@1
  1326
alpar@1
  1327
/**********************************************************************/
alpar@1
  1328
/* * *                        LINEAR FORMS                        * * */
alpar@1
  1329
/**********************************************************************/
alpar@1
  1330
alpar@1
  1331
/*----------------------------------------------------------------------
alpar@1
  1332
-- constant_term - create constant term.
alpar@1
  1333
--
alpar@1
  1334
-- This routine creates the linear form, which is a constant term. */
alpar@1
  1335
alpar@1
  1336
FORMULA *constant_term(MPL *mpl, double coef)
alpar@1
  1337
{     FORMULA *form;
alpar@1
  1338
      if (coef == 0.0)
alpar@1
  1339
         form = NULL;
alpar@1
  1340
      else
alpar@1
  1341
      {  form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
alpar@1
  1342
         form->coef = coef;
alpar@1
  1343
         form->var = NULL;
alpar@1
  1344
         form->next = NULL;
alpar@1
  1345
      }
alpar@1
  1346
      return form;
alpar@1
  1347
}
alpar@1
  1348
alpar@1
  1349
/*----------------------------------------------------------------------
alpar@1
  1350
-- single_variable - create single variable.
alpar@1
  1351
--
alpar@1
  1352
-- This routine creates the linear form, which is a single elemental
alpar@1
  1353
-- variable. */
alpar@1
  1354
alpar@1
  1355
FORMULA *single_variable
alpar@1
  1356
(     MPL *mpl,
alpar@1
  1357
      ELEMVAR *var            /* referenced */
alpar@1
  1358
)
alpar@1
  1359
{     FORMULA *form;
alpar@1
  1360
      xassert(var != NULL);
alpar@1
  1361
      form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
alpar@1
  1362
      form->coef = 1.0;
alpar@1
  1363
      form->var = var;
alpar@1
  1364
      form->next = NULL;
alpar@1
  1365
      return form;
alpar@1
  1366
}
alpar@1
  1367
alpar@1
  1368
/*----------------------------------------------------------------------
alpar@1
  1369
-- copy_formula - make copy of linear form.
alpar@1
  1370
--
alpar@1
  1371
-- This routine returns an exact copy of linear form. */
alpar@1
  1372
alpar@1
  1373
FORMULA *copy_formula
alpar@1
  1374
(     MPL *mpl,
alpar@1
  1375
      FORMULA *form           /* not changed */
alpar@1
  1376
)
alpar@1
  1377
{     FORMULA *head, *tail;
alpar@1
  1378
      if (form == NULL)
alpar@1
  1379
         head = NULL;
alpar@1
  1380
      else
alpar@1
  1381
      {  head = tail = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
alpar@1
  1382
         for (; form != NULL; form = form->next)
alpar@1
  1383
         {  tail->coef = form->coef;
alpar@1
  1384
            tail->var = form->var;
alpar@1
  1385
            if (form->next != NULL)
alpar@1
  1386
tail = (tail->next = dmp_get_atom(mpl->formulae, sizeof(FORMULA)));
alpar@1
  1387
         }
alpar@1
  1388
         tail->next = NULL;
alpar@1
  1389
      }
alpar@1
  1390
      return head;
alpar@1
  1391
}
alpar@1
  1392
alpar@1
  1393
/*----------------------------------------------------------------------
alpar@1
  1394
-- delete_formula - delete linear form.
alpar@1
  1395
--
alpar@1
  1396
-- This routine deletes specified linear form. */
alpar@1
  1397
alpar@1
  1398
void delete_formula
alpar@1
  1399
(     MPL *mpl,
alpar@1
  1400
      FORMULA *form           /* destroyed */
alpar@1
  1401
)
alpar@1
  1402
{     FORMULA *temp;
alpar@1
  1403
      while (form != NULL)
alpar@1
  1404
      {  temp = form;
alpar@1
  1405
         form = form->next;
alpar@1
  1406
         dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
alpar@1
  1407
      }
alpar@1
  1408
      return;
alpar@1
  1409
}
alpar@1
  1410
alpar@1
  1411
/*----------------------------------------------------------------------
alpar@1
  1412
-- linear_comb - linear combination of two linear forms.
alpar@1
  1413
--
alpar@1
  1414
-- This routine computes the linear combination:
alpar@1
  1415
--
alpar@1
  1416
--    a * fx + b * fy,
alpar@1
  1417
--
alpar@1
  1418
-- where a and b are numeric coefficients, fx and fy are linear forms
alpar@1
  1419
-- (destroyed on exit). */
alpar@1
  1420
alpar@1
  1421
FORMULA *linear_comb
alpar@1
  1422
(     MPL *mpl,
alpar@1
  1423
      double a, FORMULA *fx,  /* destroyed */
alpar@1
  1424
      double b, FORMULA *fy   /* destroyed */
alpar@1
  1425
)
alpar@1
  1426
{     FORMULA *form = NULL, *term, *temp;
alpar@1
  1427
      double c0 = 0.0;
alpar@1
  1428
      for (term = fx; term != NULL; term = term->next)
alpar@1
  1429
      {  if (term->var == NULL)
alpar@1
  1430
            c0 = fp_add(mpl, c0, fp_mul(mpl, a, term->coef));
alpar@1
  1431
         else
alpar@1
  1432
            term->var->temp =
alpar@1
  1433
               fp_add(mpl, term->var->temp, fp_mul(mpl, a, term->coef));
alpar@1
  1434
      }
alpar@1
  1435
      for (term = fy; term != NULL; term = term->next)
alpar@1
  1436
      {  if (term->var == NULL)
alpar@1
  1437
            c0 = fp_add(mpl, c0, fp_mul(mpl, b, term->coef));
alpar@1
  1438
         else
alpar@1
  1439
            term->var->temp =
alpar@1
  1440
               fp_add(mpl, term->var->temp, fp_mul(mpl, b, term->coef));
alpar@1
  1441
      }
alpar@1
  1442
      for (term = fx; term != NULL; term = term->next)
alpar@1
  1443
      {  if (term->var != NULL && term->var->temp != 0.0)
alpar@1
  1444
         {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
alpar@1
  1445
            temp->coef = term->var->temp, temp->var = term->var;
alpar@1
  1446
            temp->next = form, form = temp;
alpar@1
  1447
            term->var->temp = 0.0;
alpar@1
  1448
         }
alpar@1
  1449
      }
alpar@1
  1450
      for (term = fy; term != NULL; term = term->next)
alpar@1
  1451
      {  if (term->var != NULL && term->var->temp != 0.0)
alpar@1
  1452
         {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
alpar@1
  1453
            temp->coef = term->var->temp, temp->var = term->var;
alpar@1
  1454
            temp->next = form, form = temp;
alpar@1
  1455
            term->var->temp = 0.0;
alpar@1
  1456
         }
alpar@1
  1457
      }
alpar@1
  1458
      if (c0 != 0.0)
alpar@1
  1459
      {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
alpar@1
  1460
         temp->coef = c0, temp->var = NULL;
alpar@1
  1461
         temp->next = form, form = temp;
alpar@1
  1462
      }
alpar@1
  1463
      delete_formula(mpl, fx);
alpar@1
  1464
      delete_formula(mpl, fy);
alpar@1
  1465
      return form;
alpar@1
  1466
}
alpar@1
  1467
alpar@1
  1468
/*----------------------------------------------------------------------
alpar@1
  1469
-- remove_constant - remove constant term from linear form.
alpar@1
  1470
--
alpar@1
  1471
-- This routine removes constant term from linear form and stores its
alpar@1
  1472
-- value to given location. */
alpar@1
  1473
alpar@1
  1474
FORMULA *remove_constant
alpar@1
  1475
(     MPL *mpl,
alpar@1
  1476
      FORMULA *form,          /* destroyed */
alpar@1
  1477
      double *coef            /* modified */
alpar@1
  1478
)
alpar@1
  1479
{     FORMULA *head = NULL, *temp;
alpar@1
  1480
      *coef = 0.0;
alpar@1
  1481
      while (form != NULL)
alpar@1
  1482
      {  temp = form;
alpar@1
  1483
         form = form->next;
alpar@1
  1484
         if (temp->var == NULL)
alpar@1
  1485
         {  /* constant term */
alpar@1
  1486
            *coef = fp_add(mpl, *coef, temp->coef);
alpar@1
  1487
            dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
alpar@1
  1488
         }
alpar@1
  1489
         else
alpar@1
  1490
         {  /* linear term */
alpar@1
  1491
            temp->next = head;
alpar@1
  1492
            head = temp;
alpar@1
  1493
         }
alpar@1
  1494
      }
alpar@1
  1495
      return head;
alpar@1
  1496
}
alpar@1
  1497
alpar@1
  1498
/*----------------------------------------------------------------------
alpar@1
  1499
-- reduce_terms - reduce identical terms in linear form.
alpar@1
  1500
--
alpar@1
  1501
-- This routine reduces identical terms in specified linear form. */
alpar@1
  1502
alpar@1
  1503
FORMULA *reduce_terms
alpar@1
  1504
(     MPL *mpl,
alpar@1
  1505
      FORMULA *form           /* destroyed */
alpar@1
  1506
)
alpar@1
  1507
{     FORMULA *term, *next_term;
alpar@1
  1508
      double c0 = 0.0;
alpar@1
  1509
      for (term = form; term != NULL; term = term->next)
alpar@1
  1510
      {  if (term->var == NULL)
alpar@1
  1511
            c0 = fp_add(mpl, c0, term->coef);
alpar@1
  1512
         else
alpar@1
  1513
            term->var->temp = fp_add(mpl, term->var->temp, term->coef);
alpar@1
  1514
      }
alpar@1
  1515
      next_term = form, form = NULL;
alpar@1
  1516
      for (term = next_term; term != NULL; term = next_term)
alpar@1
  1517
      {  next_term = term->next;
alpar@1
  1518
         if (term->var == NULL && c0 != 0.0)
alpar@1
  1519
         {  term->coef = c0, c0 = 0.0;
alpar@1
  1520
            term->next = form, form = term;
alpar@1
  1521
         }
alpar@1
  1522
         else if (term->var != NULL && term->var->temp != 0.0)
alpar@1
  1523
         {  term->coef = term->var->temp, term->var->temp = 0.0;
alpar@1
  1524
            term->next = form, form = term;
alpar@1
  1525
         }
alpar@1
  1526
         else
alpar@1
  1527
            dmp_free_atom(mpl->formulae, term, sizeof(FORMULA));
alpar@1
  1528
      }
alpar@1
  1529
      return form;
alpar@1
  1530
}
alpar@1
  1531
alpar@1
  1532
/**********************************************************************/
alpar@1
  1533
/* * *                   ELEMENTAL CONSTRAINTS                    * * */
alpar@1
  1534
/**********************************************************************/
alpar@1
  1535
alpar@1
  1536
/* (there are no specific routines for elemental constraints) */
alpar@1
  1537
alpar@1
  1538
/**********************************************************************/
alpar@1
  1539
/* * *                       GENERIC VALUES                       * * */
alpar@1
  1540
/**********************************************************************/
alpar@1
  1541
alpar@1
  1542
/*----------------------------------------------------------------------
alpar@1
  1543
-- delete_value - delete generic value.
alpar@1
  1544
--
alpar@1
  1545
-- This routine deletes specified generic value.
alpar@1
  1546
--
alpar@1
  1547
-- NOTE: The generic value to be deleted must be valid. */
alpar@1
  1548
alpar@1
  1549
void delete_value
alpar@1
  1550
(     MPL *mpl,
alpar@1
  1551
      int type,
alpar@1
  1552
      VALUE *value            /* content destroyed */
alpar@1
  1553
)
alpar@1
  1554
{     xassert(value != NULL);
alpar@1
  1555
      switch (type)
alpar@1
  1556
      {  case A_NONE:
alpar@1
  1557
            value->none = NULL;
alpar@1
  1558
            break;
alpar@1
  1559
         case A_NUMERIC:
alpar@1
  1560
            value->num = 0.0;
alpar@1
  1561
            break;
alpar@1
  1562
         case A_SYMBOLIC:
alpar@1
  1563
            delete_symbol(mpl, value->sym), value->sym = NULL;
alpar@1
  1564
            break;
alpar@1
  1565
         case A_LOGICAL:
alpar@1
  1566
            value->bit = 0;
alpar@1
  1567
            break;
alpar@1
  1568
         case A_TUPLE:
alpar@1
  1569
            delete_tuple(mpl, value->tuple), value->tuple = NULL;
alpar@1
  1570
            break;
alpar@1
  1571
         case A_ELEMSET:
alpar@1
  1572
            delete_elemset(mpl, value->set), value->set = NULL;
alpar@1
  1573
            break;
alpar@1
  1574
         case A_ELEMVAR:
alpar@1
  1575
            value->var = NULL;
alpar@1
  1576
            break;
alpar@1
  1577
         case A_FORMULA:
alpar@1
  1578
            delete_formula(mpl, value->form), value->form = NULL;
alpar@1
  1579
            break;
alpar@1
  1580
         case A_ELEMCON:
alpar@1
  1581
            value->con = NULL;
alpar@1
  1582
            break;
alpar@1
  1583
         default:
alpar@1
  1584
            xassert(type != type);
alpar@1
  1585
      }
alpar@1
  1586
      return;
alpar@1
  1587
}
alpar@1
  1588
alpar@1
  1589
/**********************************************************************/
alpar@1
  1590
/* * *                SYMBOLICALLY INDEXED ARRAYS                 * * */
alpar@1
  1591
/**********************************************************************/
alpar@1
  1592
alpar@1
  1593
/*----------------------------------------------------------------------
alpar@1
  1594
-- create_array - create array.
alpar@1
  1595
--
alpar@1
  1596
-- This routine creates an array of specified type and dimension. Being
alpar@1
  1597
-- created the array is initially empty.
alpar@1
  1598
--
alpar@1
  1599
-- The type indicator determines generic values, which can be assigned
alpar@1
  1600
-- to the array members:
alpar@1
  1601
--
alpar@1
  1602
-- A_NONE     - none (members have no assigned values)
alpar@1
  1603
-- A_NUMERIC  - floating-point numbers
alpar@1
  1604
-- A_SYMBOLIC - symbols
alpar@1
  1605
-- A_ELEMSET  - elemental sets
alpar@1
  1606
-- A_ELEMVAR  - elemental variables
alpar@1
  1607
-- A_ELEMCON  - elemental constraints
alpar@1
  1608
--
alpar@1
  1609
-- The dimension may be 0, in which case the array consists of the only
alpar@1
  1610
-- member (such arrays represent 0-dimensional objects). */
alpar@1
  1611
alpar@1
  1612
ARRAY *create_array(MPL *mpl, int type, int dim)
alpar@1
  1613
{     ARRAY *array;
alpar@1
  1614
      xassert(type == A_NONE || type == A_NUMERIC ||
alpar@1
  1615
             type == A_SYMBOLIC || type == A_ELEMSET ||
alpar@1
  1616
             type == A_ELEMVAR || type == A_ELEMCON);
alpar@1
  1617
      xassert(dim >= 0);
alpar@1
  1618
      array = dmp_get_atom(mpl->arrays, sizeof(ARRAY));
alpar@1
  1619
      array->type = type;
alpar@1
  1620
      array->dim = dim;
alpar@1
  1621
      array->size = 0;
alpar@1
  1622
      array->head = NULL;
alpar@1
  1623
      array->tail = NULL;
alpar@1
  1624
      array->tree = NULL;
alpar@1
  1625
      array->prev = NULL;
alpar@1
  1626
      array->next = mpl->a_list;
alpar@1
  1627
      /* include the array in the global array list */
alpar@1
  1628
      if (array->next != NULL) array->next->prev = array;
alpar@1
  1629
      mpl->a_list = array;
alpar@1
  1630
      return array;
alpar@1
  1631
}
alpar@1
  1632
alpar@1
  1633
/*----------------------------------------------------------------------
alpar@1
  1634
-- find_member - find array member with given n-tuple.
alpar@1
  1635
--
alpar@1
  1636
-- This routine finds an array member, which has given n-tuple. If the
alpar@1
  1637
-- array is short, the linear search is used. Otherwise the routine
alpar@1
  1638
-- autimatically creates the search tree (i.e. the array index) to find
alpar@1
  1639
-- members for logarithmic time. */
alpar@1
  1640
alpar@1
  1641
static int compare_member_tuples(void *info, const void *key1,
alpar@1
  1642
      const void *key2)
alpar@1
  1643
{     /* this is an auxiliary routine used to compare keys, which are
alpar@1
  1644
         n-tuples assigned to array members */
alpar@1
  1645
      return compare_tuples((MPL *)info, (TUPLE *)key1, (TUPLE *)key2);
alpar@1
  1646
}
alpar@1
  1647
alpar@1
  1648
MEMBER *find_member
alpar@1
  1649
(     MPL *mpl,
alpar@1
  1650
      ARRAY *array,           /* not changed */
alpar@1
  1651
      TUPLE *tuple            /* not changed */
alpar@1
  1652
)
alpar@1
  1653
{     MEMBER *memb;
alpar@1
  1654
      xassert(array != NULL);
alpar@1
  1655
      /* the n-tuple must have the same dimension as the array */
alpar@1
  1656
      xassert(tuple_dimen(mpl, tuple) == array->dim);
alpar@1
  1657
      /* if the array is large enough, create the search tree and index
alpar@1
  1658
         all existing members of the array */
alpar@1
  1659
      if (array->size > 30 && array->tree == NULL)
alpar@1
  1660
      {  array->tree = avl_create_tree(compare_member_tuples, mpl);
alpar@1
  1661
         for (memb = array->head; memb != NULL; memb = memb->next)
alpar@1
  1662
avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
alpar@1
  1663
               (void *)memb);
alpar@1
  1664
      }
alpar@1
  1665
      /* find a member, which has the given tuple */
alpar@1
  1666
      if (array->tree == NULL)
alpar@1
  1667
      {  /* the search tree doesn't exist; use the linear search */
alpar@1
  1668
         for (memb = array->head; memb != NULL; memb = memb->next)
alpar@1
  1669
            if (compare_tuples(mpl, memb->tuple, tuple) == 0) break;
alpar@1
  1670
      }
alpar@1
  1671
      else
alpar@1
  1672
      {  /* the search tree exists; use the binary search */
alpar@1
  1673
         AVLNODE *node;
alpar@1
  1674
         node = avl_find_node(array->tree, tuple);
alpar@1
  1675
memb = (MEMBER *)(node == NULL ? NULL : avl_get_node_link(node));
alpar@1
  1676
      }
alpar@1
  1677
      return memb;
alpar@1
  1678
}
alpar@1
  1679
alpar@1
  1680
/*----------------------------------------------------------------------
alpar@1
  1681
-- add_member - add new member to array.
alpar@1
  1682
--
alpar@1
  1683
-- This routine creates a new member with given n-tuple and adds it to
alpar@1
  1684
-- specified array.
alpar@1
  1685
--
alpar@1
  1686
-- For the sake of efficiency this routine doesn't check whether the
alpar@1
  1687
-- array already contains a member with the given n-tuple or not. Thus,
alpar@1
  1688
-- if necessary, the calling program should use the routine find_member
alpar@1
  1689
-- in order to be sure that the array contains no member with the same
alpar@1
  1690
-- n-tuple, because members with duplicate n-tuples are not allowed.
alpar@1
  1691
--
alpar@1
  1692
-- This routine assigns no generic value to the new member, because the
alpar@1
  1693
-- calling program must do that. */
alpar@1
  1694
alpar@1
  1695
MEMBER *add_member
alpar@1
  1696
(     MPL *mpl,
alpar@1
  1697
      ARRAY *array,           /* modified */
alpar@1
  1698
      TUPLE *tuple            /* destroyed */
alpar@1
  1699
)
alpar@1
  1700
{     MEMBER *memb;
alpar@1
  1701
      xassert(array != NULL);
alpar@1
  1702
      /* the n-tuple must have the same dimension as the array */
alpar@1
  1703
      xassert(tuple_dimen(mpl, tuple) == array->dim);
alpar@1
  1704
      /* create new member */
alpar@1
  1705
      memb = dmp_get_atom(mpl->members, sizeof(MEMBER));
alpar@1
  1706
      memb->tuple = tuple;
alpar@1
  1707
      memb->next = NULL;
alpar@1
  1708
      memset(&memb->value, '?', sizeof(VALUE));
alpar@1
  1709
      /* and append it to the member list */
alpar@1
  1710
      array->size++;
alpar@1
  1711
      if (array->head == NULL)
alpar@1
  1712
         array->head = memb;
alpar@1
  1713
      else
alpar@1
  1714
         array->tail->next = memb;
alpar@1
  1715
      array->tail = memb;
alpar@1
  1716
      /* if the search tree exists, index the new member */
alpar@1
  1717
      if (array->tree != NULL)
alpar@1
  1718
avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
alpar@1
  1719
            (void *)memb);
alpar@1
  1720
      return memb;
alpar@1
  1721
}
alpar@1
  1722
alpar@1
  1723
/*----------------------------------------------------------------------
alpar@1
  1724
-- delete_array - delete array.
alpar@1
  1725
--
alpar@1
  1726
-- This routine deletes specified array.
alpar@1
  1727
--
alpar@1
  1728
-- Generic values assigned to the array members are not deleted by this
alpar@1
  1729
-- routine. The calling program itself must delete all assigned generic
alpar@1
  1730
-- values before deleting the array. */
alpar@1
  1731
alpar@1
  1732
void delete_array
alpar@1
  1733
(     MPL *mpl,
alpar@1
  1734
      ARRAY *array            /* destroyed */
alpar@1
  1735
)
alpar@1
  1736
{     MEMBER *memb;
alpar@1
  1737
      xassert(array != NULL);
alpar@1
  1738
      /* delete all existing array members */
alpar@1
  1739
      while (array->head != NULL)
alpar@1
  1740
      {  memb = array->head;
alpar@1
  1741
         array->head = memb->next;
alpar@1
  1742
         delete_tuple(mpl, memb->tuple);
alpar@1
  1743
         dmp_free_atom(mpl->members, memb, sizeof(MEMBER));
alpar@1
  1744
      }
alpar@1
  1745
      /* if the search tree exists, also delete it */
alpar@1
  1746
      if (array->tree != NULL) avl_delete_tree(array->tree);
alpar@1
  1747
      /* remove the array from the global array list */
alpar@1
  1748
      if (array->prev == NULL)
alpar@1
  1749
         mpl->a_list = array->next;
alpar@1
  1750
      else
alpar@1
  1751
         array->prev->next = array->next;
alpar@1
  1752
      if (array->next == NULL)
alpar@1
  1753
         ;
alpar@1
  1754
      else
alpar@1
  1755
         array->next->prev = array->prev;
alpar@1
  1756
      /* delete the array descriptor */
alpar@1
  1757
      dmp_free_atom(mpl->arrays, array, sizeof(ARRAY));
alpar@1
  1758
      return;
alpar@1
  1759
}
alpar@1
  1760
alpar@1
  1761
/**********************************************************************/
alpar@1
  1762
/* * *                 DOMAINS AND DUMMY INDICES                  * * */
alpar@1
  1763
/**********************************************************************/
alpar@1
  1764
alpar@1
  1765
/*----------------------------------------------------------------------
alpar@1
  1766
-- assign_dummy_index - assign new value to dummy index.
alpar@1
  1767
--
alpar@1
  1768
-- This routine assigns new value to specified dummy index and, that is
alpar@1
  1769
-- important, invalidates all temporary resultant values, which depends
alpar@1
  1770
-- on that dummy index. */
alpar@1
  1771
alpar@1
  1772
void assign_dummy_index
alpar@1
  1773
(     MPL *mpl,
alpar@1
  1774
      DOMAIN_SLOT *slot,      /* modified */
alpar@1
  1775
      SYMBOL *value           /* not changed */
alpar@1
  1776
)
alpar@1
  1777
{     CODE *leaf, *code;
alpar@1
  1778
      xassert(slot != NULL);
alpar@1
  1779
      xassert(value != NULL);
alpar@1
  1780
      /* delete the current value assigned to the dummy index */
alpar@1
  1781
      if (slot->value != NULL)
alpar@1
  1782
      {  /* if the current value and the new one are identical, actual
alpar@1
  1783
            assignment is not needed */
alpar@1
  1784
         if (compare_symbols(mpl, slot->value, value) == 0) goto done;
alpar@1
  1785
         /* delete a symbol, which is the current value */
alpar@1
  1786
         delete_symbol(mpl, slot->value), slot->value = NULL;
alpar@1
  1787
      }
alpar@1
  1788
      /* now walk through all the pseudo-codes with op = O_INDEX, which
alpar@1
  1789
         refer to the dummy index to be changed (these pseudo-codes are
alpar@1
  1790
         leaves in the forest of *all* expressions in the database) */
alpar@1
  1791
      for (leaf = slot->list; leaf != NULL; leaf = leaf->arg.index.
alpar@1
  1792
         next)
alpar@1
  1793
      {  xassert(leaf->op == O_INDEX);
alpar@1
  1794
         /* invalidate all resultant values, which depend on the dummy
alpar@1
  1795
            index, walking from the current leaf toward the root of the
alpar@1
  1796
            corresponding expression tree */
alpar@1
  1797
         for (code = leaf; code != NULL; code = code->up)
alpar@1
  1798
         {  if (code->valid)
alpar@1
  1799
            {  /* invalidate and delete resultant value */
alpar@1
  1800
               code->valid = 0;
alpar@1
  1801
               delete_value(mpl, code->type, &code->value);
alpar@1
  1802
            }
alpar@1
  1803
         }
alpar@1
  1804
      }
alpar@1
  1805
      /* assign new value to the dummy index */
alpar@1
  1806
      slot->value = copy_symbol(mpl, value);
alpar@1
  1807
done: return;
alpar@1
  1808
}
alpar@1
  1809
alpar@1
  1810
/*----------------------------------------------------------------------
alpar@1
  1811
-- update_dummy_indices - update current values of dummy indices.
alpar@1
  1812
--
alpar@1
  1813
-- This routine assigns components of "backup" n-tuple to dummy indices
alpar@1
  1814
-- of specified domain block. If no "backup" n-tuple is defined for the
alpar@1
  1815
-- domain block, values of the dummy indices remain untouched. */
alpar@1
  1816
alpar@1
  1817
void update_dummy_indices
alpar@1
  1818
(     MPL *mpl,
alpar@1
  1819
      DOMAIN_BLOCK *block     /* not changed */
alpar@1
  1820
)
alpar@1
  1821
{     DOMAIN_SLOT *slot;
alpar@1
  1822
      TUPLE *temp;
alpar@1
  1823
      if (block->backup != NULL)
alpar@1
  1824
      {  for (slot = block->list, temp = block->backup; slot != NULL;
alpar@1
  1825
            slot = slot->next, temp = temp->next)
alpar@1
  1826
         {  xassert(temp != NULL);
alpar@1
  1827
            xassert(temp->sym != NULL);
alpar@1
  1828
            assign_dummy_index(mpl, slot, temp->sym);
alpar@1
  1829
         }
alpar@1
  1830
      }
alpar@1
  1831
      return;
alpar@1
  1832
}
alpar@1
  1833
alpar@1
  1834
/*----------------------------------------------------------------------
alpar@1
  1835
-- enter_domain_block - enter domain block.
alpar@1
  1836
--
alpar@1
  1837
-- Let specified domain block have the form:
alpar@1
  1838
--
alpar@1
  1839
--    { ..., (j1, j2, ..., jn) in J, ... }
alpar@1
  1840
--
alpar@1
  1841
-- where j1, j2, ..., jn are dummy indices, J is a basic set.
alpar@1
  1842
--
alpar@1
  1843
-- This routine does the following:
alpar@1
  1844
--
alpar@1
  1845
-- 1. Checks if the given n-tuple is a member of the basic set J. Note
alpar@1
  1846
--    that J being *out of the scope* of the domain block cannot depend
alpar@1
  1847
--    on the dummy indices in the same and inner domain blocks, so it
alpar@1
  1848
--    can be computed before the dummy indices are assigned new values.
alpar@1
  1849
--    If this check fails, the routine returns with non-zero code.
alpar@1
  1850
--
alpar@1
  1851
-- 2. Saves current values of the dummy indices j1, j2, ..., jn.
alpar@1
  1852
--
alpar@1
  1853
-- 3. Assigns new values, which are components of the given n-tuple, to
alpar@1
  1854
--    the dummy indices j1, j2, ..., jn. If dimension of the n-tuple is
alpar@1
  1855
--    larger than n, its extra components n+1, n+2, ... are not used.
alpar@1
  1856
--
alpar@1
  1857
-- 4. Calls the formal routine func which either enters the next domain
alpar@1
  1858
--    block or evaluates some code within the domain scope.
alpar@1
  1859
--
alpar@1
  1860
-- 5. Restores former values of the dummy indices j1, j2, ..., jn.
alpar@1
  1861
--
alpar@1
  1862
-- Since current values assigned to the dummy indices on entry to this
alpar@1
  1863
-- routine are restored on exit, the formal routine func is allowed to
alpar@1
  1864
-- call this routine recursively. */
alpar@1
  1865
alpar@1
  1866
int enter_domain_block
alpar@1
  1867
(     MPL *mpl,
alpar@1
  1868
      DOMAIN_BLOCK *block,    /* not changed */
alpar@1
  1869
      TUPLE *tuple,           /* not changed */
alpar@1
  1870
      void *info, void (*func)(MPL *mpl, void *info)
alpar@1
  1871
)
alpar@1
  1872
{     TUPLE *backup;
alpar@1
  1873
      int ret = 0;
alpar@1
  1874
      /* check if the given n-tuple is a member of the basic set */
alpar@1
  1875
      xassert(block->code != NULL);
alpar@1
  1876
      if (!is_member(mpl, block->code, tuple))
alpar@1
  1877
      {  ret = 1;
alpar@1
  1878
         goto done;
alpar@1
  1879
      }
alpar@1
  1880
      /* save reference to "backup" n-tuple, which was used to assign
alpar@1
  1881
         current values of the dummy indices (it is sufficient to save
alpar@1
  1882
         reference, not value, because that n-tuple is defined in some
alpar@1
  1883
         outer level of recursion and therefore cannot be changed on
alpar@1
  1884
         this and deeper recursive calls) */
alpar@1
  1885
      backup = block->backup;
alpar@1
  1886
      /* set up new "backup" n-tuple, which defines new values of the
alpar@1
  1887
         dummy indices */
alpar@1
  1888
      block->backup = tuple;
alpar@1
  1889
      /* assign new values to the dummy indices */
alpar@1
  1890
      update_dummy_indices(mpl, block);
alpar@1
  1891
      /* call the formal routine that does the rest part of the job */
alpar@1
  1892
      func(mpl, info);
alpar@1
  1893
      /* restore reference to the former "backup" n-tuple */
alpar@1
  1894
      block->backup = backup;
alpar@1
  1895
      /* restore former values of the dummy indices; note that if the
alpar@1
  1896
         domain block just escaped has no other active instances which
alpar@1
  1897
         may exist due to recursion (it is indicated by a null pointer
alpar@1
  1898
         to the former n-tuple), former values of the dummy indices are
alpar@1
  1899
         undefined; therefore in this case the routine keeps currently
alpar@1
  1900
         assigned values of the dummy indices that involves keeping all
alpar@1
  1901
         dependent temporary results and thereby, if this domain block
alpar@1
  1902
         is not used recursively, allows improving efficiency */
alpar@1
  1903
      update_dummy_indices(mpl, block);
alpar@1
  1904
done: return ret;
alpar@1
  1905
}
alpar@1
  1906
alpar@1
  1907
/*----------------------------------------------------------------------
alpar@1
  1908
-- eval_within_domain - perform evaluation within domain scope.
alpar@1
  1909
--
alpar@1
  1910
-- This routine assigns new values (symbols) to all dummy indices of
alpar@1
  1911
-- specified domain and calls the formal routine func, which is used to
alpar@1
  1912
-- evaluate some code in the domain scope. Each free dummy index in the
alpar@1
  1913
-- domain is assigned a value specified in the corresponding component
alpar@1
  1914
-- of given n-tuple. Non-free dummy indices are assigned values, which
alpar@1
  1915
-- are computed by this routine.
alpar@1
  1916
--
alpar@1
  1917
-- Number of components in the given n-tuple must be the same as number
alpar@1
  1918
-- of free indices in the domain.
alpar@1
  1919
--
alpar@1
  1920
-- If the given n-tuple is not a member of the domain set, the routine
alpar@1
  1921
-- func is not called, and non-zero code is returned.
alpar@1
  1922
--
alpar@1
  1923
-- For the sake of convenience it is allowed to specify domain as NULL
alpar@1
  1924
-- (then n-tuple also must be 0-tuple, i.e. empty), in which case this
alpar@1
  1925
-- routine just calls the routine func and returns zero.
alpar@1
  1926
--
alpar@1
  1927
-- This routine allows recursive calls from the routine func providing
alpar@1
  1928
-- correct values of dummy indices for each instance.
alpar@1
  1929
--
alpar@1
  1930
-- NOTE: The n-tuple passed to this routine must not be changed by any
alpar@1
  1931
--       other routines called from the formal routine func until this
alpar@1
  1932
--       routine has returned. */
alpar@1
  1933
alpar@1
  1934
struct eval_domain_info
alpar@1
  1935
{     /* working info used by the routine eval_within_domain */
alpar@1
  1936
      DOMAIN *domain;
alpar@1
  1937
      /* domain, which has to be entered */
alpar@1
  1938
      DOMAIN_BLOCK *block;
alpar@1
  1939
      /* domain block, which is currently processed */
alpar@1
  1940
      TUPLE *tuple;
alpar@1
  1941
      /* tail of original n-tuple, whose components have to be assigned
alpar@1
  1942
         to free dummy indices in the current domain block */
alpar@1
  1943
      void *info;
alpar@1
  1944
      /* transit pointer passed to the formal routine func */
alpar@1
  1945
      void (*func)(MPL *mpl, void *info);
alpar@1
  1946
      /* routine, which has to be executed in the domain scope */
alpar@1
  1947
      int failure;
alpar@1
  1948
      /* this flag indicates that given n-tuple is not a member of the
alpar@1
  1949
         domain set */
alpar@1
  1950
};
alpar@1
  1951
alpar@1
  1952
static void eval_domain_func(MPL *mpl, void *_my_info)
alpar@1
  1953
{     /* this routine recursively enters into the domain scope and then
alpar@1
  1954
         calls the routine func */
alpar@1
  1955
      struct eval_domain_info *my_info = _my_info;
alpar@1
  1956
      if (my_info->block != NULL)
alpar@1
  1957
      {  /* the current domain block to be entered exists */
alpar@1
  1958
         DOMAIN_BLOCK *block;
alpar@1
  1959
         DOMAIN_SLOT *slot;
alpar@1
  1960
         TUPLE *tuple = NULL, *temp = NULL;
alpar@1
  1961
         /* save pointer to the current domain block */
alpar@1
  1962
         block = my_info->block;
alpar@1
  1963
         /* and get ready to enter the next block (if it exists) */
alpar@1
  1964
         my_info->block = block->next;
alpar@1
  1965
         /* construct temporary n-tuple, whose components correspond to
alpar@1
  1966
            dummy indices (slots) of the current domain; components of
alpar@1
  1967
            the temporary n-tuple that correspond to free dummy indices
alpar@1
  1968
            are assigned references (not values!) to symbols specified
alpar@1
  1969
            in the corresponding components of the given n-tuple, while
alpar@1
  1970
            other components that correspond to non-free dummy indices
alpar@1
  1971
            are assigned symbolic values computed here */
alpar@1
  1972
         for (slot = block->list; slot != NULL; slot = slot->next)
alpar@1
  1973
         {  /* create component that corresponds to the current slot */
alpar@1
  1974
            if (tuple == NULL)
alpar@1
  1975
               tuple = temp = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
alpar@1
  1976
            else
alpar@1
  1977
temp = (temp->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
alpar@1
  1978
            if (slot->code == NULL)
alpar@1
  1979
            {  /* dummy index is free; take reference to symbol, which
alpar@1
  1980
                  is specified in the corresponding component of given
alpar@1
  1981
                  n-tuple */
alpar@1
  1982
               xassert(my_info->tuple != NULL);
alpar@1
  1983
               temp->sym = my_info->tuple->sym;
alpar@1
  1984
               xassert(temp->sym != NULL);
alpar@1
  1985
               my_info->tuple = my_info->tuple->next;
alpar@1
  1986
            }
alpar@1
  1987
            else
alpar@1
  1988
            {  /* dummy index is non-free; compute symbolic value to be
alpar@1
  1989
                  temporarily assigned to the dummy index */
alpar@1
  1990
               temp->sym = eval_symbolic(mpl, slot->code);
alpar@1
  1991
            }
alpar@1
  1992
         }
alpar@1
  1993
         temp->next = NULL;
alpar@1
  1994
         /* enter the current domain block */
alpar@1
  1995
         if (enter_domain_block(mpl, block, tuple, my_info,
alpar@1
  1996
               eval_domain_func)) my_info->failure = 1;
alpar@1
  1997
         /* delete temporary n-tuple as well as symbols that correspond
alpar@1
  1998
            to non-free dummy indices (they were computed here) */
alpar@1
  1999
         for (slot = block->list; slot != NULL; slot = slot->next)
alpar@1
  2000
         {  xassert(tuple != NULL);
alpar@1
  2001
            temp = tuple;
alpar@1
  2002
            tuple = tuple->next;
alpar@1
  2003
            if (slot->code != NULL)
alpar@1
  2004
            {  /* dummy index is non-free; delete symbolic value */
alpar@1
  2005
               delete_symbol(mpl, temp->sym);
alpar@1
  2006
            }
alpar@1
  2007
            /* delete component that corresponds to the current slot */
alpar@1
  2008
            dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
alpar@1
  2009
         }
alpar@1
  2010
      }
alpar@1
  2011
      else
alpar@1
  2012
      {  /* there are no more domain blocks, i.e. we have reached the
alpar@1
  2013
            domain scope */
alpar@1
  2014
         xassert(my_info->tuple == NULL);
alpar@1
  2015
         /* check optional predicate specified for the domain */
alpar@1
  2016
         if (my_info->domain->code != NULL && !eval_logical(mpl,
alpar@1
  2017
            my_info->domain->code))
alpar@1
  2018
         {  /* the predicate is false */
alpar@1
  2019
            my_info->failure = 2;
alpar@1
  2020
         }
alpar@1
  2021
         else
alpar@1
  2022
         {  /* the predicate is true; do the job */
alpar@1
  2023
            my_info->func(mpl, my_info->info);
alpar@1
  2024
         }
alpar@1
  2025
      }
alpar@1
  2026
      return;
alpar@1
  2027
}
alpar@1
  2028
alpar@1
  2029
int eval_within_domain
alpar@1
  2030
(     MPL *mpl,
alpar@1
  2031
      DOMAIN *domain,         /* not changed */
alpar@1
  2032
      TUPLE *tuple,           /* not changed */
alpar@1
  2033
      void *info, void (*func)(MPL *mpl, void *info)
alpar@1
  2034
)
alpar@1
  2035
{     /* this routine performs evaluation within domain scope */
alpar@1
  2036
      struct eval_domain_info _my_info, *my_info = &_my_info;
alpar@1
  2037
      if (domain == NULL)
alpar@1
  2038
      {  xassert(tuple == NULL);
alpar@1
  2039
         func(mpl, info);
alpar@1
  2040
         my_info->failure = 0;
alpar@1
  2041
      }
alpar@1
  2042
      else
alpar@1
  2043
      {  xassert(tuple != NULL);
alpar@1
  2044
         my_info->domain = domain;
alpar@1
  2045
         my_info->block = domain->list;
alpar@1
  2046
         my_info->tuple = tuple;
alpar@1
  2047
         my_info->info = info;
alpar@1
  2048
         my_info->func = func;
alpar@1
  2049
         my_info->failure = 0;
alpar@1
  2050
         /* enter the very first domain block */
alpar@1
  2051
         eval_domain_func(mpl, my_info);
alpar@1
  2052
      }
alpar@1
  2053
      return my_info->failure;
alpar@1
  2054
}
alpar@1
  2055
alpar@1
  2056
/*----------------------------------------------------------------------
alpar@1
  2057
-- loop_within_domain - perform iterations within domain scope.
alpar@1
  2058
--
alpar@1
  2059
-- This routine iteratively assigns new values (symbols) to the dummy
alpar@1
  2060
-- indices of specified domain by enumerating all n-tuples, which are
alpar@1
  2061
-- members of the domain set, and for every n-tuple it calls the formal
alpar@1
  2062
-- routine func to evaluate some code within the domain scope.
alpar@1
  2063
--
alpar@1
  2064
-- If the routine func returns non-zero, enumeration within the domain
alpar@1
  2065
-- is prematurely terminated.
alpar@1
  2066
--
alpar@1
  2067
-- For the sake of convenience it is allowed to specify domain as NULL,
alpar@1
  2068
-- in which case this routine just calls the routine func only once and
alpar@1
  2069
-- returns zero.
alpar@1
  2070
--
alpar@1
  2071
-- This routine allows recursive calls from the routine func providing
alpar@1
  2072
-- correct values of dummy indices for each instance. */
alpar@1
  2073
alpar@1
  2074
struct loop_domain_info
alpar@1
  2075
{     /* working info used by the routine loop_within_domain */
alpar@1
  2076
      DOMAIN *domain;
alpar@1
  2077
      /* domain, which has to be entered */
alpar@1
  2078
      DOMAIN_BLOCK *block;
alpar@1
  2079
      /* domain block, which is currently processed */
alpar@1
  2080
      int looping;
alpar@1
  2081
      /* clearing this flag leads to terminating enumeration */
alpar@1
  2082
      void *info;
alpar@1
  2083
      /* transit pointer passed to the formal routine func */
alpar@1
  2084
      int (*func)(MPL *mpl, void *info);
alpar@1
  2085
      /* routine, which needs to be executed in the domain scope */
alpar@1
  2086
};
alpar@1
  2087
alpar@1
  2088
static void loop_domain_func(MPL *mpl, void *_my_info)
alpar@1
  2089
{     /* this routine enumerates all n-tuples in the basic set of the
alpar@1
  2090
         current domain block, enters recursively into the domain scope
alpar@1
  2091
         for every n-tuple, and then calls the routine func */
alpar@1
  2092
      struct loop_domain_info *my_info = _my_info;
alpar@1
  2093
      if (my_info->block != NULL)
alpar@1
  2094
      {  /* the current domain block to be entered exists */
alpar@1
  2095
         DOMAIN_BLOCK *block;
alpar@1
  2096
         DOMAIN_SLOT *slot;
alpar@1
  2097
         TUPLE *bound;
alpar@1
  2098
         /* save pointer to the current domain block */
alpar@1
  2099
         block = my_info->block;
alpar@1
  2100
         /* and get ready to enter the next block (if it exists) */
alpar@1
  2101
         my_info->block = block->next;
alpar@1
  2102
         /* compute symbolic values, at which non-free dummy indices of
alpar@1
  2103
            the current domain block are bound; since that values don't
alpar@1
  2104
            depend on free dummy indices of the current block, they can
alpar@1
  2105
            be computed once out of the enumeration loop */
alpar@1
  2106
         bound = create_tuple(mpl);
alpar@1
  2107
         for (slot = block->list; slot != NULL; slot = slot->next)
alpar@1
  2108
         {  if (slot->code != NULL)
alpar@1
  2109
               bound = expand_tuple(mpl, bound, eval_symbolic(mpl,
alpar@1
  2110
                  slot->code));
alpar@1
  2111
         }
alpar@1
  2112
         /* start enumeration */
alpar@1
  2113
         xassert(block->code != NULL);
alpar@1
  2114
         if (block->code->op == O_DOTS)
alpar@1
  2115
         {  /* the basic set is "arithmetic", in which case it doesn't
alpar@1
  2116
               need to be computed explicitly */
alpar@1
  2117
            TUPLE *tuple;
alpar@1
  2118
            int n, j;
alpar@1
  2119
            double t0, tf, dt;
alpar@1
  2120
            /* compute "parameters" of the basic set */
alpar@1
  2121
            t0 = eval_numeric(mpl, block->code->arg.arg.x);
alpar@1
  2122
            tf = eval_numeric(mpl, block->code->arg.arg.y);
alpar@1
  2123
            if (block->code->arg.arg.z == NULL)
alpar@1
  2124
               dt = 1.0;
alpar@1
  2125
            else
alpar@1
  2126
               dt = eval_numeric(mpl, block->code->arg.arg.z);
alpar@1
  2127
            /* determine cardinality of the basic set */
alpar@1
  2128
            n = arelset_size(mpl, t0, tf, dt);
alpar@1
  2129
            /* create dummy 1-tuple for members of the basic set */
alpar@1
  2130
            tuple = expand_tuple(mpl, create_tuple(mpl),
alpar@1
  2131
               create_symbol_num(mpl, 0.0));
alpar@1
  2132
            /* in case of "arithmetic" set there is exactly one dummy
alpar@1
  2133
               index, which cannot be non-free */
alpar@1
  2134
            xassert(bound == NULL);
alpar@1
  2135
            /* walk through 1-tuples of the basic set */
alpar@1
  2136
            for (j = 1; j <= n && my_info->looping; j++)
alpar@1
  2137
            {  /* construct dummy 1-tuple for the current member */
alpar@1
  2138
               tuple->sym->num = arelset_member(mpl, t0, tf, dt, j);
alpar@1
  2139
               /* enter the current domain block */
alpar@1
  2140
               enter_domain_block(mpl, block, tuple, my_info,
alpar@1
  2141
                  loop_domain_func);
alpar@1
  2142
            }
alpar@1
  2143
            /* delete dummy 1-tuple */
alpar@1
  2144
            delete_tuple(mpl, tuple);
alpar@1
  2145
         }
alpar@1
  2146
         else
alpar@1
  2147
         {  /* the basic set is of general kind, in which case it needs
alpar@1
  2148
               to be explicitly computed */
alpar@1
  2149
            ELEMSET *set;
alpar@1
  2150
            MEMBER *memb;
alpar@1
  2151
            TUPLE *temp1, *temp2;
alpar@1
  2152
            /* compute the basic set */
alpar@1
  2153
            set = eval_elemset(mpl, block->code);
alpar@1
  2154
            /* walk through all n-tuples of the basic set */
alpar@1
  2155
            for (memb = set->head; memb != NULL && my_info->looping;
alpar@1
  2156
               memb = memb->next)
alpar@1
  2157
            {  /* all components of the current n-tuple that correspond
alpar@1
  2158
                  to non-free dummy indices must be feasible; otherwise
alpar@1
  2159
                  the n-tuple is not in the basic set */
alpar@1
  2160
               temp1 = memb->tuple;
alpar@1
  2161
               temp2 = bound;
alpar@1
  2162
               for (slot = block->list; slot != NULL; slot = slot->next)
alpar@1
  2163
               {  xassert(temp1 != NULL);
alpar@1
  2164
                  if (slot->code != NULL)
alpar@1
  2165
                  {  /* non-free dummy index */
alpar@1
  2166
                     xassert(temp2 != NULL);
alpar@1
  2167
                     if (compare_symbols(mpl, temp1->sym, temp2->sym)
alpar@1
  2168
                        != 0)
alpar@1
  2169
                     {  /* the n-tuple is not in the basic set */
alpar@1
  2170
                        goto skip;
alpar@1
  2171
                     }
alpar@1
  2172
                     temp2 = temp2->next;
alpar@1
  2173
                  }
alpar@1
  2174
                  temp1 = temp1->next;
alpar@1
  2175
               }
alpar@1
  2176
               xassert(temp1 == NULL);
alpar@1
  2177
               xassert(temp2 == NULL);
alpar@1
  2178
               /* enter the current domain block */
alpar@1
  2179
               enter_domain_block(mpl, block, memb->tuple, my_info,
alpar@1
  2180
                  loop_domain_func);
alpar@1
  2181
skip:          ;
alpar@1
  2182
            }
alpar@1
  2183
            /* delete the basic set */
alpar@1
  2184
            delete_elemset(mpl, set);
alpar@1
  2185
         }
alpar@1
  2186
         /* delete symbolic values binding non-free dummy indices */
alpar@1
  2187
         delete_tuple(mpl, bound);
alpar@1
  2188
         /* restore pointer to the current domain block */
alpar@1
  2189
         my_info->block = block;
alpar@1
  2190
      }
alpar@1
  2191
      else
alpar@1
  2192
      {  /* there are no more domain blocks, i.e. we have reached the
alpar@1
  2193
            domain scope */
alpar@1
  2194
         /* check optional predicate specified for the domain */
alpar@1
  2195
         if (my_info->domain->code != NULL && !eval_logical(mpl,
alpar@1
  2196
            my_info->domain->code))
alpar@1
  2197
         {  /* the predicate is false */
alpar@1
  2198
            /* nop */;
alpar@1
  2199
         }
alpar@1
  2200
         else
alpar@1
  2201
         {  /* the predicate is true; do the job */
alpar@1
  2202
            my_info->looping = !my_info->func(mpl, my_info->info);
alpar@1
  2203
         }
alpar@1
  2204
      }
alpar@1
  2205
      return;
alpar@1
  2206
}
alpar@1
  2207
alpar@1
  2208
void loop_within_domain
alpar@1
  2209
(     MPL *mpl,
alpar@1
  2210
      DOMAIN *domain,         /* not changed */
alpar@1
  2211
      void *info, int (*func)(MPL *mpl, void *info)
alpar@1
  2212
)
alpar@1
  2213
{     /* this routine performs iterations within domain scope */
alpar@1
  2214
      struct loop_domain_info _my_info, *my_info = &_my_info;
alpar@1
  2215
      if (domain == NULL)
alpar@1
  2216
         func(mpl, info);
alpar@1
  2217
      else
alpar@1
  2218
      {  my_info->domain = domain;
alpar@1
  2219
         my_info->block = domain->list;
alpar@1
  2220
         my_info->looping = 1;
alpar@1
  2221
         my_info->info = info;
alpar@1
  2222
         my_info->func = func;
alpar@1
  2223
         /* enter the very first domain block */
alpar@1
  2224
         loop_domain_func(mpl, my_info);
alpar@1
  2225
      }
alpar@1
  2226
      return;
alpar@1
  2227
}
alpar@1
  2228
alpar@1
  2229
/*----------------------------------------------------------------------
alpar@1
  2230
-- out_of_domain - raise domain exception.
alpar@1
  2231
--
alpar@1
  2232
-- This routine is called when a reference is made to a member of some
alpar@1
  2233
-- model object, but its n-tuple is out of the object domain. */
alpar@1
  2234
alpar@1
  2235
void out_of_domain
alpar@1
  2236
(     MPL *mpl,
alpar@1
  2237
      char *name,             /* not changed */
alpar@1
  2238
      TUPLE *tuple            /* not changed */
alpar@1
  2239
)
alpar@1
  2240
{     xassert(name != NULL);
alpar@1
  2241
      xassert(tuple != NULL);
alpar@1
  2242
      error(mpl, "%s%s out of domain", name, format_tuple(mpl, '[',
alpar@1
  2243
         tuple));
alpar@1
  2244
      /* no return */
alpar@1
  2245
}
alpar@1
  2246
alpar@1
  2247
/*----------------------------------------------------------------------
alpar@1
  2248
-- get_domain_tuple - obtain current n-tuple from domain.
alpar@1
  2249
--
alpar@1
  2250
-- This routine constructs n-tuple, whose components are current values
alpar@1
  2251
-- assigned to *free* dummy indices of specified domain.
alpar@1
  2252
--
alpar@1
  2253
-- For the sake of convenience it is allowed to specify domain as NULL,
alpar@1
  2254
-- in which case this routine returns 0-tuple.
alpar@1
  2255
--
alpar@1
  2256
-- NOTE: This routine must not be called out of domain scope. */
alpar@1
  2257
alpar@1
  2258
TUPLE *get_domain_tuple
alpar@1
  2259
(     MPL *mpl,
alpar@1
  2260
      DOMAIN *domain          /* not changed */
alpar@1
  2261
)
alpar@1
  2262
{     DOMAIN_BLOCK *block;
alpar@1
  2263
      DOMAIN_SLOT *slot;
alpar@1
  2264
      TUPLE *tuple;
alpar@1
  2265
      tuple = create_tuple(mpl);
alpar@1
  2266
      if (domain != NULL)
alpar@1
  2267
      {  for (block = domain->list; block != NULL; block = block->next)
alpar@1
  2268
         {  for (slot = block->list; slot != NULL; slot = slot->next)
alpar@1
  2269
            {  if (slot->code == NULL)
alpar@1
  2270
               {  xassert(slot->value != NULL);
alpar@1
  2271
                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
alpar@1
  2272
                     slot->value));
alpar@1
  2273
               }
alpar@1
  2274
            }
alpar@1
  2275
         }
alpar@1
  2276
      }
alpar@1
  2277
      return tuple;
alpar@1
  2278
}
alpar@1
  2279
alpar@1
  2280
/*----------------------------------------------------------------------
alpar@1
  2281
-- clean_domain - clean domain.
alpar@1
  2282
--
alpar@1
  2283
-- This routine cleans specified domain that assumes deleting all stuff
alpar@1
  2284
-- dynamically allocated during the generation phase. */
alpar@1
  2285
alpar@1
  2286
void clean_domain(MPL *mpl, DOMAIN *domain)
alpar@1
  2287
{     DOMAIN_BLOCK *block;
alpar@1
  2288
      DOMAIN_SLOT *slot;
alpar@1
  2289
      /* if no domain is specified, do nothing */
alpar@1
  2290
      if (domain == NULL) goto done;
alpar@1
  2291
      /* clean all domain blocks */
alpar@1
  2292
      for (block = domain->list; block != NULL; block = block->next)
alpar@1
  2293
      {  /* clean all domain slots */
alpar@1
  2294
         for (slot = block->list; slot != NULL; slot = slot->next)
alpar@1
  2295
         {  /* clean pseudo-code for computing bound value */
alpar@1
  2296
            clean_code(mpl, slot->code);
alpar@1
  2297
            /* delete symbolic value assigned to dummy index */
alpar@1
  2298
            if (slot->value != NULL)
alpar@1
  2299
               delete_symbol(mpl, slot->value), slot->value = NULL;
alpar@1
  2300
         }
alpar@1
  2301
         /* clean pseudo-code for computing basic set */
alpar@1
  2302
         clean_code(mpl, block->code);
alpar@1
  2303
      }
alpar@1
  2304
      /* clean pseudo-code for computing domain predicate */
alpar@1
  2305
      clean_code(mpl, domain->code);
alpar@1
  2306
done: return;
alpar@1
  2307
}
alpar@1
  2308
alpar@1
  2309
/**********************************************************************/
alpar@1
  2310
/* * *                         MODEL SETS                         * * */
alpar@1
  2311
/**********************************************************************/
alpar@1
  2312
alpar@1
  2313
/*----------------------------------------------------------------------
alpar@1
  2314
-- check_elem_set - check elemental set assigned to set member.
alpar@1
  2315
--
alpar@1
  2316
-- This routine checks if given elemental set being assigned to member
alpar@1
  2317
-- of specified model set satisfies to all restrictions.
alpar@1
  2318
--
alpar@1
  2319
-- NOTE: This routine must not be called out of domain scope. */
alpar@1
  2320
alpar@1
  2321
void check_elem_set
alpar@1
  2322
(     MPL *mpl,
alpar@1
  2323
      SET *set,               /* not changed */
alpar@1
  2324
      TUPLE *tuple,           /* not changed */
alpar@1
  2325
      ELEMSET *refer          /* not changed */
alpar@1
  2326
)
alpar@1
  2327
{     WITHIN *within;
alpar@1
  2328
      MEMBER *memb;
alpar@1
  2329
      int eqno;
alpar@1
  2330
      /* elemental set must be within all specified supersets */
alpar@1
  2331
      for (within = set->within, eqno = 1; within != NULL; within =
alpar@1
  2332
         within->next, eqno++)
alpar@1
  2333
      {  xassert(within->code != NULL);
alpar@1
  2334
         for (memb = refer->head; memb != NULL; memb = memb->next)
alpar@1
  2335
         {  if (!is_member(mpl, within->code, memb->tuple))
alpar@1
  2336
            {  char buf[255+1];
alpar@1
  2337
               strcpy(buf, format_tuple(mpl, '(', memb->tuple));
alpar@1
  2338
               xassert(strlen(buf) < sizeof(buf));
alpar@1
  2339
               error(mpl, "%s%s contains %s which not within specified "
alpar@1
  2340
                  "set; see (%d)", set->name, format_tuple(mpl, '[',
alpar@1
  2341
                     tuple), buf, eqno);
alpar@1
  2342
            }
alpar@1
  2343
         }
alpar@1
  2344
      }
alpar@1
  2345
      return;
alpar@1
  2346
}
alpar@1
  2347
alpar@1
  2348
/*----------------------------------------------------------------------
alpar@1
  2349
-- take_member_set - obtain elemental set assigned to set member.
alpar@1
  2350
--
alpar@1
  2351
-- This routine obtains a reference to elemental set assigned to given
alpar@1
  2352
-- member of specified model set and returns it on exit.
alpar@1
  2353
--
alpar@1
  2354
-- NOTE: This routine must not be called out of domain scope. */
alpar@1
  2355
alpar@1
  2356
ELEMSET *take_member_set      /* returns reference, not value */
alpar@1
  2357
(     MPL *mpl,
alpar@1
  2358
      SET *set,               /* not changed */
alpar@1
  2359
      TUPLE *tuple            /* not changed */
alpar@1
  2360
)
alpar@1
  2361
{     MEMBER *memb;
alpar@1
  2362
      ELEMSET *refer;
alpar@1
  2363
      /* find member in the set array */
alpar@1
  2364
      memb = find_member(mpl, set->array, tuple);
alpar@1
  2365
      if (memb != NULL)
alpar@1
  2366
      {  /* member exists, so just take the reference */
alpar@1
  2367
         refer = memb->value.set;
alpar@1
  2368
      }
alpar@1
  2369
      else if (set->assign != NULL)
alpar@1
  2370
      {  /* compute value using assignment expression */
alpar@1
  2371
         refer = eval_elemset(mpl, set->assign);
alpar@1
  2372
add:     /* check that the elemental set satisfies to all restrictions,
alpar@1
  2373
            assign it to new member, and add the member to the array */
alpar@1
  2374
         check_elem_set(mpl, set, tuple, refer);
alpar@1
  2375
         memb = add_member(mpl, set->array, copy_tuple(mpl, tuple));
alpar@1
  2376
         memb->value.set = refer;
alpar@1
  2377
      }
alpar@1
  2378
      else if (set->option != NULL)
alpar@1
  2379
      {  /* compute default elemental set */
alpar@1
  2380
         refer = eval_elemset(mpl, set->option);
alpar@1
  2381
         goto add;
alpar@1
  2382
      }
alpar@1
  2383
      else
alpar@1
  2384
      {  /* no value (elemental set) is provided */
alpar@1
  2385
         error(mpl, "no value for %s%s", set->name, format_tuple(mpl,
alpar@1
  2386
            '[', tuple));
alpar@1
  2387
      }
alpar@1
  2388
      return refer;
alpar@1
  2389
}
alpar@1
  2390
alpar@1
  2391
/*----------------------------------------------------------------------
alpar@1
  2392
-- eval_member_set - evaluate elemental set assigned to set member.
alpar@1
  2393
--
alpar@1
  2394
-- This routine evaluates a reference to elemental set assigned to given
alpar@1
  2395
-- member of specified model set and returns it on exit. */
alpar@1
  2396
alpar@1
  2397
struct eval_set_info
alpar@1
  2398
{     /* working info used by the routine eval_member_set */
alpar@1
  2399
      SET *set;
alpar@1
  2400
      /* model set */
alpar@1
  2401
      TUPLE *tuple;
alpar@1
  2402
      /* n-tuple, which defines set member */
alpar@1
  2403
      MEMBER *memb;
alpar@1
  2404
      /* normally this pointer is NULL; the routine uses this pointer
alpar@1
  2405
         to check data provided in the data section, in which case it
alpar@1
  2406
         points to a member currently checked; this check is performed
alpar@1
  2407
         automatically only once when a reference to any member occurs
alpar@1
  2408
         for the first time */
alpar@1
  2409
      ELEMSET *refer;
alpar@1
  2410
      /* evaluated reference to elemental set */
alpar@1
  2411
};
alpar@1
  2412
alpar@1
  2413
static void eval_set_func(MPL *mpl, void *_info)
alpar@1
  2414
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  2415
      struct eval_set_info *info = _info;
alpar@1
  2416
      if (info->memb != NULL)
alpar@1
  2417
      {  /* checking call; check elemental set being assigned */
alpar@1
  2418
         check_elem_set(mpl, info->set, info->memb->tuple,
alpar@1
  2419
            info->memb->value.set);
alpar@1
  2420
      }
alpar@1
  2421
      else
alpar@1
  2422
      {  /* normal call; evaluate member, which has given n-tuple */
alpar@1
  2423
         info->refer = take_member_set(mpl, info->set, info->tuple);
alpar@1
  2424
      }
alpar@1
  2425
      return;
alpar@1
  2426
}
alpar@1
  2427
alpar@1
  2428
#if 1 /* 12/XII-2008 */
alpar@1
  2429
static void saturate_set(MPL *mpl, SET *set)
alpar@1
  2430
{     GADGET *gadget = set->gadget;
alpar@1
  2431
      ELEMSET *data;
alpar@1
  2432
      MEMBER *elem, *memb;
alpar@1
  2433
      TUPLE *tuple, *work[20];
alpar@1
  2434
      int i;
alpar@1
  2435
      xprintf("Generating %s...\n", set->name);
alpar@1
  2436
      eval_whole_set(mpl, gadget->set);
alpar@1
  2437
      /* gadget set must have exactly one member */
alpar@1
  2438
      xassert(gadget->set->array != NULL);
alpar@1
  2439
      xassert(gadget->set->array->head != NULL);
alpar@1
  2440
      xassert(gadget->set->array->head == gadget->set->array->tail);
alpar@1
  2441
      data = gadget->set->array->head->value.set;
alpar@1
  2442
      xassert(data->type == A_NONE);
alpar@1
  2443
      xassert(data->dim == gadget->set->dimen);
alpar@1
  2444
      /* walk thru all elements of the plain set */
alpar@1
  2445
      for (elem = data->head; elem != NULL; elem = elem->next)
alpar@1
  2446
      {  /* create a copy of n-tuple */
alpar@1
  2447
         tuple = copy_tuple(mpl, elem->tuple);
alpar@1
  2448
         /* rearrange component of the n-tuple */
alpar@1
  2449
         for (i = 0; i < gadget->set->dimen; i++)
alpar@1
  2450
            work[i] = NULL;
alpar@1
  2451
         for (i = 0; tuple != NULL; tuple = tuple->next)
alpar@1
  2452
            work[gadget->ind[i++]-1] = tuple;
alpar@1
  2453
         xassert(i == gadget->set->dimen);
alpar@1
  2454
         for (i = 0; i < gadget->set->dimen; i++)
alpar@1
  2455
         {  xassert(work[i] != NULL);
alpar@1
  2456
            work[i]->next = work[i+1];
alpar@1
  2457
         }
alpar@1
  2458
         /* construct subscript list from first set->dim components */
alpar@1
  2459
         if (set->dim == 0)
alpar@1
  2460
            tuple = NULL;
alpar@1
  2461
         else
alpar@1
  2462
            tuple = work[0], work[set->dim-1]->next = NULL;
alpar@1
  2463
         /* find corresponding member of the set to be initialized */
alpar@1
  2464
         memb = find_member(mpl, set->array, tuple);
alpar@1
  2465
         if (memb == NULL)
alpar@1
  2466
         {  /* not found; add new member to the set and assign it empty
alpar@1
  2467
               elemental set */
alpar@1
  2468
            memb = add_member(mpl, set->array, tuple);
alpar@1
  2469
            memb->value.set = create_elemset(mpl, set->dimen);
alpar@1
  2470
         }
alpar@1
  2471
         else
alpar@1
  2472
         {  /* found; free subscript list */
alpar@1
  2473
            delete_tuple(mpl, tuple);
alpar@1
  2474
         }
alpar@1
  2475
         /* construct new n-tuple from rest set->dimen components */
alpar@1
  2476
         tuple = work[set->dim];
alpar@1
  2477
         xassert(set->dim + set->dimen == gadget->set->dimen);
alpar@1
  2478
         work[gadget->set->dimen-1]->next = NULL;
alpar@1
  2479
         /* and add it to the elemental set assigned to the member
alpar@1
  2480
            (no check for duplicates is needed) */
alpar@1
  2481
         add_tuple(mpl, memb->value.set, tuple);
alpar@1
  2482
      }
alpar@1
  2483
      /* the set has been saturated with data */
alpar@1
  2484
      set->data = 1;
alpar@1
  2485
      return;
alpar@1
  2486
}
alpar@1
  2487
#endif
alpar@1
  2488
alpar@1
  2489
ELEMSET *eval_member_set      /* returns reference, not value */
alpar@1
  2490
(     MPL *mpl,
alpar@1
  2491
      SET *set,               /* not changed */
alpar@1
  2492
      TUPLE *tuple            /* not changed */
alpar@1
  2493
)
alpar@1
  2494
{     /* this routine evaluates set member */
alpar@1
  2495
      struct eval_set_info _info, *info = &_info;
alpar@1
  2496
      xassert(set->dim == tuple_dimen(mpl, tuple));
alpar@1
  2497
      info->set = set;
alpar@1
  2498
      info->tuple = tuple;
alpar@1
  2499
#if 1 /* 12/XII-2008 */
alpar@1
  2500
      if (set->gadget != NULL && set->data == 0)
alpar@1
  2501
      {  /* initialize the set with data from a plain set */
alpar@1
  2502
         saturate_set(mpl, set);
alpar@1
  2503
      }
alpar@1
  2504
#endif
alpar@1
  2505
      if (set->data == 1)
alpar@1
  2506
      {  /* check data, which are provided in the data section, but not
alpar@1
  2507
            checked yet */
alpar@1
  2508
         /* save pointer to the last array member; note that during the
alpar@1
  2509
            check new members may be added beyond the last member due to
alpar@1
  2510
            references to the same parameter from default expression as
alpar@1
  2511
            well as from expressions that define restricting supersets;
alpar@1
  2512
            however, values assigned to the new members will be checked
alpar@1
  2513
            by other routine, so we don't need to check them here */
alpar@1
  2514
         MEMBER *tail = set->array->tail;
alpar@1
  2515
         /* change the data status to prevent infinite recursive loop
alpar@1
  2516
            due to references to the same set during the check */
alpar@1
  2517
         set->data = 2;
alpar@1
  2518
         /* check elemental sets assigned to array members in the data
alpar@1
  2519
            section until the marked member has been reached */
alpar@1
  2520
         for (info->memb = set->array->head; info->memb != NULL;
alpar@1
  2521
            info->memb = info->memb->next)
alpar@1
  2522
         {  if (eval_within_domain(mpl, set->domain, info->memb->tuple,
alpar@1
  2523
               info, eval_set_func))
alpar@1
  2524
               out_of_domain(mpl, set->name, info->memb->tuple);
alpar@1
  2525
            if (info->memb == tail) break;
alpar@1
  2526
         }
alpar@1
  2527
         /* the check has been finished */
alpar@1
  2528
      }
alpar@1
  2529
      /* evaluate member, which has given n-tuple */
alpar@1
  2530
      info->memb = NULL;
alpar@1
  2531
      if (eval_within_domain(mpl, info->set->domain, info->tuple, info,
alpar@1
  2532
         eval_set_func))
alpar@1
  2533
      out_of_domain(mpl, set->name, info->tuple);
alpar@1
  2534
      /* bring evaluated reference to the calling program */
alpar@1
  2535
      return info->refer;
alpar@1
  2536
}
alpar@1
  2537
alpar@1
  2538
/*----------------------------------------------------------------------
alpar@1
  2539
-- eval_whole_set - evaluate model set over entire domain.
alpar@1
  2540
--
alpar@1
  2541
-- This routine evaluates all members of specified model set over entire
alpar@1
  2542
-- domain. */
alpar@1
  2543
alpar@1
  2544
static int whole_set_func(MPL *mpl, void *info)
alpar@1
  2545
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  2546
      SET *set = (SET *)info;
alpar@1
  2547
      TUPLE *tuple = get_domain_tuple(mpl, set->domain);
alpar@1
  2548
      eval_member_set(mpl, set, tuple);
alpar@1
  2549
      delete_tuple(mpl, tuple);
alpar@1
  2550
      return 0;
alpar@1
  2551
}
alpar@1
  2552
alpar@1
  2553
void eval_whole_set(MPL *mpl, SET *set)
alpar@1
  2554
{     loop_within_domain(mpl, set->domain, set, whole_set_func);
alpar@1
  2555
      return;
alpar@1
  2556
}
alpar@1
  2557
alpar@1
  2558
/*----------------------------------------------------------------------
alpar@1
  2559
-- clean set - clean model set.
alpar@1
  2560
--
alpar@1
  2561
-- This routine cleans specified model set that assumes deleting all
alpar@1
  2562
-- stuff dynamically allocated during the generation phase. */
alpar@1
  2563
alpar@1
  2564
void clean_set(MPL *mpl, SET *set)
alpar@1
  2565
{     WITHIN *within;
alpar@1
  2566
      MEMBER *memb;
alpar@1
  2567
      /* clean subscript domain */
alpar@1
  2568
      clean_domain(mpl, set->domain);
alpar@1
  2569
      /* clean pseudo-code for computing supersets */
alpar@1
  2570
      for (within = set->within; within != NULL; within = within->next)
alpar@1
  2571
         clean_code(mpl, within->code);
alpar@1
  2572
      /* clean pseudo-code for computing assigned value */
alpar@1
  2573
      clean_code(mpl, set->assign);
alpar@1
  2574
      /* clean pseudo-code for computing default value */
alpar@1
  2575
      clean_code(mpl, set->option);
alpar@1
  2576
      /* reset data status flag */
alpar@1
  2577
      set->data = 0;
alpar@1
  2578
      /* delete content array */
alpar@1
  2579
      for (memb = set->array->head; memb != NULL; memb = memb->next)
alpar@1
  2580
         delete_value(mpl, set->array->type, &memb->value);
alpar@1
  2581
      delete_array(mpl, set->array), set->array = NULL;
alpar@1
  2582
      return;
alpar@1
  2583
}
alpar@1
  2584
alpar@1
  2585
/**********************************************************************/
alpar@1
  2586
/* * *                      MODEL PARAMETERS                      * * */
alpar@1
  2587
/**********************************************************************/
alpar@1
  2588
alpar@1
  2589
/*----------------------------------------------------------------------
alpar@1
  2590
-- check_value_num - check numeric value assigned to parameter member.
alpar@1
  2591
--
alpar@1
  2592
-- This routine checks if numeric value being assigned to some member
alpar@1
  2593
-- of specified numeric model parameter satisfies to all restrictions.
alpar@1
  2594
--
alpar@1
  2595
-- NOTE: This routine must not be called out of domain scope. */
alpar@1
  2596
alpar@1
  2597
void check_value_num
alpar@1
  2598
(     MPL *mpl,
alpar@1
  2599
      PARAMETER *par,         /* not changed */
alpar@1
  2600
      TUPLE *tuple,           /* not changed */
alpar@1
  2601
      double value
alpar@1
  2602
)
alpar@1
  2603
{     CONDITION *cond;
alpar@1
  2604
      WITHIN *in;
alpar@1
  2605
      int eqno;
alpar@1
  2606
      /* the value must satisfy to the parameter type */
alpar@1
  2607
      switch (par->type)
alpar@1
  2608
      {  case A_NUMERIC:
alpar@1
  2609
            break;
alpar@1
  2610
         case A_INTEGER:
alpar@1
  2611
            if (value != floor(value))
alpar@1
  2612
               error(mpl, "%s%s = %.*g not integer", par->name,
alpar@1
  2613
                  format_tuple(mpl, '[', tuple), DBL_DIG, value);
alpar@1
  2614
            break;
alpar@1
  2615
         case A_BINARY:
alpar@1
  2616
            if (!(value == 0.0 || value == 1.0))
alpar@1
  2617
               error(mpl, "%s%s = %.*g not binary", par->name,
alpar@1
  2618
                  format_tuple(mpl, '[', tuple), DBL_DIG, value);
alpar@1
  2619
            break;
alpar@1
  2620
         default:
alpar@1
  2621
            xassert(par != par);
alpar@1
  2622
      }
alpar@1
  2623
      /* the value must satisfy to all specified conditions */
alpar@1
  2624
      for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
alpar@1
  2625
         eqno++)
alpar@1
  2626
      {  double bound;
alpar@1
  2627
         char *rho;
alpar@1
  2628
         xassert(cond->code != NULL);
alpar@1
  2629
         bound = eval_numeric(mpl, cond->code);
alpar@1
  2630
         switch (cond->rho)
alpar@1
  2631
         {  case O_LT:
alpar@1
  2632
               if (!(value < bound))
alpar@1
  2633
               {  rho = "<";
alpar@1
  2634
err:              error(mpl, "%s%s = %.*g not %s %.*g; see (%d)",
alpar@1
  2635
                     par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
alpar@1
  2636
                     value, rho, DBL_DIG, bound, eqno);
alpar@1
  2637
               }
alpar@1
  2638
               break;
alpar@1
  2639
            case O_LE:
alpar@1
  2640
               if (!(value <= bound)) { rho = "<="; goto err; }
alpar@1
  2641
               break;
alpar@1
  2642
            case O_EQ:
alpar@1
  2643
               if (!(value == bound)) { rho = "="; goto err; }
alpar@1
  2644
               break;
alpar@1
  2645
            case O_GE:
alpar@1
  2646
               if (!(value >= bound)) { rho = ">="; goto err; }
alpar@1
  2647
               break;
alpar@1
  2648
            case O_GT:
alpar@1
  2649
               if (!(value > bound)) { rho = ">"; goto err; }
alpar@1
  2650
               break;
alpar@1
  2651
            case O_NE:
alpar@1
  2652
               if (!(value != bound)) { rho = "<>"; goto err; }
alpar@1
  2653
               break;
alpar@1
  2654
            default:
alpar@1
  2655
               xassert(cond != cond);
alpar@1
  2656
         }
alpar@1
  2657
      }
alpar@1
  2658
      /* the value must be in all specified supersets */
alpar@1
  2659
      for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
alpar@1
  2660
      {  TUPLE *dummy;
alpar@1
  2661
         xassert(in->code != NULL);
alpar@1
  2662
         xassert(in->code->dim == 1);
alpar@1
  2663
         dummy = expand_tuple(mpl, create_tuple(mpl),
alpar@1
  2664
            create_symbol_num(mpl, value));
alpar@1
  2665
         if (!is_member(mpl, in->code, dummy))
alpar@1
  2666
            error(mpl, "%s%s = %.*g not in specified set; see (%d)",
alpar@1
  2667
               par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
alpar@1
  2668
               value, eqno);
alpar@1
  2669
         delete_tuple(mpl, dummy);
alpar@1
  2670
      }
alpar@1
  2671
      return;
alpar@1
  2672
}
alpar@1
  2673
alpar@1
  2674
/*----------------------------------------------------------------------
alpar@1
  2675
-- take_member_num - obtain num. value assigned to parameter member.
alpar@1
  2676
--
alpar@1
  2677
-- This routine obtains a numeric value assigned to member of specified
alpar@1
  2678
-- numeric model parameter and returns it on exit.
alpar@1
  2679
--
alpar@1
  2680
-- NOTE: This routine must not be called out of domain scope. */
alpar@1
  2681
alpar@1
  2682
double take_member_num
alpar@1
  2683
(     MPL *mpl,
alpar@1
  2684
      PARAMETER *par,         /* not changed */
alpar@1
  2685
      TUPLE *tuple            /* not changed */
alpar@1
  2686
)
alpar@1
  2687
{     MEMBER *memb;
alpar@1
  2688
      double value;
alpar@1
  2689
      /* find member in the parameter array */
alpar@1
  2690
      memb = find_member(mpl, par->array, tuple);
alpar@1
  2691
      if (memb != NULL)
alpar@1
  2692
      {  /* member exists, so just take its value */
alpar@1
  2693
         value = memb->value.num;
alpar@1
  2694
      }
alpar@1
  2695
      else if (par->assign != NULL)
alpar@1
  2696
      {  /* compute value using assignment expression */
alpar@1
  2697
         value = eval_numeric(mpl, par->assign);
alpar@1
  2698
add:     /* check that the value satisfies to all restrictions, assign
alpar@1
  2699
            it to new member, and add the member to the array */
alpar@1
  2700
         check_value_num(mpl, par, tuple, value);
alpar@1
  2701
         memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
alpar@1
  2702
         memb->value.num = value;
alpar@1
  2703
      }
alpar@1
  2704
      else if (par->option != NULL)
alpar@1
  2705
      {  /* compute default value */
alpar@1
  2706
         value = eval_numeric(mpl, par->option);
alpar@1
  2707
         goto add;
alpar@1
  2708
      }
alpar@1
  2709
      else if (par->defval != NULL)
alpar@1
  2710
      {  /* take default value provided in the data section */
alpar@1
  2711
         if (par->defval->str != NULL)
alpar@1
  2712
            error(mpl, "cannot convert %s to floating-point number",
alpar@1
  2713
               format_symbol(mpl, par->defval));
alpar@1
  2714
         value = par->defval->num;
alpar@1
  2715
         goto add;
alpar@1
  2716
      }
alpar@1
  2717
      else
alpar@1
  2718
      {  /* no value is provided */
alpar@1
  2719
         error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
alpar@1
  2720
            '[', tuple));
alpar@1
  2721
      }
alpar@1
  2722
      return value;
alpar@1
  2723
}
alpar@1
  2724
alpar@1
  2725
/*----------------------------------------------------------------------
alpar@1
  2726
-- eval_member_num - evaluate num. value assigned to parameter member.
alpar@1
  2727
--
alpar@1
  2728
-- This routine evaluates a numeric value assigned to given member of
alpar@1
  2729
-- specified numeric model parameter and returns it on exit. */
alpar@1
  2730
alpar@1
  2731
struct eval_num_info
alpar@1
  2732
{     /* working info used by the routine eval_member_num */
alpar@1
  2733
      PARAMETER *par;
alpar@1
  2734
      /* model parameter  */
alpar@1
  2735
      TUPLE *tuple;
alpar@1
  2736
      /* n-tuple, which defines parameter member */
alpar@1
  2737
      MEMBER *memb;
alpar@1
  2738
      /* normally this pointer is NULL; the routine uses this pointer
alpar@1
  2739
         to check data provided in the data section, in which case it
alpar@1
  2740
         points to a member currently checked; this check is performed
alpar@1
  2741
         automatically only once when a reference to any member occurs
alpar@1
  2742
         for the first time */
alpar@1
  2743
      double value;
alpar@1
  2744
      /* evaluated numeric value */
alpar@1
  2745
};
alpar@1
  2746
alpar@1
  2747
static void eval_num_func(MPL *mpl, void *_info)
alpar@1
  2748
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  2749
      struct eval_num_info *info = _info;
alpar@1
  2750
      if (info->memb != NULL)
alpar@1
  2751
      {  /* checking call; check numeric value being assigned */
alpar@1
  2752
         check_value_num(mpl, info->par, info->memb->tuple,
alpar@1
  2753
            info->memb->value.num);
alpar@1
  2754
      }
alpar@1
  2755
      else
alpar@1
  2756
      {  /* normal call; evaluate member, which has given n-tuple */
alpar@1
  2757
         info->value = take_member_num(mpl, info->par, info->tuple);
alpar@1
  2758
      }
alpar@1
  2759
      return;
alpar@1
  2760
}
alpar@1
  2761
alpar@1
  2762
double eval_member_num
alpar@1
  2763
(     MPL *mpl,
alpar@1
  2764
      PARAMETER *par,         /* not changed */
alpar@1
  2765
      TUPLE *tuple            /* not changed */
alpar@1
  2766
)
alpar@1
  2767
{     /* this routine evaluates numeric parameter member */
alpar@1
  2768
      struct eval_num_info _info, *info = &_info;
alpar@1
  2769
      xassert(par->type == A_NUMERIC || par->type == A_INTEGER ||
alpar@1
  2770
             par->type == A_BINARY);
alpar@1
  2771
      xassert(par->dim == tuple_dimen(mpl, tuple));
alpar@1
  2772
      info->par = par;
alpar@1
  2773
      info->tuple = tuple;
alpar@1
  2774
      if (par->data == 1)
alpar@1
  2775
      {  /* check data, which are provided in the data section, but not
alpar@1
  2776
            checked yet */
alpar@1
  2777
         /* save pointer to the last array member; note that during the
alpar@1
  2778
            check new members may be added beyond the last member due to
alpar@1
  2779
            references to the same parameter from default expression as
alpar@1
  2780
            well as from expressions that define restricting conditions;
alpar@1
  2781
            however, values assigned to the new members will be checked
alpar@1
  2782
            by other routine, so we don't need to check them here */
alpar@1
  2783
         MEMBER *tail = par->array->tail;
alpar@1
  2784
         /* change the data status to prevent infinite recursive loop
alpar@1
  2785
            due to references to the same parameter during the check */
alpar@1
  2786
         par->data = 2;
alpar@1
  2787
         /* check values assigned to array members in the data section
alpar@1
  2788
            until the marked member has been reached */
alpar@1
  2789
         for (info->memb = par->array->head; info->memb != NULL;
alpar@1
  2790
            info->memb = info->memb->next)
alpar@1
  2791
         {  if (eval_within_domain(mpl, par->domain, info->memb->tuple,
alpar@1
  2792
               info, eval_num_func))
alpar@1
  2793
               out_of_domain(mpl, par->name, info->memb->tuple);
alpar@1
  2794
            if (info->memb == tail) break;
alpar@1
  2795
         }
alpar@1
  2796
         /* the check has been finished */
alpar@1
  2797
      }
alpar@1
  2798
      /* evaluate member, which has given n-tuple */
alpar@1
  2799
      info->memb = NULL;
alpar@1
  2800
      if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
alpar@1
  2801
         eval_num_func))
alpar@1
  2802
         out_of_domain(mpl, par->name, info->tuple);
alpar@1
  2803
      /* bring evaluated value to the calling program */
alpar@1
  2804
      return info->value;
alpar@1
  2805
}
alpar@1
  2806
alpar@1
  2807
/*----------------------------------------------------------------------
alpar@1
  2808
-- check_value_sym - check symbolic value assigned to parameter member.
alpar@1
  2809
--
alpar@1
  2810
-- This routine checks if symbolic value being assigned to some member
alpar@1
  2811
-- of specified symbolic model parameter satisfies to all restrictions.
alpar@1
  2812
--
alpar@1
  2813
-- NOTE: This routine must not be called out of domain scope. */
alpar@1
  2814
alpar@1
  2815
void check_value_sym
alpar@1
  2816
(     MPL *mpl,
alpar@1
  2817
      PARAMETER *par,         /* not changed */
alpar@1
  2818
      TUPLE *tuple,           /* not changed */
alpar@1
  2819
      SYMBOL *value           /* not changed */
alpar@1
  2820
)
alpar@1
  2821
{     CONDITION *cond;
alpar@1
  2822
      WITHIN *in;
alpar@1
  2823
      int eqno;
alpar@1
  2824
      /* the value must satisfy to all specified conditions */
alpar@1
  2825
      for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
alpar@1
  2826
         eqno++)
alpar@1
  2827
      {  SYMBOL *bound;
alpar@1
  2828
         char buf[255+1];
alpar@1
  2829
         xassert(cond->code != NULL);
alpar@1
  2830
         bound = eval_symbolic(mpl, cond->code);
alpar@1
  2831
         switch (cond->rho)
alpar@1
  2832
         {
alpar@1
  2833
#if 1 /* 13/VIII-2008 */
alpar@1
  2834
            case O_LT:
alpar@1
  2835
               if (!(compare_symbols(mpl, value, bound) < 0))
alpar@1
  2836
               {  strcpy(buf, format_symbol(mpl, bound));
alpar@1
  2837
                  xassert(strlen(buf) < sizeof(buf));
alpar@1
  2838
                  error(mpl, "%s%s = %s not < %s",
alpar@1
  2839
                     par->name, format_tuple(mpl, '[', tuple),
alpar@1
  2840
                     format_symbol(mpl, value), buf, eqno);
alpar@1
  2841
               }
alpar@1
  2842
               break;
alpar@1
  2843
            case O_LE:
alpar@1
  2844
               if (!(compare_symbols(mpl, value, bound) <= 0))
alpar@1
  2845
               {  strcpy(buf, format_symbol(mpl, bound));
alpar@1
  2846
                  xassert(strlen(buf) < sizeof(buf));
alpar@1
  2847
                  error(mpl, "%s%s = %s not <= %s",
alpar@1
  2848
                     par->name, format_tuple(mpl, '[', tuple),
alpar@1
  2849
                     format_symbol(mpl, value), buf, eqno);
alpar@1
  2850
               }
alpar@1
  2851
               break;
alpar@1
  2852
#endif
alpar@1
  2853
            case O_EQ:
alpar@1
  2854
               if (!(compare_symbols(mpl, value, bound) == 0))
alpar@1
  2855
               {  strcpy(buf, format_symbol(mpl, bound));
alpar@1
  2856
                  xassert(strlen(buf) < sizeof(buf));
alpar@1
  2857
                  error(mpl, "%s%s = %s not = %s",
alpar@1
  2858
                     par->name, format_tuple(mpl, '[', tuple),
alpar@1
  2859
                     format_symbol(mpl, value), buf, eqno);
alpar@1
  2860
               }
alpar@1
  2861
               break;
alpar@1
  2862
#if 1 /* 13/VIII-2008 */
alpar@1
  2863
            case O_GE:
alpar@1
  2864
               if (!(compare_symbols(mpl, value, bound) >= 0))
alpar@1
  2865
               {  strcpy(buf, format_symbol(mpl, bound));
alpar@1
  2866
                  xassert(strlen(buf) < sizeof(buf));
alpar@1
  2867
                  error(mpl, "%s%s = %s not >= %s",
alpar@1
  2868
                     par->name, format_tuple(mpl, '[', tuple),
alpar@1
  2869
                     format_symbol(mpl, value), buf, eqno);
alpar@1
  2870
               }
alpar@1
  2871
               break;
alpar@1
  2872
            case O_GT:
alpar@1
  2873
               if (!(compare_symbols(mpl, value, bound) > 0))
alpar@1
  2874
               {  strcpy(buf, format_symbol(mpl, bound));
alpar@1
  2875
                  xassert(strlen(buf) < sizeof(buf));
alpar@1
  2876
                  error(mpl, "%s%s = %s not > %s",
alpar@1
  2877
                     par->name, format_tuple(mpl, '[', tuple),
alpar@1
  2878
                     format_symbol(mpl, value), buf, eqno);
alpar@1
  2879
               }
alpar@1
  2880
               break;
alpar@1
  2881
#endif
alpar@1
  2882
            case O_NE:
alpar@1
  2883
               if (!(compare_symbols(mpl, value, bound) != 0))
alpar@1
  2884
               {  strcpy(buf, format_symbol(mpl, bound));
alpar@1
  2885
                  xassert(strlen(buf) < sizeof(buf));
alpar@1
  2886
                  error(mpl, "%s%s = %s not <> %s",
alpar@1
  2887
                     par->name, format_tuple(mpl, '[', tuple),
alpar@1
  2888
                     format_symbol(mpl, value), buf, eqno);
alpar@1
  2889
               }
alpar@1
  2890
               break;
alpar@1
  2891
            default:
alpar@1
  2892
               xassert(cond != cond);
alpar@1
  2893
         }
alpar@1
  2894
         delete_symbol(mpl, bound);
alpar@1
  2895
      }
alpar@1
  2896
      /* the value must be in all specified supersets */
alpar@1
  2897
      for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
alpar@1
  2898
      {  TUPLE *dummy;
alpar@1
  2899
         xassert(in->code != NULL);
alpar@1
  2900
         xassert(in->code->dim == 1);
alpar@1
  2901
         dummy = expand_tuple(mpl, create_tuple(mpl), copy_symbol(mpl,
alpar@1
  2902
            value));
alpar@1
  2903
         if (!is_member(mpl, in->code, dummy))
alpar@1
  2904
            error(mpl, "%s%s = %s not in specified set; see (%d)",
alpar@1
  2905
               par->name, format_tuple(mpl, '[', tuple),
alpar@1
  2906
               format_symbol(mpl, value), eqno);
alpar@1
  2907
         delete_tuple(mpl, dummy);
alpar@1
  2908
      }
alpar@1
  2909
      return;
alpar@1
  2910
}
alpar@1
  2911
alpar@1
  2912
/*----------------------------------------------------------------------
alpar@1
  2913
-- take_member_sym - obtain symb. value assigned to parameter member.
alpar@1
  2914
--
alpar@1
  2915
-- This routine obtains a symbolic value assigned to member of specified
alpar@1
  2916
-- symbolic model parameter and returns it on exit.
alpar@1
  2917
--
alpar@1
  2918
-- NOTE: This routine must not be called out of domain scope. */
alpar@1
  2919
alpar@1
  2920
SYMBOL *take_member_sym       /* returns value, not reference */
alpar@1
  2921
(     MPL *mpl,
alpar@1
  2922
      PARAMETER *par,         /* not changed */
alpar@1
  2923
      TUPLE *tuple            /* not changed */
alpar@1
  2924
)
alpar@1
  2925
{     MEMBER *memb;
alpar@1
  2926
      SYMBOL *value;
alpar@1
  2927
      /* find member in the parameter array */
alpar@1
  2928
      memb = find_member(mpl, par->array, tuple);
alpar@1
  2929
      if (memb != NULL)
alpar@1
  2930
      {  /* member exists, so just take its value */
alpar@1
  2931
         value = copy_symbol(mpl, memb->value.sym);
alpar@1
  2932
      }
alpar@1
  2933
      else if (par->assign != NULL)
alpar@1
  2934
      {  /* compute value using assignment expression */
alpar@1
  2935
         value = eval_symbolic(mpl, par->assign);
alpar@1
  2936
add:     /* check that the value satisfies to all restrictions, assign
alpar@1
  2937
            it to new member, and add the member to the array */
alpar@1
  2938
         check_value_sym(mpl, par, tuple, value);
alpar@1
  2939
         memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
alpar@1
  2940
         memb->value.sym = copy_symbol(mpl, value);
alpar@1
  2941
      }
alpar@1
  2942
      else if (par->option != NULL)
alpar@1
  2943
      {  /* compute default value */
alpar@1
  2944
         value = eval_symbolic(mpl, par->option);
alpar@1
  2945
         goto add;
alpar@1
  2946
      }
alpar@1
  2947
      else if (par->defval != NULL)
alpar@1
  2948
      {  /* take default value provided in the data section */
alpar@1
  2949
         value = copy_symbol(mpl, par->defval);
alpar@1
  2950
         goto add;
alpar@1
  2951
      }
alpar@1
  2952
      else
alpar@1
  2953
      {  /* no value is provided */
alpar@1
  2954
         error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
alpar@1
  2955
            '[', tuple));
alpar@1
  2956
      }
alpar@1
  2957
      return value;
alpar@1
  2958
}
alpar@1
  2959
alpar@1
  2960
/*----------------------------------------------------------------------
alpar@1
  2961
-- eval_member_sym - evaluate symb. value assigned to parameter member.
alpar@1
  2962
--
alpar@1
  2963
-- This routine evaluates a symbolic value assigned to given member of
alpar@1
  2964
-- specified symbolic model parameter and returns it on exit. */
alpar@1
  2965
alpar@1
  2966
struct eval_sym_info
alpar@1
  2967
{     /* working info used by the routine eval_member_sym */
alpar@1
  2968
      PARAMETER *par;
alpar@1
  2969
      /* model parameter */
alpar@1
  2970
      TUPLE *tuple;
alpar@1
  2971
      /* n-tuple, which defines parameter member */
alpar@1
  2972
      MEMBER *memb;
alpar@1
  2973
      /* normally this pointer is NULL; the routine uses this pointer
alpar@1
  2974
         to check data provided in the data section, in which case it
alpar@1
  2975
         points to a member currently checked; this check is performed
alpar@1
  2976
         automatically only once when a reference to any member occurs
alpar@1
  2977
         for the first time */
alpar@1
  2978
      SYMBOL *value;
alpar@1
  2979
      /* evaluated symbolic value */
alpar@1
  2980
};
alpar@1
  2981
alpar@1
  2982
static void eval_sym_func(MPL *mpl, void *_info)
alpar@1
  2983
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  2984
      struct eval_sym_info *info = _info;
alpar@1
  2985
      if (info->memb != NULL)
alpar@1
  2986
      {  /* checking call; check symbolic value being assigned */
alpar@1
  2987
         check_value_sym(mpl, info->par, info->memb->tuple,
alpar@1
  2988
            info->memb->value.sym);
alpar@1
  2989
      }
alpar@1
  2990
      else
alpar@1
  2991
      {  /* normal call; evaluate member, which has given n-tuple */
alpar@1
  2992
         info->value = take_member_sym(mpl, info->par, info->tuple);
alpar@1
  2993
      }
alpar@1
  2994
      return;
alpar@1
  2995
}
alpar@1
  2996
alpar@1
  2997
SYMBOL *eval_member_sym       /* returns value, not reference */
alpar@1
  2998
(     MPL *mpl,
alpar@1
  2999
      PARAMETER *par,         /* not changed */
alpar@1
  3000
      TUPLE *tuple            /* not changed */
alpar@1
  3001
)
alpar@1
  3002
{     /* this routine evaluates symbolic parameter member */
alpar@1
  3003
      struct eval_sym_info _info, *info = &_info;
alpar@1
  3004
      xassert(par->type == A_SYMBOLIC);
alpar@1
  3005
      xassert(par->dim == tuple_dimen(mpl, tuple));
alpar@1
  3006
      info->par = par;
alpar@1
  3007
      info->tuple = tuple;
alpar@1
  3008
      if (par->data == 1)
alpar@1
  3009
      {  /* check data, which are provided in the data section, but not
alpar@1
  3010
            checked yet */
alpar@1
  3011
         /* save pointer to the last array member; note that during the
alpar@1
  3012
            check new members may be added beyond the last member due to
alpar@1
  3013
            references to the same parameter from default expression as
alpar@1
  3014
            well as from expressions that define restricting conditions;
alpar@1
  3015
            however, values assigned to the new members will be checked
alpar@1
  3016
            by other routine, so we don't need to check them here */
alpar@1
  3017
         MEMBER *tail = par->array->tail;
alpar@1
  3018
         /* change the data status to prevent infinite recursive loop
alpar@1
  3019
            due to references to the same parameter during the check */
alpar@1
  3020
         par->data = 2;
alpar@1
  3021
         /* check values assigned to array members in the data section
alpar@1
  3022
            until the marked member has been reached */
alpar@1
  3023
         for (info->memb = par->array->head; info->memb != NULL;
alpar@1
  3024
            info->memb = info->memb->next)
alpar@1
  3025
         {  if (eval_within_domain(mpl, par->domain, info->memb->tuple,
alpar@1
  3026
               info, eval_sym_func))
alpar@1
  3027
               out_of_domain(mpl, par->name, info->memb->tuple);
alpar@1
  3028
            if (info->memb == tail) break;
alpar@1
  3029
         }
alpar@1
  3030
         /* the check has been finished */
alpar@1
  3031
      }
alpar@1
  3032
      /* evaluate member, which has given n-tuple */
alpar@1
  3033
      info->memb = NULL;
alpar@1
  3034
      if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
alpar@1
  3035
         eval_sym_func))
alpar@1
  3036
         out_of_domain(mpl, par->name, info->tuple);
alpar@1
  3037
      /* bring evaluated value to the calling program */
alpar@1
  3038
      return info->value;
alpar@1
  3039
}
alpar@1
  3040
alpar@1
  3041
/*----------------------------------------------------------------------
alpar@1
  3042
-- eval_whole_par - evaluate model parameter over entire domain.
alpar@1
  3043
--
alpar@1
  3044
-- This routine evaluates all members of specified model parameter over
alpar@1
  3045
-- entire domain. */
alpar@1
  3046
alpar@1
  3047
static int whole_par_func(MPL *mpl, void *info)
alpar@1
  3048
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  3049
      PARAMETER *par = (PARAMETER *)info;
alpar@1
  3050
      TUPLE *tuple = get_domain_tuple(mpl, par->domain);
alpar@1
  3051
      switch (par->type)
alpar@1
  3052
      {  case A_NUMERIC:
alpar@1
  3053
         case A_INTEGER:
alpar@1
  3054
         case A_BINARY:
alpar@1
  3055
            eval_member_num(mpl, par, tuple);
alpar@1
  3056
            break;
alpar@1
  3057
         case A_SYMBOLIC:
alpar@1
  3058
            delete_symbol(mpl, eval_member_sym(mpl, par, tuple));
alpar@1
  3059
            break;
alpar@1
  3060
         default:
alpar@1
  3061
            xassert(par != par);
alpar@1
  3062
      }
alpar@1
  3063
      delete_tuple(mpl, tuple);
alpar@1
  3064
      return 0;
alpar@1
  3065
}
alpar@1
  3066
alpar@1
  3067
void eval_whole_par(MPL *mpl, PARAMETER *par)
alpar@1
  3068
{     loop_within_domain(mpl, par->domain, par, whole_par_func);
alpar@1
  3069
      return;
alpar@1
  3070
}
alpar@1
  3071
alpar@1
  3072
/*----------------------------------------------------------------------
alpar@1
  3073
-- clean_parameter - clean model parameter.
alpar@1
  3074
--
alpar@1
  3075
-- This routine cleans specified model parameter that assumes deleting
alpar@1
  3076
-- all stuff dynamically allocated during the generation phase. */
alpar@1
  3077
alpar@1
  3078
void clean_parameter(MPL *mpl, PARAMETER *par)
alpar@1
  3079
{     CONDITION *cond;
alpar@1
  3080
      WITHIN *in;
alpar@1
  3081
      MEMBER *memb;
alpar@1
  3082
      /* clean subscript domain */
alpar@1
  3083
      clean_domain(mpl, par->domain);
alpar@1
  3084
      /* clean pseudo-code for computing restricting conditions */
alpar@1
  3085
      for (cond = par->cond; cond != NULL; cond = cond->next)
alpar@1
  3086
         clean_code(mpl, cond->code);
alpar@1
  3087
      /* clean pseudo-code for computing restricting supersets */
alpar@1
  3088
      for (in = par->in; in != NULL; in = in->next)
alpar@1
  3089
         clean_code(mpl, in->code);
alpar@1
  3090
      /* clean pseudo-code for computing assigned value */
alpar@1
  3091
      clean_code(mpl, par->assign);
alpar@1
  3092
      /* clean pseudo-code for computing default value */
alpar@1
  3093
      clean_code(mpl, par->option);
alpar@1
  3094
      /* reset data status flag */
alpar@1
  3095
      par->data = 0;
alpar@1
  3096
      /* delete default symbolic value */
alpar@1
  3097
      if (par->defval != NULL)
alpar@1
  3098
         delete_symbol(mpl, par->defval), par->defval = NULL;
alpar@1
  3099
      /* delete content array */
alpar@1
  3100
      for (memb = par->array->head; memb != NULL; memb = memb->next)
alpar@1
  3101
         delete_value(mpl, par->array->type, &memb->value);
alpar@1
  3102
      delete_array(mpl, par->array), par->array = NULL;
alpar@1
  3103
      return;
alpar@1
  3104
}
alpar@1
  3105
alpar@1
  3106
/**********************************************************************/
alpar@1
  3107
/* * *                      MODEL VARIABLES                       * * */
alpar@1
  3108
/**********************************************************************/
alpar@1
  3109
alpar@1
  3110
/*----------------------------------------------------------------------
alpar@1
  3111
-- take_member_var - obtain reference to elemental variable.
alpar@1
  3112
--
alpar@1
  3113
-- This routine obtains a reference to elemental variable assigned to
alpar@1
  3114
-- given member of specified model variable and returns it on exit. If
alpar@1
  3115
-- necessary, new elemental variable is created.
alpar@1
  3116
--
alpar@1
  3117
-- NOTE: This routine must not be called out of domain scope. */
alpar@1
  3118
alpar@1
  3119
ELEMVAR *take_member_var      /* returns reference */
alpar@1
  3120
(     MPL *mpl,
alpar@1
  3121
      VARIABLE *var,          /* not changed */
alpar@1
  3122
      TUPLE *tuple            /* not changed */
alpar@1
  3123
)
alpar@1
  3124
{     MEMBER *memb;
alpar@1
  3125
      ELEMVAR *refer;
alpar@1
  3126
      /* find member in the variable array */
alpar@1
  3127
      memb = find_member(mpl, var->array, tuple);
alpar@1
  3128
      if (memb != NULL)
alpar@1
  3129
      {  /* member exists, so just take the reference */
alpar@1
  3130
         refer = memb->value.var;
alpar@1
  3131
      }
alpar@1
  3132
      else
alpar@1
  3133
      {  /* member is referenced for the first time and therefore does
alpar@1
  3134
            not exist; create new elemental variable, assign it to new
alpar@1
  3135
            member, and add the member to the variable array */
alpar@1
  3136
         memb = add_member(mpl, var->array, copy_tuple(mpl, tuple));
alpar@1
  3137
         refer = (memb->value.var =
alpar@1
  3138
            dmp_get_atom(mpl->elemvars, sizeof(ELEMVAR)));
alpar@1
  3139
         refer->j = 0;
alpar@1
  3140
         refer->var = var;
alpar@1
  3141
         refer->memb = memb;
alpar@1
  3142
         /* compute lower bound */
alpar@1
  3143
         if (var->lbnd == NULL)
alpar@1
  3144
            refer->lbnd = 0.0;
alpar@1
  3145
         else
alpar@1
  3146
            refer->lbnd = eval_numeric(mpl, var->lbnd);
alpar@1
  3147
         /* compute upper bound */
alpar@1
  3148
         if (var->ubnd == NULL)
alpar@1
  3149
            refer->ubnd = 0.0;
alpar@1
  3150
         else if (var->ubnd == var->lbnd)
alpar@1
  3151
            refer->ubnd = refer->lbnd;
alpar@1
  3152
         else
alpar@1
  3153
            refer->ubnd = eval_numeric(mpl, var->ubnd);
alpar@1
  3154
         /* nullify working quantity */
alpar@1
  3155
         refer->temp = 0.0;
alpar@1
  3156
#if 1 /* 15/V-2010 */
alpar@1
  3157
         /* solution has not been obtained by the solver yet */
alpar@1
  3158
         refer->stat = 0;
alpar@1
  3159
         refer->prim = refer->dual = 0.0;
alpar@1
  3160
#endif
alpar@1
  3161
      }
alpar@1
  3162
      return refer;
alpar@1
  3163
}
alpar@1
  3164
alpar@1
  3165
/*----------------------------------------------------------------------
alpar@1
  3166
-- eval_member_var - evaluate reference to elemental variable.
alpar@1
  3167
--
alpar@1
  3168
-- This routine evaluates a reference to elemental variable assigned to
alpar@1
  3169
-- member of specified model variable and returns it on exit. */
alpar@1
  3170
alpar@1
  3171
struct eval_var_info
alpar@1
  3172
{     /* working info used by the routine eval_member_var */
alpar@1
  3173
      VARIABLE *var;
alpar@1
  3174
      /* model variable */
alpar@1
  3175
      TUPLE *tuple;
alpar@1
  3176
      /* n-tuple, which defines variable member */
alpar@1
  3177
      ELEMVAR *refer;
alpar@1
  3178
      /* evaluated reference to elemental variable */
alpar@1
  3179
};
alpar@1
  3180
alpar@1
  3181
static void eval_var_func(MPL *mpl, void *_info)
alpar@1
  3182
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  3183
      struct eval_var_info *info = _info;
alpar@1
  3184
      info->refer = take_member_var(mpl, info->var, info->tuple);
alpar@1
  3185
      return;
alpar@1
  3186
}
alpar@1
  3187
alpar@1
  3188
ELEMVAR *eval_member_var      /* returns reference */
alpar@1
  3189
(     MPL *mpl,
alpar@1
  3190
      VARIABLE *var,          /* not changed */
alpar@1
  3191
      TUPLE *tuple            /* not changed */
alpar@1
  3192
)
alpar@1
  3193
{     /* this routine evaluates variable member */
alpar@1
  3194
      struct eval_var_info _info, *info = &_info;
alpar@1
  3195
      xassert(var->dim == tuple_dimen(mpl, tuple));
alpar@1
  3196
      info->var = var;
alpar@1
  3197
      info->tuple = tuple;
alpar@1
  3198
      /* evaluate member, which has given n-tuple */
alpar@1
  3199
      if (eval_within_domain(mpl, info->var->domain, info->tuple, info,
alpar@1
  3200
         eval_var_func))
alpar@1
  3201
         out_of_domain(mpl, var->name, info->tuple);
alpar@1
  3202
      /* bring evaluated reference to the calling program */
alpar@1
  3203
      return info->refer;
alpar@1
  3204
}
alpar@1
  3205
alpar@1
  3206
/*----------------------------------------------------------------------
alpar@1
  3207
-- eval_whole_var - evaluate model variable over entire domain.
alpar@1
  3208
--
alpar@1
  3209
-- This routine evaluates all members of specified model variable over
alpar@1
  3210
-- entire domain. */
alpar@1
  3211
alpar@1
  3212
static int whole_var_func(MPL *mpl, void *info)
alpar@1
  3213
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  3214
      VARIABLE *var = (VARIABLE *)info;
alpar@1
  3215
      TUPLE *tuple = get_domain_tuple(mpl, var->domain);
alpar@1
  3216
      eval_member_var(mpl, var, tuple);
alpar@1
  3217
      delete_tuple(mpl, tuple);
alpar@1
  3218
      return 0;
alpar@1
  3219
}
alpar@1
  3220
alpar@1
  3221
void eval_whole_var(MPL *mpl, VARIABLE *var)
alpar@1
  3222
{     loop_within_domain(mpl, var->domain, var, whole_var_func);
alpar@1
  3223
      return;
alpar@1
  3224
}
alpar@1
  3225
alpar@1
  3226
/*----------------------------------------------------------------------
alpar@1
  3227
-- clean_variable - clean model variable.
alpar@1
  3228
--
alpar@1
  3229
-- This routine cleans specified model variable that assumes deleting
alpar@1
  3230
-- all stuff dynamically allocated during the generation phase. */
alpar@1
  3231
alpar@1
  3232
void clean_variable(MPL *mpl, VARIABLE *var)
alpar@1
  3233
{     MEMBER *memb;
alpar@1
  3234
      /* clean subscript domain */
alpar@1
  3235
      clean_domain(mpl, var->domain);
alpar@1
  3236
      /* clean code for computing lower bound */
alpar@1
  3237
      clean_code(mpl, var->lbnd);
alpar@1
  3238
      /* clean code for computing upper bound */
alpar@1
  3239
      if (var->ubnd != var->lbnd) clean_code(mpl, var->ubnd);
alpar@1
  3240
      /* delete content array */
alpar@1
  3241
      for (memb = var->array->head; memb != NULL; memb = memb->next)
alpar@1
  3242
         dmp_free_atom(mpl->elemvars, memb->value.var, sizeof(ELEMVAR));
alpar@1
  3243
      delete_array(mpl, var->array), var->array = NULL;
alpar@1
  3244
      return;
alpar@1
  3245
}
alpar@1
  3246
alpar@1
  3247
/**********************************************************************/
alpar@1
  3248
/* * *              MODEL CONSTRAINTS AND OBJECTIVES              * * */
alpar@1
  3249
/**********************************************************************/
alpar@1
  3250
alpar@1
  3251
/*----------------------------------------------------------------------
alpar@1
  3252
-- take_member_con - obtain reference to elemental constraint.
alpar@1
  3253
--
alpar@1
  3254
-- This routine obtains a reference to elemental constraint assigned
alpar@1
  3255
-- to given member of specified model constraint and returns it on exit.
alpar@1
  3256
-- If necessary, new elemental constraint is created.
alpar@1
  3257
--
alpar@1
  3258
-- NOTE: This routine must not be called out of domain scope. */
alpar@1
  3259
alpar@1
  3260
ELEMCON *take_member_con      /* returns reference */
alpar@1
  3261
(     MPL *mpl,
alpar@1
  3262
      CONSTRAINT *con,        /* not changed */
alpar@1
  3263
      TUPLE *tuple            /* not changed */
alpar@1
  3264
)
alpar@1
  3265
{     MEMBER *memb;
alpar@1
  3266
      ELEMCON *refer;
alpar@1
  3267
      /* find member in the constraint array */
alpar@1
  3268
      memb = find_member(mpl, con->array, tuple);
alpar@1
  3269
      if (memb != NULL)
alpar@1
  3270
      {  /* member exists, so just take the reference */
alpar@1
  3271
         refer = memb->value.con;
alpar@1
  3272
      }
alpar@1
  3273
      else
alpar@1
  3274
      {  /* member is referenced for the first time and therefore does
alpar@1
  3275
            not exist; create new elemental constraint, assign it to new
alpar@1
  3276
            member, and add the member to the constraint array */
alpar@1
  3277
         memb = add_member(mpl, con->array, copy_tuple(mpl, tuple));
alpar@1
  3278
         refer = (memb->value.con =
alpar@1
  3279
            dmp_get_atom(mpl->elemcons, sizeof(ELEMCON)));
alpar@1
  3280
         refer->i = 0;
alpar@1
  3281
         refer->con = con;
alpar@1
  3282
         refer->memb = memb;
alpar@1
  3283
         /* compute linear form */
alpar@1
  3284
         xassert(con->code != NULL);
alpar@1
  3285
         refer->form = eval_formula(mpl, con->code);
alpar@1
  3286
         /* compute lower and upper bounds */
alpar@1
  3287
         if (con->lbnd == NULL && con->ubnd == NULL)
alpar@1
  3288
         {  /* objective has no bounds */
alpar@1
  3289
            double temp;
alpar@1
  3290
            xassert(con->type == A_MINIMIZE || con->type == A_MAXIMIZE);
alpar@1
  3291
            /* carry the constant term to the right-hand side */
alpar@1
  3292
            refer->form = remove_constant(mpl, refer->form, &temp);
alpar@1
  3293
            refer->lbnd = refer->ubnd = - temp;
alpar@1
  3294
         }
alpar@1
  3295
         else if (con->lbnd != NULL && con->ubnd == NULL)
alpar@1
  3296
         {  /* constraint a * x + b >= c * y + d is transformed to the
alpar@1
  3297
               standard form a * x - c * y >= d - b */
alpar@1
  3298
            double temp;
alpar@1
  3299
            xassert(con->type == A_CONSTRAINT);
alpar@1
  3300
            refer->form = linear_comb(mpl,
alpar@1
  3301
               +1.0, refer->form,
alpar@1
  3302
               -1.0, eval_formula(mpl, con->lbnd));
alpar@1
  3303
            refer->form = remove_constant(mpl, refer->form, &temp);
alpar@1
  3304
            refer->lbnd = - temp;
alpar@1
  3305
            refer->ubnd = 0.0;
alpar@1
  3306
         }
alpar@1
  3307
         else if (con->lbnd == NULL && con->ubnd != NULL)
alpar@1
  3308
         {  /* constraint a * x + b <= c * y + d is transformed to the
alpar@1
  3309
               standard form a * x - c * y <= d - b */
alpar@1
  3310
            double temp;
alpar@1
  3311
            xassert(con->type == A_CONSTRAINT);
alpar@1
  3312
            refer->form = linear_comb(mpl,
alpar@1
  3313
               +1.0, refer->form,
alpar@1
  3314
               -1.0, eval_formula(mpl, con->ubnd));
alpar@1
  3315
            refer->form = remove_constant(mpl, refer->form, &temp);
alpar@1
  3316
            refer->lbnd = 0.0;
alpar@1
  3317
            refer->ubnd = - temp;
alpar@1
  3318
         }
alpar@1
  3319
         else if (con->lbnd == con->ubnd)
alpar@1
  3320
         {  /* constraint a * x + b = c * y + d is transformed to the
alpar@1
  3321
               standard form a * x - c * y = d - b */
alpar@1
  3322
            double temp;
alpar@1
  3323
            xassert(con->type == A_CONSTRAINT);
alpar@1
  3324
            refer->form = linear_comb(mpl,
alpar@1
  3325
               +1.0, refer->form,
alpar@1
  3326
               -1.0, eval_formula(mpl, con->lbnd));
alpar@1
  3327
            refer->form = remove_constant(mpl, refer->form, &temp);
alpar@1
  3328
            refer->lbnd = refer->ubnd = - temp;
alpar@1
  3329
         }
alpar@1
  3330
         else
alpar@1
  3331
         {  /* ranged constraint c <= a * x + b <= d is transformed to
alpar@1
  3332
               the standard form c - b <= a * x <= d - b */
alpar@1
  3333
            double temp, temp1, temp2;
alpar@1
  3334
            xassert(con->type == A_CONSTRAINT);
alpar@1
  3335
            refer->form = remove_constant(mpl, refer->form, &temp);
alpar@1
  3336
            xassert(remove_constant(mpl, eval_formula(mpl, con->lbnd),
alpar@1
  3337
               &temp1) == NULL);
alpar@1
  3338
            xassert(remove_constant(mpl, eval_formula(mpl, con->ubnd),
alpar@1
  3339
               &temp2) == NULL);
alpar@1
  3340
            refer->lbnd = fp_sub(mpl, temp1, temp);
alpar@1
  3341
            refer->ubnd = fp_sub(mpl, temp2, temp);
alpar@1
  3342
         }
alpar@1
  3343
#if 1 /* 15/V-2010 */
alpar@1
  3344
         /* solution has not been obtained by the solver yet */
alpar@1
  3345
         refer->stat = 0;
alpar@1
  3346
         refer->prim = refer->dual = 0.0;
alpar@1
  3347
#endif
alpar@1
  3348
      }
alpar@1
  3349
      return refer;
alpar@1
  3350
}
alpar@1
  3351
alpar@1
  3352
/*----------------------------------------------------------------------
alpar@1
  3353
-- eval_member_con - evaluate reference to elemental constraint.
alpar@1
  3354
--
alpar@1
  3355
-- This routine evaluates a reference to elemental constraint assigned
alpar@1
  3356
-- to member of specified model constraint and returns it on exit. */
alpar@1
  3357
alpar@1
  3358
struct eval_con_info
alpar@1
  3359
{     /* working info used by the routine eval_member_con */
alpar@1
  3360
      CONSTRAINT *con;
alpar@1
  3361
      /* model constraint */
alpar@1
  3362
      TUPLE *tuple;
alpar@1
  3363
      /* n-tuple, which defines constraint member */
alpar@1
  3364
      ELEMCON *refer;
alpar@1
  3365
      /* evaluated reference to elemental constraint */
alpar@1
  3366
};
alpar@1
  3367
alpar@1
  3368
static void eval_con_func(MPL *mpl, void *_info)
alpar@1
  3369
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  3370
      struct eval_con_info *info = _info;
alpar@1
  3371
      info->refer = take_member_con(mpl, info->con, info->tuple);
alpar@1
  3372
      return;
alpar@1
  3373
}
alpar@1
  3374
alpar@1
  3375
ELEMCON *eval_member_con      /* returns reference */
alpar@1
  3376
(     MPL *mpl,
alpar@1
  3377
      CONSTRAINT *con,        /* not changed */
alpar@1
  3378
      TUPLE *tuple            /* not changed */
alpar@1
  3379
)
alpar@1
  3380
{     /* this routine evaluates constraint member */
alpar@1
  3381
      struct eval_con_info _info, *info = &_info;
alpar@1
  3382
      xassert(con->dim == tuple_dimen(mpl, tuple));
alpar@1
  3383
      info->con = con;
alpar@1
  3384
      info->tuple = tuple;
alpar@1
  3385
      /* evaluate member, which has given n-tuple */
alpar@1
  3386
      if (eval_within_domain(mpl, info->con->domain, info->tuple, info,
alpar@1
  3387
         eval_con_func))
alpar@1
  3388
         out_of_domain(mpl, con->name, info->tuple);
alpar@1
  3389
      /* bring evaluated reference to the calling program */
alpar@1
  3390
      return info->refer;
alpar@1
  3391
}
alpar@1
  3392
alpar@1
  3393
/*----------------------------------------------------------------------
alpar@1
  3394
-- eval_whole_con - evaluate model constraint over entire domain.
alpar@1
  3395
--
alpar@1
  3396
-- This routine evaluates all members of specified model constraint over
alpar@1
  3397
-- entire domain. */
alpar@1
  3398
alpar@1
  3399
static int whole_con_func(MPL *mpl, void *info)
alpar@1
  3400
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  3401
      CONSTRAINT *con = (CONSTRAINT *)info;
alpar@1
  3402
      TUPLE *tuple = get_domain_tuple(mpl, con->domain);
alpar@1
  3403
      eval_member_con(mpl, con, tuple);
alpar@1
  3404
      delete_tuple(mpl, tuple);
alpar@1
  3405
      return 0;
alpar@1
  3406
}
alpar@1
  3407
alpar@1
  3408
void eval_whole_con(MPL *mpl, CONSTRAINT *con)
alpar@1
  3409
{     loop_within_domain(mpl, con->domain, con, whole_con_func);
alpar@1
  3410
      return;
alpar@1
  3411
}
alpar@1
  3412
alpar@1
  3413
/*----------------------------------------------------------------------
alpar@1
  3414
-- clean_constraint - clean model constraint.
alpar@1
  3415
--
alpar@1
  3416
-- This routine cleans specified model constraint that assumes deleting
alpar@1
  3417
-- all stuff dynamically allocated during the generation phase. */
alpar@1
  3418
alpar@1
  3419
void clean_constraint(MPL *mpl, CONSTRAINT *con)
alpar@1
  3420
{     MEMBER *memb;
alpar@1
  3421
      /* clean subscript domain */
alpar@1
  3422
      clean_domain(mpl, con->domain);
alpar@1
  3423
      /* clean code for computing main linear form */
alpar@1
  3424
      clean_code(mpl, con->code);
alpar@1
  3425
      /* clean code for computing lower bound */
alpar@1
  3426
      clean_code(mpl, con->lbnd);
alpar@1
  3427
      /* clean code for computing upper bound */
alpar@1
  3428
      if (con->ubnd != con->lbnd) clean_code(mpl, con->ubnd);
alpar@1
  3429
      /* delete content array */
alpar@1
  3430
      for (memb = con->array->head; memb != NULL; memb = memb->next)
alpar@1
  3431
      {  delete_formula(mpl, memb->value.con->form);
alpar@1
  3432
         dmp_free_atom(mpl->elemcons, memb->value.con, sizeof(ELEMCON));
alpar@1
  3433
      }
alpar@1
  3434
      delete_array(mpl, con->array), con->array = NULL;
alpar@1
  3435
      return;
alpar@1
  3436
}
alpar@1
  3437
alpar@1
  3438
/**********************************************************************/
alpar@1
  3439
/* * *                        PSEUDO-CODE                         * * */
alpar@1
  3440
/**********************************************************************/
alpar@1
  3441
alpar@1
  3442
/*----------------------------------------------------------------------
alpar@1
  3443
-- eval_numeric - evaluate pseudo-code to determine numeric value.
alpar@1
  3444
--
alpar@1
  3445
-- This routine evaluates specified pseudo-code to determine resultant
alpar@1
  3446
-- numeric value, which is returned on exit. */
alpar@1
  3447
alpar@1
  3448
struct iter_num_info
alpar@1
  3449
{     /* working info used by the routine iter_num_func */
alpar@1
  3450
      CODE *code;
alpar@1
  3451
      /* pseudo-code for iterated operation to be performed */
alpar@1
  3452
      double value;
alpar@1
  3453
      /* resultant value */
alpar@1
  3454
};
alpar@1
  3455
alpar@1
  3456
static int iter_num_func(MPL *mpl, void *_info)
alpar@1
  3457
{     /* this is auxiliary routine used to perform iterated operation
alpar@1
  3458
         on numeric "integrand" within domain scope */
alpar@1
  3459
      struct iter_num_info *info = _info;
alpar@1
  3460
      double temp;
alpar@1
  3461
      temp = eval_numeric(mpl, info->code->arg.loop.x);
alpar@1
  3462
      switch (info->code->op)
alpar@1
  3463
      {  case O_SUM:
alpar@1
  3464
            /* summation over domain */
alpar@1
  3465
            info->value = fp_add(mpl, info->value, temp);
alpar@1
  3466
            break;
alpar@1
  3467
         case O_PROD:
alpar@1
  3468
            /* multiplication over domain */
alpar@1
  3469
            info->value = fp_mul(mpl, info->value, temp);
alpar@1
  3470
            break;
alpar@1
  3471
         case O_MINIMUM:
alpar@1
  3472
            /* minimum over domain */
alpar@1
  3473
            if (info->value > temp) info->value = temp;
alpar@1
  3474
            break;
alpar@1
  3475
         case O_MAXIMUM:
alpar@1
  3476
            /* maximum over domain */
alpar@1
  3477
            if (info->value < temp) info->value = temp;
alpar@1
  3478
            break;
alpar@1
  3479
         default:
alpar@1
  3480
            xassert(info != info);
alpar@1
  3481
      }
alpar@1
  3482
      return 0;
alpar@1
  3483
}
alpar@1
  3484
alpar@1
  3485
double eval_numeric(MPL *mpl, CODE *code)
alpar@1
  3486
{     double value;
alpar@1
  3487
      xassert(code != NULL);
alpar@1
  3488
      xassert(code->type == A_NUMERIC);
alpar@1
  3489
      xassert(code->dim == 0);
alpar@1
  3490
      /* if the operation has a side effect, invalidate and delete the
alpar@1
  3491
         resultant value */
alpar@1
  3492
      if (code->vflag && code->valid)
alpar@1
  3493
      {  code->valid = 0;
alpar@1
  3494
         delete_value(mpl, code->type, &code->value);
alpar@1
  3495
      }
alpar@1
  3496
      /* if resultant value is valid, no evaluation is needed */
alpar@1
  3497
      if (code->valid)
alpar@1
  3498
      {  value = code->value.num;
alpar@1
  3499
         goto done;
alpar@1
  3500
      }
alpar@1
  3501
      /* evaluate pseudo-code recursively */
alpar@1
  3502
      switch (code->op)
alpar@1
  3503
      {  case O_NUMBER:
alpar@1
  3504
            /* take floating-point number */
alpar@1
  3505
            value = code->arg.num;
alpar@1
  3506
            break;
alpar@1
  3507
         case O_MEMNUM:
alpar@1
  3508
            /* take member of numeric parameter */
alpar@1
  3509
            {  TUPLE *tuple;
alpar@1
  3510
               ARG_LIST *e;
alpar@1
  3511
               tuple = create_tuple(mpl);
alpar@1
  3512
               for (e = code->arg.par.list; e != NULL; e = e->next)
alpar@1
  3513
                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
alpar@1
  3514
                     e->x));
alpar@1
  3515
               value = eval_member_num(mpl, code->arg.par.par, tuple);
alpar@1
  3516
               delete_tuple(mpl, tuple);
alpar@1
  3517
            }
alpar@1
  3518
            break;
alpar@1
  3519
         case O_MEMVAR:
alpar@1
  3520
            /* take computed value of elemental variable */
alpar@1
  3521
            {  TUPLE *tuple;
alpar@1
  3522
               ARG_LIST *e;
alpar@1
  3523
#if 1 /* 15/V-2010 */
alpar@1
  3524
               ELEMVAR *var;
alpar@1
  3525
#endif
alpar@1
  3526
               tuple = create_tuple(mpl);
alpar@1
  3527
               for (e = code->arg.var.list; e != NULL; e = e->next)
alpar@1
  3528
                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
alpar@1
  3529
                     e->x));
alpar@1
  3530
#if 0 /* 15/V-2010 */
alpar@1
  3531
               value = eval_member_var(mpl, code->arg.var.var, tuple)
alpar@1
  3532
                  ->value;
alpar@1
  3533
#else
alpar@1
  3534
               var = eval_member_var(mpl, code->arg.var.var, tuple);
alpar@1
  3535
               switch (code->arg.var.suff)
alpar@1
  3536
               {  case DOT_LB:
alpar@1
  3537
                     if (var->var->lbnd == NULL)
alpar@1
  3538
                        value = -DBL_MAX;
alpar@1
  3539
                     else
alpar@1
  3540
                        value = var->lbnd;
alpar@1
  3541
                     break;
alpar@1
  3542
                  case DOT_UB:
alpar@1
  3543
                     if (var->var->ubnd == NULL)
alpar@1
  3544
                        value = +DBL_MAX;
alpar@1
  3545
                     else
alpar@1
  3546
                        value = var->ubnd;
alpar@1
  3547
                     break;
alpar@1
  3548
                  case DOT_STATUS:
alpar@1
  3549
                     value = var->stat;
alpar@1
  3550
                     break;
alpar@1
  3551
                  case DOT_VAL:
alpar@1
  3552
                     value = var->prim;
alpar@1
  3553
                     break;
alpar@1
  3554
                  case DOT_DUAL:
alpar@1
  3555
                     value = var->dual;
alpar@1
  3556
                     break;
alpar@1
  3557
                  default:
alpar@1
  3558
                     xassert(code != code);
alpar@1
  3559
               }
alpar@1
  3560
#endif
alpar@1
  3561
               delete_tuple(mpl, tuple);
alpar@1
  3562
            }
alpar@1
  3563
            break;
alpar@1
  3564
#if 1 /* 15/V-2010 */
alpar@1
  3565
         case O_MEMCON:
alpar@1
  3566
            /* take computed value of elemental constraint */
alpar@1
  3567
            {  TUPLE *tuple;
alpar@1
  3568
               ARG_LIST *e;
alpar@1
  3569
               ELEMCON *con;
alpar@1
  3570
               tuple = create_tuple(mpl);
alpar@1
  3571
               for (e = code->arg.con.list; e != NULL; e = e->next)
alpar@1
  3572
                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
alpar@1
  3573
                     e->x));
alpar@1
  3574
               con = eval_member_con(mpl, code->arg.con.con, tuple);
alpar@1
  3575
               switch (code->arg.con.suff)
alpar@1
  3576
               {  case DOT_LB:
alpar@1
  3577
                     if (con->con->lbnd == NULL)
alpar@1
  3578
                        value = -DBL_MAX;
alpar@1
  3579
                     else
alpar@1
  3580
                        value = con->lbnd;
alpar@1
  3581
                     break;
alpar@1
  3582
                  case DOT_UB:
alpar@1
  3583
                     if (con->con->ubnd == NULL)
alpar@1
  3584
                        value = +DBL_MAX;
alpar@1
  3585
                     else
alpar@1
  3586
                        value = con->ubnd;
alpar@1
  3587
                     break;
alpar@1
  3588
                  case DOT_STATUS:
alpar@1
  3589
                     value = con->stat;
alpar@1
  3590
                     break;
alpar@1
  3591
                  case DOT_VAL:
alpar@1
  3592
                     value = con->prim;
alpar@1
  3593
                     break;
alpar@1
  3594
                  case DOT_DUAL:
alpar@1
  3595
                     value = con->dual;
alpar@1
  3596
                     break;
alpar@1
  3597
                  default:
alpar@1
  3598
                     xassert(code != code);
alpar@1
  3599
               }
alpar@1
  3600
               delete_tuple(mpl, tuple);
alpar@1
  3601
            }
alpar@1
  3602
            break;
alpar@1
  3603
#endif
alpar@1
  3604
         case O_IRAND224:
alpar@1
  3605
            /* pseudo-random in [0, 2^24-1] */
alpar@1
  3606
            value = fp_irand224(mpl);
alpar@1
  3607
            break;
alpar@1
  3608
         case O_UNIFORM01:
alpar@1
  3609
            /* pseudo-random in [0, 1) */
alpar@1
  3610
            value = fp_uniform01(mpl);
alpar@1
  3611
            break;
alpar@1
  3612
         case O_NORMAL01:
alpar@1
  3613
            /* gaussian random, mu = 0, sigma = 1 */
alpar@1
  3614
            value = fp_normal01(mpl);
alpar@1
  3615
            break;
alpar@1
  3616
         case O_GMTIME:
alpar@1
  3617
            /* current calendar time */
alpar@1
  3618
            value = fn_gmtime(mpl);
alpar@1
  3619
            break;
alpar@1
  3620
         case O_CVTNUM:
alpar@1
  3621
            /* conversion to numeric */
alpar@1
  3622
            {  SYMBOL *sym;
alpar@1
  3623
               sym = eval_symbolic(mpl, code->arg.arg.x);
alpar@1
  3624
#if 0 /* 23/XI-2008 */
alpar@1
  3625
               if (sym->str != NULL)
alpar@1
  3626
                  error(mpl, "cannot convert %s to floating-point numbe"
alpar@1
  3627
                     "r", format_symbol(mpl, sym));
alpar@1
  3628
               value = sym->num;
alpar@1
  3629
#else
alpar@1
  3630
               if (sym->str == NULL)
alpar@1
  3631
                  value = sym->num;
alpar@1
  3632
               else
alpar@1
  3633
               {  if (str2num(sym->str, &value))
alpar@1
  3634
                     error(mpl, "cannot convert %s to floating-point nu"
alpar@1
  3635
                        "mber", format_symbol(mpl, sym));
alpar@1
  3636
               }
alpar@1
  3637
#endif
alpar@1
  3638
               delete_symbol(mpl, sym);
alpar@1
  3639
            }
alpar@1
  3640
            break;
alpar@1
  3641
         case O_PLUS:
alpar@1
  3642
            /* unary plus */
alpar@1
  3643
            value = + eval_numeric(mpl, code->arg.arg.x);
alpar@1
  3644
            break;
alpar@1
  3645
         case O_MINUS:
alpar@1
  3646
            /* unary minus */
alpar@1
  3647
            value = - eval_numeric(mpl, code->arg.arg.x);
alpar@1
  3648
            break;
alpar@1
  3649
         case O_ABS:
alpar@1
  3650
            /* absolute value */
alpar@1
  3651
            value = fabs(eval_numeric(mpl, code->arg.arg.x));
alpar@1
  3652
            break;
alpar@1
  3653
         case O_CEIL:
alpar@1
  3654
            /* round upward ("ceiling of x") */
alpar@1
  3655
            value = ceil(eval_numeric(mpl, code->arg.arg.x));
alpar@1
  3656
            break;
alpar@1
  3657
         case O_FLOOR:
alpar@1
  3658
            /* round downward ("floor of x") */
alpar@1
  3659
            value = floor(eval_numeric(mpl, code->arg.arg.x));
alpar@1
  3660
            break;
alpar@1
  3661
         case O_EXP:
alpar@1
  3662
            /* base-e exponential */
alpar@1
  3663
            value = fp_exp(mpl, eval_numeric(mpl, code->arg.arg.x));
alpar@1
  3664
            break;
alpar@1
  3665
         case O_LOG:
alpar@1
  3666
            /* natural logarithm */
alpar@1
  3667
            value = fp_log(mpl, eval_numeric(mpl, code->arg.arg.x));
alpar@1
  3668
            break;
alpar@1
  3669
         case O_LOG10:
alpar@1
  3670
            /* common (decimal) logarithm */
alpar@1
  3671
            value = fp_log10(mpl, eval_numeric(mpl, code->arg.arg.x));
alpar@1
  3672
            break;
alpar@1
  3673
         case O_SQRT:
alpar@1
  3674
            /* square root */
alpar@1
  3675
            value = fp_sqrt(mpl, eval_numeric(mpl, code->arg.arg.x));
alpar@1
  3676
            break;
alpar@1
  3677
         case O_SIN:
alpar@1
  3678
            /* trigonometric sine */
alpar@1
  3679
            value = fp_sin(mpl, eval_numeric(mpl, code->arg.arg.x));
alpar@1
  3680
            break;
alpar@1
  3681
         case O_COS:
alpar@1
  3682
            /* trigonometric cosine */
alpar@1
  3683
            value = fp_cos(mpl, eval_numeric(mpl, code->arg.arg.x));
alpar@1
  3684
            break;
alpar@1
  3685
         case O_ATAN:
alpar@1
  3686
            /* trigonometric arctangent (one argument) */
alpar@1
  3687
            value = fp_atan(mpl, eval_numeric(mpl, code->arg.arg.x));
alpar@1
  3688
            break;
alpar@1
  3689
         case O_ATAN2:
alpar@1
  3690
            /* trigonometric arctangent (two arguments) */
alpar@1
  3691
            value = fp_atan2(mpl,
alpar@1
  3692
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3693
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3694
            break;
alpar@1
  3695
         case O_ROUND:
alpar@1
  3696
            /* round to nearest integer */
alpar@1
  3697
            value = fp_round(mpl,
alpar@1
  3698
               eval_numeric(mpl, code->arg.arg.x), 0.0);
alpar@1
  3699
            break;
alpar@1
  3700
         case O_ROUND2:
alpar@1
  3701
            /* round to n fractional digits */
alpar@1
  3702
            value = fp_round(mpl,
alpar@1
  3703
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3704
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3705
            break;
alpar@1
  3706
         case O_TRUNC:
alpar@1
  3707
            /* truncate to nearest integer */
alpar@1
  3708
            value = fp_trunc(mpl,
alpar@1
  3709
               eval_numeric(mpl, code->arg.arg.x), 0.0);
alpar@1
  3710
            break;
alpar@1
  3711
         case O_TRUNC2:
alpar@1
  3712
            /* truncate to n fractional digits */
alpar@1
  3713
            value = fp_trunc(mpl,
alpar@1
  3714
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3715
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3716
            break;
alpar@1
  3717
         case O_ADD:
alpar@1
  3718
            /* addition */
alpar@1
  3719
            value = fp_add(mpl,
alpar@1
  3720
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3721
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3722
            break;
alpar@1
  3723
         case O_SUB:
alpar@1
  3724
            /* subtraction */
alpar@1
  3725
            value = fp_sub(mpl,
alpar@1
  3726
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3727
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3728
            break;
alpar@1
  3729
         case O_LESS:
alpar@1
  3730
            /* non-negative subtraction */
alpar@1
  3731
            value = fp_less(mpl,
alpar@1
  3732
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3733
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3734
            break;
alpar@1
  3735
         case O_MUL:
alpar@1
  3736
            /* multiplication */
alpar@1
  3737
            value = fp_mul(mpl,
alpar@1
  3738
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3739
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3740
            break;
alpar@1
  3741
         case O_DIV:
alpar@1
  3742
            /* division */
alpar@1
  3743
            value = fp_div(mpl,
alpar@1
  3744
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3745
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3746
            break;
alpar@1
  3747
         case O_IDIV:
alpar@1
  3748
            /* quotient of exact division */
alpar@1
  3749
            value = fp_idiv(mpl,
alpar@1
  3750
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3751
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3752
            break;
alpar@1
  3753
         case O_MOD:
alpar@1
  3754
            /* remainder of exact division */
alpar@1
  3755
            value = fp_mod(mpl,
alpar@1
  3756
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3757
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3758
            break;
alpar@1
  3759
         case O_POWER:
alpar@1
  3760
            /* exponentiation (raise to power) */
alpar@1
  3761
            value = fp_power(mpl,
alpar@1
  3762
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3763
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3764
            break;
alpar@1
  3765
         case O_UNIFORM:
alpar@1
  3766
            /* pseudo-random in [a, b) */
alpar@1
  3767
            value = fp_uniform(mpl,
alpar@1
  3768
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3769
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3770
            break;
alpar@1
  3771
         case O_NORMAL:
alpar@1
  3772
            /* gaussian random, given mu and sigma */
alpar@1
  3773
            value = fp_normal(mpl,
alpar@1
  3774
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  3775
               eval_numeric(mpl, code->arg.arg.y));
alpar@1
  3776
            break;
alpar@1
  3777
         case O_CARD:
alpar@1
  3778
            {  ELEMSET *set;
alpar@1
  3779
               set = eval_elemset(mpl, code->arg.arg.x);
alpar@1
  3780
               value = set->size;
alpar@1
  3781
               delete_array(mpl, set);
alpar@1
  3782
            }
alpar@1
  3783
            break;
alpar@1
  3784
         case O_LENGTH:
alpar@1
  3785
            {  SYMBOL *sym;
alpar@1
  3786
               char str[MAX_LENGTH+1];
alpar@1
  3787
               sym = eval_symbolic(mpl, code->arg.arg.x);
alpar@1
  3788
               if (sym->str == NULL)
alpar@1
  3789
                  sprintf(str, "%.*g", DBL_DIG, sym->num);
alpar@1
  3790
               else
alpar@1
  3791
                  fetch_string(mpl, sym->str, str);
alpar@1
  3792
               delete_symbol(mpl, sym);
alpar@1
  3793
               value = strlen(str);
alpar@1
  3794
            }
alpar@1
  3795
            break;
alpar@1
  3796
         case O_STR2TIME:
alpar@1
  3797
            {  SYMBOL *sym;
alpar@1
  3798
               char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
alpar@1
  3799
               sym = eval_symbolic(mpl, code->arg.arg.x);
alpar@1
  3800
               if (sym->str == NULL)
alpar@1
  3801
                  sprintf(str, "%.*g", DBL_DIG, sym->num);
alpar@1
  3802
               else
alpar@1
  3803
                  fetch_string(mpl, sym->str, str);
alpar@1
  3804
               delete_symbol(mpl, sym);
alpar@1
  3805
               sym = eval_symbolic(mpl, code->arg.arg.y);
alpar@1
  3806
               if (sym->str == NULL)
alpar@1
  3807
                  sprintf(fmt, "%.*g", DBL_DIG, sym->num);
alpar@1
  3808
               else
alpar@1
  3809
                  fetch_string(mpl, sym->str, fmt);
alpar@1
  3810
               delete_symbol(mpl, sym);
alpar@1
  3811
               value = fn_str2time(mpl, str, fmt);
alpar@1
  3812
            }
alpar@1
  3813
            break;
alpar@1
  3814
         case O_FORK:
alpar@1
  3815
            /* if-then-else */
alpar@1
  3816
            if (eval_logical(mpl, code->arg.arg.x))
alpar@1
  3817
               value = eval_numeric(mpl, code->arg.arg.y);
alpar@1
  3818
            else if (code->arg.arg.z == NULL)
alpar@1
  3819
               value = 0.0;
alpar@1
  3820
            else
alpar@1
  3821
               value = eval_numeric(mpl, code->arg.arg.z);
alpar@1
  3822
            break;
alpar@1
  3823
         case O_MIN:
alpar@1
  3824
            /* minimal value (n-ary) */
alpar@1
  3825
            {  ARG_LIST *e;
alpar@1
  3826
               double temp;
alpar@1
  3827
               value = +DBL_MAX;
alpar@1
  3828
               for (e = code->arg.list; e != NULL; e = e->next)
alpar@1
  3829
               {  temp = eval_numeric(mpl, e->x);
alpar@1
  3830
                  if (value > temp) value = temp;
alpar@1
  3831
               }
alpar@1
  3832
            }
alpar@1
  3833
            break;
alpar@1
  3834
         case O_MAX:
alpar@1
  3835
            /* maximal value (n-ary) */
alpar@1
  3836
            {  ARG_LIST *e;
alpar@1
  3837
               double temp;
alpar@1
  3838
               value = -DBL_MAX;
alpar@1
  3839
               for (e = code->arg.list; e != NULL; e = e->next)
alpar@1
  3840
               {  temp = eval_numeric(mpl, e->x);
alpar@1
  3841
                  if (value < temp) value = temp;
alpar@1
  3842
               }
alpar@1
  3843
            }
alpar@1
  3844
            break;
alpar@1
  3845
         case O_SUM:
alpar@1
  3846
            /* summation over domain */
alpar@1
  3847
            {  struct iter_num_info _info, *info = &_info;
alpar@1
  3848
               info->code = code;
alpar@1
  3849
               info->value = 0.0;
alpar@1
  3850
               loop_within_domain(mpl, code->arg.loop.domain, info,
alpar@1
  3851
                  iter_num_func);
alpar@1
  3852
               value = info->value;
alpar@1
  3853
            }
alpar@1
  3854
            break;
alpar@1
  3855
         case O_PROD:
alpar@1
  3856
            /* multiplication over domain */
alpar@1
  3857
            {  struct iter_num_info _info, *info = &_info;
alpar@1
  3858
               info->code = code;
alpar@1
  3859
               info->value = 1.0;
alpar@1
  3860
               loop_within_domain(mpl, code->arg.loop.domain, info,
alpar@1
  3861
                  iter_num_func);
alpar@1
  3862
               value = info->value;
alpar@1
  3863
            }
alpar@1
  3864
            break;
alpar@1
  3865
         case O_MINIMUM:
alpar@1
  3866
            /* minimum over domain */
alpar@1
  3867
            {  struct iter_num_info _info, *info = &_info;
alpar@1
  3868
               info->code = code;
alpar@1
  3869
               info->value = +DBL_MAX;
alpar@1
  3870
               loop_within_domain(mpl, code->arg.loop.domain, info,
alpar@1
  3871
                  iter_num_func);
alpar@1
  3872
               if (info->value == +DBL_MAX)
alpar@1
  3873
                  error(mpl, "min{} over empty set; result undefined");
alpar@1
  3874
               value = info->value;
alpar@1
  3875
            }
alpar@1
  3876
            break;
alpar@1
  3877
         case O_MAXIMUM:
alpar@1
  3878
            /* maximum over domain */
alpar@1
  3879
            {  struct iter_num_info _info, *info = &_info;
alpar@1
  3880
               info->code = code;
alpar@1
  3881
               info->value = -DBL_MAX;
alpar@1
  3882
               loop_within_domain(mpl, code->arg.loop.domain, info,
alpar@1
  3883
                  iter_num_func);
alpar@1
  3884
               if (info->value == -DBL_MAX)
alpar@1
  3885
                  error(mpl, "max{} over empty set; result undefined");
alpar@1
  3886
               value = info->value;
alpar@1
  3887
            }
alpar@1
  3888
            break;
alpar@1
  3889
         default:
alpar@1
  3890
            xassert(code != code);
alpar@1
  3891
      }
alpar@1
  3892
      /* save resultant value */
alpar@1
  3893
      xassert(!code->valid);
alpar@1
  3894
      code->valid = 1;
alpar@1
  3895
      code->value.num = value;
alpar@1
  3896
done: return value;
alpar@1
  3897
}
alpar@1
  3898
alpar@1
  3899
/*----------------------------------------------------------------------
alpar@1
  3900
-- eval_symbolic - evaluate pseudo-code to determine symbolic value.
alpar@1
  3901
--
alpar@1
  3902
-- This routine evaluates specified pseudo-code to determine resultant
alpar@1
  3903
-- symbolic value, which is returned on exit. */
alpar@1
  3904
alpar@1
  3905
SYMBOL *eval_symbolic(MPL *mpl, CODE *code)
alpar@1
  3906
{     SYMBOL *value;
alpar@1
  3907
      xassert(code != NULL);
alpar@1
  3908
      xassert(code->type == A_SYMBOLIC);
alpar@1
  3909
      xassert(code->dim == 0);
alpar@1
  3910
      /* if the operation has a side effect, invalidate and delete the
alpar@1
  3911
         resultant value */
alpar@1
  3912
      if (code->vflag && code->valid)
alpar@1
  3913
      {  code->valid = 0;
alpar@1
  3914
         delete_value(mpl, code->type, &code->value);
alpar@1
  3915
      }
alpar@1
  3916
      /* if resultant value is valid, no evaluation is needed */
alpar@1
  3917
      if (code->valid)
alpar@1
  3918
      {  value = copy_symbol(mpl, code->value.sym);
alpar@1
  3919
         goto done;
alpar@1
  3920
      }
alpar@1
  3921
      /* evaluate pseudo-code recursively */
alpar@1
  3922
      switch (code->op)
alpar@1
  3923
      {  case O_STRING:
alpar@1
  3924
            /* take character string */
alpar@1
  3925
            value = create_symbol_str(mpl, create_string(mpl,
alpar@1
  3926
               code->arg.str));
alpar@1
  3927
            break;
alpar@1
  3928
         case O_INDEX:
alpar@1
  3929
            /* take dummy index */
alpar@1
  3930
            xassert(code->arg.index.slot->value != NULL);
alpar@1
  3931
            value = copy_symbol(mpl, code->arg.index.slot->value);
alpar@1
  3932
            break;
alpar@1
  3933
         case O_MEMSYM:
alpar@1
  3934
            /* take member of symbolic parameter */
alpar@1
  3935
            {  TUPLE *tuple;
alpar@1
  3936
               ARG_LIST *e;
alpar@1
  3937
               tuple = create_tuple(mpl);
alpar@1
  3938
               for (e = code->arg.par.list; e != NULL; e = e->next)
alpar@1
  3939
                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
alpar@1
  3940
                     e->x));
alpar@1
  3941
               value = eval_member_sym(mpl, code->arg.par.par, tuple);
alpar@1
  3942
               delete_tuple(mpl, tuple);
alpar@1
  3943
            }
alpar@1
  3944
            break;
alpar@1
  3945
         case O_CVTSYM:
alpar@1
  3946
            /* conversion to symbolic */
alpar@1
  3947
            value = create_symbol_num(mpl, eval_numeric(mpl,
alpar@1
  3948
               code->arg.arg.x));
alpar@1
  3949
            break;
alpar@1
  3950
         case O_CONCAT:
alpar@1
  3951
            /* concatenation */
alpar@1
  3952
            value = concat_symbols(mpl,
alpar@1
  3953
               eval_symbolic(mpl, code->arg.arg.x),
alpar@1
  3954
               eval_symbolic(mpl, code->arg.arg.y));
alpar@1
  3955
            break;
alpar@1
  3956
         case O_FORK:
alpar@1
  3957
            /* if-then-else */
alpar@1
  3958
            if (eval_logical(mpl, code->arg.arg.x))
alpar@1
  3959
               value = eval_symbolic(mpl, code->arg.arg.y);
alpar@1
  3960
            else if (code->arg.arg.z == NULL)
alpar@1
  3961
               value = create_symbol_num(mpl, 0.0);
alpar@1
  3962
            else
alpar@1
  3963
               value = eval_symbolic(mpl, code->arg.arg.z);
alpar@1
  3964
            break;
alpar@1
  3965
         case O_SUBSTR:
alpar@1
  3966
         case O_SUBSTR3:
alpar@1
  3967
            {  double pos, len;
alpar@1
  3968
               char str[MAX_LENGTH+1];
alpar@1
  3969
               value = eval_symbolic(mpl, code->arg.arg.x);
alpar@1
  3970
               if (value->str == NULL)
alpar@1
  3971
                  sprintf(str, "%.*g", DBL_DIG, value->num);
alpar@1
  3972
               else
alpar@1
  3973
                  fetch_string(mpl, value->str, str);
alpar@1
  3974
               delete_symbol(mpl, value);
alpar@1
  3975
               if (code->op == O_SUBSTR)
alpar@1
  3976
               {  pos = eval_numeric(mpl, code->arg.arg.y);
alpar@1
  3977
                  if (pos != floor(pos))
alpar@1
  3978
                     error(mpl, "substr('...', %.*g); non-integer secon"
alpar@1
  3979
                        "d argument", DBL_DIG, pos);
alpar@1
  3980
                  if (pos < 1 || pos > strlen(str) + 1)
alpar@1
  3981
                     error(mpl, "substr('...', %.*g); substring out of "
alpar@1
  3982
                        "range", DBL_DIG, pos);
alpar@1
  3983
               }
alpar@1
  3984
               else
alpar@1
  3985
               {  pos = eval_numeric(mpl, code->arg.arg.y);
alpar@1
  3986
                  len = eval_numeric(mpl, code->arg.arg.z);
alpar@1
  3987
                  if (pos != floor(pos) || len != floor(len))
alpar@1
  3988
                     error(mpl, "substr('...', %.*g, %.*g); non-integer"
alpar@1
  3989
                        " second and/or third argument", DBL_DIG, pos,
alpar@1
  3990
                        DBL_DIG, len);
alpar@1
  3991
                  if (pos < 1 || len < 0 || pos + len > strlen(str) + 1)
alpar@1
  3992
                     error(mpl, "substr('...', %.*g, %.*g); substring o"
alpar@1
  3993
                        "ut of range", DBL_DIG, pos, DBL_DIG, len);
alpar@1
  3994
                  str[(int)pos + (int)len - 1] = '\0';
alpar@1
  3995
               }
alpar@1
  3996
               value = create_symbol_str(mpl, create_string(mpl, str +
alpar@1
  3997
                  (int)pos - 1));
alpar@1
  3998
            }
alpar@1
  3999
            break;
alpar@1
  4000
         case O_TIME2STR:
alpar@1
  4001
            {  double num;
alpar@1
  4002
               SYMBOL *sym;
alpar@1
  4003
               char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
alpar@1
  4004
               num = eval_numeric(mpl, code->arg.arg.x);
alpar@1
  4005
               sym = eval_symbolic(mpl, code->arg.arg.y);
alpar@1
  4006
               if (sym->str == NULL)
alpar@1
  4007
                  sprintf(fmt, "%.*g", DBL_DIG, sym->num);
alpar@1
  4008
               else
alpar@1
  4009
                  fetch_string(mpl, sym->str, fmt);
alpar@1
  4010
               delete_symbol(mpl, sym);
alpar@1
  4011
               fn_time2str(mpl, str, num, fmt);
alpar@1
  4012
               value = create_symbol_str(mpl, create_string(mpl, str));
alpar@1
  4013
            }
alpar@1
  4014
            break;
alpar@1
  4015
         default:
alpar@1
  4016
            xassert(code != code);
alpar@1
  4017
      }
alpar@1
  4018
      /* save resultant value */
alpar@1
  4019
      xassert(!code->valid);
alpar@1
  4020
      code->valid = 1;
alpar@1
  4021
      code->value.sym = copy_symbol(mpl, value);
alpar@1
  4022
done: return value;
alpar@1
  4023
}
alpar@1
  4024
alpar@1
  4025
/*----------------------------------------------------------------------
alpar@1
  4026
-- eval_logical - evaluate pseudo-code to determine logical value.
alpar@1
  4027
--
alpar@1
  4028
-- This routine evaluates specified pseudo-code to determine resultant
alpar@1
  4029
-- logical value, which is returned on exit. */
alpar@1
  4030
alpar@1
  4031
struct iter_log_info
alpar@1
  4032
{     /* working info used by the routine iter_log_func */
alpar@1
  4033
      CODE *code;
alpar@1
  4034
      /* pseudo-code for iterated operation to be performed */
alpar@1
  4035
      int value;
alpar@1
  4036
      /* resultant value */
alpar@1
  4037
};
alpar@1
  4038
alpar@1
  4039
static int iter_log_func(MPL *mpl, void *_info)
alpar@1
  4040
{     /* this is auxiliary routine used to perform iterated operation
alpar@1
  4041
         on logical "integrand" within domain scope */
alpar@1
  4042
      struct iter_log_info *info = _info;
alpar@1
  4043
      int ret = 0;
alpar@1
  4044
      switch (info->code->op)
alpar@1
  4045
      {  case O_FORALL:
alpar@1
  4046
            /* conjunction over domain */
alpar@1
  4047
            info->value &= eval_logical(mpl, info->code->arg.loop.x);
alpar@1
  4048
            if (!info->value) ret = 1;
alpar@1
  4049
            break;
alpar@1
  4050
         case O_EXISTS:
alpar@1
  4051
            /* disjunction over domain */
alpar@1
  4052
            info->value |= eval_logical(mpl, info->code->arg.loop.x);
alpar@1
  4053
            if (info->value) ret = 1;
alpar@1
  4054
            break;
alpar@1
  4055
         default:
alpar@1
  4056
            xassert(info != info);
alpar@1
  4057
      }
alpar@1
  4058
      return ret;
alpar@1
  4059
}
alpar@1
  4060
alpar@1
  4061
int eval_logical(MPL *mpl, CODE *code)
alpar@1
  4062
{     int value;
alpar@1
  4063
      xassert(code->type == A_LOGICAL);
alpar@1
  4064
      xassert(code->dim == 0);
alpar@1
  4065
      /* if the operation has a side effect, invalidate and delete the
alpar@1
  4066
         resultant value */
alpar@1
  4067
      if (code->vflag && code->valid)
alpar@1
  4068
      {  code->valid = 0;
alpar@1
  4069
         delete_value(mpl, code->type, &code->value);
alpar@1
  4070
      }
alpar@1
  4071
      /* if resultant value is valid, no evaluation is needed */
alpar@1
  4072
      if (code->valid)
alpar@1
  4073
      {  value = code->value.bit;
alpar@1
  4074
         goto done;
alpar@1
  4075
      }
alpar@1
  4076
      /* evaluate pseudo-code recursively */
alpar@1
  4077
      switch (code->op)
alpar@1
  4078
      {  case O_CVTLOG:
alpar@1
  4079
            /* conversion to logical */
alpar@1
  4080
            value = (eval_numeric(mpl, code->arg.arg.x) != 0.0);
alpar@1
  4081
            break;
alpar@1
  4082
         case O_NOT:
alpar@1
  4083
            /* negation (logical "not") */
alpar@1
  4084
            value = !eval_logical(mpl, code->arg.arg.x);
alpar@1
  4085
            break;
alpar@1
  4086
         case O_LT:
alpar@1
  4087
            /* comparison on 'less than' */
alpar@1
  4088
#if 0 /* 02/VIII-2008 */
alpar@1
  4089
            value = (eval_numeric(mpl, code->arg.arg.x) <
alpar@1
  4090
                     eval_numeric(mpl, code->arg.arg.y));
alpar@1
  4091
#else
alpar@1
  4092
            xassert(code->arg.arg.x != NULL);
alpar@1
  4093
            if (code->arg.arg.x->type == A_NUMERIC)
alpar@1
  4094
               value = (eval_numeric(mpl, code->arg.arg.x) <
alpar@1
  4095
                        eval_numeric(mpl, code->arg.arg.y));
alpar@1
  4096
            else
alpar@1
  4097
            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
alpar@1
  4098
               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
alpar@1
  4099
               value = (compare_symbols(mpl, sym1, sym2) < 0);
alpar@1
  4100
               delete_symbol(mpl, sym1);
alpar@1
  4101
               delete_symbol(mpl, sym2);
alpar@1
  4102
            }
alpar@1
  4103
#endif
alpar@1
  4104
            break;
alpar@1
  4105
         case O_LE:
alpar@1
  4106
            /* comparison on 'not greater than' */
alpar@1
  4107
#if 0 /* 02/VIII-2008 */
alpar@1
  4108
            value = (eval_numeric(mpl, code->arg.arg.x) <=
alpar@1
  4109
                     eval_numeric(mpl, code->arg.arg.y));
alpar@1
  4110
#else
alpar@1
  4111
            xassert(code->arg.arg.x != NULL);
alpar@1
  4112
            if (code->arg.arg.x->type == A_NUMERIC)
alpar@1
  4113
               value = (eval_numeric(mpl, code->arg.arg.x) <=
alpar@1
  4114
                        eval_numeric(mpl, code->arg.arg.y));
alpar@1
  4115
            else
alpar@1
  4116
            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
alpar@1
  4117
               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
alpar@1
  4118
               value = (compare_symbols(mpl, sym1, sym2) <= 0);
alpar@1
  4119
               delete_symbol(mpl, sym1);
alpar@1
  4120
               delete_symbol(mpl, sym2);
alpar@1
  4121
            }
alpar@1
  4122
#endif
alpar@1
  4123
            break;
alpar@1
  4124
         case O_EQ:
alpar@1
  4125
            /* comparison on 'equal to' */
alpar@1
  4126
            xassert(code->arg.arg.x != NULL);
alpar@1
  4127
            if (code->arg.arg.x->type == A_NUMERIC)
alpar@1
  4128
               value = (eval_numeric(mpl, code->arg.arg.x) ==
alpar@1
  4129
                        eval_numeric(mpl, code->arg.arg.y));
alpar@1
  4130
            else
alpar@1
  4131
            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
alpar@1
  4132
               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
alpar@1
  4133
               value = (compare_symbols(mpl, sym1, sym2) == 0);
alpar@1
  4134
               delete_symbol(mpl, sym1);
alpar@1
  4135
               delete_symbol(mpl, sym2);
alpar@1
  4136
            }
alpar@1
  4137
            break;
alpar@1
  4138
         case O_GE:
alpar@1
  4139
            /* comparison on 'not less than' */
alpar@1
  4140
#if 0 /* 02/VIII-2008 */
alpar@1
  4141
            value = (eval_numeric(mpl, code->arg.arg.x) >=
alpar@1
  4142
                     eval_numeric(mpl, code->arg.arg.y));
alpar@1
  4143
#else
alpar@1
  4144
            xassert(code->arg.arg.x != NULL);
alpar@1
  4145
            if (code->arg.arg.x->type == A_NUMERIC)
alpar@1
  4146
               value = (eval_numeric(mpl, code->arg.arg.x) >=
alpar@1
  4147
                        eval_numeric(mpl, code->arg.arg.y));
alpar@1
  4148
            else
alpar@1
  4149
            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
alpar@1
  4150
               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
alpar@1
  4151
               value = (compare_symbols(mpl, sym1, sym2) >= 0);
alpar@1
  4152
               delete_symbol(mpl, sym1);
alpar@1
  4153
               delete_symbol(mpl, sym2);
alpar@1
  4154
            }
alpar@1
  4155
#endif
alpar@1
  4156
            break;
alpar@1
  4157
         case O_GT:
alpar@1
  4158
            /* comparison on 'greater than' */
alpar@1
  4159
#if 0 /* 02/VIII-2008 */
alpar@1
  4160
            value = (eval_numeric(mpl, code->arg.arg.x) >
alpar@1
  4161
                     eval_numeric(mpl, code->arg.arg.y));
alpar@1
  4162
#else
alpar@1
  4163
            xassert(code->arg.arg.x != NULL);
alpar@1
  4164
            if (code->arg.arg.x->type == A_NUMERIC)
alpar@1
  4165
               value = (eval_numeric(mpl, code->arg.arg.x) >
alpar@1
  4166
                        eval_numeric(mpl, code->arg.arg.y));
alpar@1
  4167
            else
alpar@1
  4168
            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
alpar@1
  4169
               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
alpar@1
  4170
               value = (compare_symbols(mpl, sym1, sym2) > 0);
alpar@1
  4171
               delete_symbol(mpl, sym1);
alpar@1
  4172
               delete_symbol(mpl, sym2);
alpar@1
  4173
            }
alpar@1
  4174
#endif
alpar@1
  4175
            break;
alpar@1
  4176
         case O_NE:
alpar@1
  4177
            /* comparison on 'not equal to' */
alpar@1
  4178
            xassert(code->arg.arg.x != NULL);
alpar@1
  4179
            if (code->arg.arg.x->type == A_NUMERIC)
alpar@1
  4180
               value = (eval_numeric(mpl, code->arg.arg.x) !=
alpar@1
  4181
                        eval_numeric(mpl, code->arg.arg.y));
alpar@1
  4182
            else
alpar@1
  4183
            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
alpar@1
  4184
               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
alpar@1
  4185
               value = (compare_symbols(mpl, sym1, sym2) != 0);
alpar@1
  4186
               delete_symbol(mpl, sym1);
alpar@1
  4187
               delete_symbol(mpl, sym2);
alpar@1
  4188
            }
alpar@1
  4189
            break;
alpar@1
  4190
         case O_AND:
alpar@1
  4191
            /* conjunction (logical "and") */
alpar@1
  4192
            value = eval_logical(mpl, code->arg.arg.x) &&
alpar@1
  4193
                    eval_logical(mpl, code->arg.arg.y);
alpar@1
  4194
            break;
alpar@1
  4195
         case O_OR:
alpar@1
  4196
            /* disjunction (logical "or") */
alpar@1
  4197
            value = eval_logical(mpl, code->arg.arg.x) ||
alpar@1
  4198
                    eval_logical(mpl, code->arg.arg.y);
alpar@1
  4199
            break;
alpar@1
  4200
         case O_IN:
alpar@1
  4201
            /* test on 'x in Y' */
alpar@1
  4202
            {  TUPLE *tuple;
alpar@1
  4203
               tuple = eval_tuple(mpl, code->arg.arg.x);
alpar@1
  4204
               value = is_member(mpl, code->arg.arg.y, tuple);
alpar@1
  4205
               delete_tuple(mpl, tuple);
alpar@1
  4206
            }
alpar@1
  4207
            break;
alpar@1
  4208
         case O_NOTIN:
alpar@1
  4209
            /* test on 'x not in Y' */
alpar@1
  4210
            {  TUPLE *tuple;
alpar@1
  4211
               tuple = eval_tuple(mpl, code->arg.arg.x);
alpar@1
  4212
               value = !is_member(mpl, code->arg.arg.y, tuple);
alpar@1
  4213
               delete_tuple(mpl, tuple);
alpar@1
  4214
            }
alpar@1
  4215
            break;
alpar@1
  4216
         case O_WITHIN:
alpar@1
  4217
            /* test on 'X within Y' */
alpar@1
  4218
            {  ELEMSET *set;
alpar@1
  4219
               MEMBER *memb;
alpar@1
  4220
               set = eval_elemset(mpl, code->arg.arg.x);
alpar@1
  4221
               value = 1;
alpar@1
  4222
               for (memb = set->head; memb != NULL; memb = memb->next)
alpar@1
  4223
               {  if (!is_member(mpl, code->arg.arg.y, memb->tuple))
alpar@1
  4224
                  {  value = 0;
alpar@1
  4225
                     break;
alpar@1
  4226
                  }
alpar@1
  4227
               }
alpar@1
  4228
               delete_elemset(mpl, set);
alpar@1
  4229
            }
alpar@1
  4230
            break;
alpar@1
  4231
         case O_NOTWITHIN:
alpar@1
  4232
            /* test on 'X not within Y' */
alpar@1
  4233
            {  ELEMSET *set;
alpar@1
  4234
               MEMBER *memb;
alpar@1
  4235
               set = eval_elemset(mpl, code->arg.arg.x);
alpar@1
  4236
               value = 1;
alpar@1
  4237
               for (memb = set->head; memb != NULL; memb = memb->next)
alpar@1
  4238
               {  if (is_member(mpl, code->arg.arg.y, memb->tuple))
alpar@1
  4239
                  {  value = 0;
alpar@1
  4240
                     break;
alpar@1
  4241
                  }
alpar@1
  4242
               }
alpar@1
  4243
               delete_elemset(mpl, set);
alpar@1
  4244
            }
alpar@1
  4245
            break;
alpar@1
  4246
         case O_FORALL:
alpar@1
  4247
            /* conjunction (A-quantification) */
alpar@1
  4248
            {  struct iter_log_info _info, *info = &_info;
alpar@1
  4249
               info->code = code;
alpar@1
  4250
               info->value = 1;
alpar@1
  4251
               loop_within_domain(mpl, code->arg.loop.domain, info,
alpar@1
  4252
                  iter_log_func);
alpar@1
  4253
               value = info->value;
alpar@1
  4254
            }
alpar@1
  4255
            break;
alpar@1
  4256
         case O_EXISTS:
alpar@1
  4257
            /* disjunction (E-quantification) */
alpar@1
  4258
            {  struct iter_log_info _info, *info = &_info;
alpar@1
  4259
               info->code = code;
alpar@1
  4260
               info->value = 0;
alpar@1
  4261
               loop_within_domain(mpl, code->arg.loop.domain, info,
alpar@1
  4262
                  iter_log_func);
alpar@1
  4263
               value = info->value;
alpar@1
  4264
            }
alpar@1
  4265
            break;
alpar@1
  4266
         default:
alpar@1
  4267
            xassert(code != code);
alpar@1
  4268
      }
alpar@1
  4269
      /* save resultant value */
alpar@1
  4270
      xassert(!code->valid);
alpar@1
  4271
      code->valid = 1;
alpar@1
  4272
      code->value.bit = value;
alpar@1
  4273
done: return value;
alpar@1
  4274
}
alpar@1
  4275
alpar@1
  4276
/*----------------------------------------------------------------------
alpar@1
  4277
-- eval_tuple - evaluate pseudo-code to construct n-tuple.
alpar@1
  4278
--
alpar@1
  4279
-- This routine evaluates specified pseudo-code to construct resultant
alpar@1
  4280
-- n-tuple, which is returned on exit. */
alpar@1
  4281
alpar@1
  4282
TUPLE *eval_tuple(MPL *mpl, CODE *code)
alpar@1
  4283
{     TUPLE *value;
alpar@1
  4284
      xassert(code != NULL);
alpar@1
  4285
      xassert(code->type == A_TUPLE);
alpar@1
  4286
      xassert(code->dim > 0);
alpar@1
  4287
      /* if the operation has a side effect, invalidate and delete the
alpar@1
  4288
         resultant value */
alpar@1
  4289
      if (code->vflag && code->valid)
alpar@1
  4290
      {  code->valid = 0;
alpar@1
  4291
         delete_value(mpl, code->type, &code->value);
alpar@1
  4292
      }
alpar@1
  4293
      /* if resultant value is valid, no evaluation is needed */
alpar@1
  4294
      if (code->valid)
alpar@1
  4295
      {  value = copy_tuple(mpl, code->value.tuple);
alpar@1
  4296
         goto done;
alpar@1
  4297
      }
alpar@1
  4298
      /* evaluate pseudo-code recursively */
alpar@1
  4299
      switch (code->op)
alpar@1
  4300
      {  case O_TUPLE:
alpar@1
  4301
            /* make n-tuple */
alpar@1
  4302
            {  ARG_LIST *e;
alpar@1
  4303
               value = create_tuple(mpl);
alpar@1
  4304
               for (e = code->arg.list; e != NULL; e = e->next)
alpar@1
  4305
                  value = expand_tuple(mpl, value, eval_symbolic(mpl,
alpar@1
  4306
                     e->x));
alpar@1
  4307
            }
alpar@1
  4308
            break;
alpar@1
  4309
         case O_CVTTUP:
alpar@1
  4310
            /* convert to 1-tuple */
alpar@1
  4311
            value = expand_tuple(mpl, create_tuple(mpl),
alpar@1
  4312
               eval_symbolic(mpl, code->arg.arg.x));
alpar@1
  4313
            break;
alpar@1
  4314
         default:
alpar@1
  4315
            xassert(code != code);
alpar@1
  4316
      }
alpar@1
  4317
      /* save resultant value */
alpar@1
  4318
      xassert(!code->valid);
alpar@1
  4319
      code->valid = 1;
alpar@1
  4320
      code->value.tuple = copy_tuple(mpl, value);
alpar@1
  4321
done: return value;
alpar@1
  4322
}
alpar@1
  4323
alpar@1
  4324
/*----------------------------------------------------------------------
alpar@1
  4325
-- eval_elemset - evaluate pseudo-code to construct elemental set.
alpar@1
  4326
--
alpar@1
  4327
-- This routine evaluates specified pseudo-code to construct resultant
alpar@1
  4328
-- elemental set, which is returned on exit. */
alpar@1
  4329
alpar@1
  4330
struct iter_set_info
alpar@1
  4331
{     /* working info used by the routine iter_set_func */
alpar@1
  4332
      CODE *code;
alpar@1
  4333
      /* pseudo-code for iterated operation to be performed */
alpar@1
  4334
      ELEMSET *value;
alpar@1
  4335
      /* resultant value */
alpar@1
  4336
};
alpar@1
  4337
alpar@1
  4338
static int iter_set_func(MPL *mpl, void *_info)
alpar@1
  4339
{     /* this is auxiliary routine used to perform iterated operation
alpar@1
  4340
         on n-tuple "integrand" within domain scope */
alpar@1
  4341
      struct iter_set_info *info = _info;
alpar@1
  4342
      TUPLE *tuple;
alpar@1
  4343
      switch (info->code->op)
alpar@1
  4344
      {  case O_SETOF:
alpar@1
  4345
            /* compute next n-tuple and add it to the set; in this case
alpar@1
  4346
               duplicate n-tuples are silently ignored */
alpar@1
  4347
            tuple = eval_tuple(mpl, info->code->arg.loop.x);
alpar@1
  4348
            if (find_tuple(mpl, info->value, tuple) == NULL)
alpar@1
  4349
               add_tuple(mpl, info->value, tuple);
alpar@1
  4350
            else
alpar@1
  4351
               delete_tuple(mpl, tuple);
alpar@1
  4352
            break;
alpar@1
  4353
         case O_BUILD:
alpar@1
  4354
            /* construct next n-tuple using current values assigned to
alpar@1
  4355
               *free* dummy indices as its components and add it to the
alpar@1
  4356
               set; in this case duplicate n-tuples cannot appear */
alpar@1
  4357
            add_tuple(mpl, info->value, get_domain_tuple(mpl,
alpar@1
  4358
               info->code->arg.loop.domain));
alpar@1
  4359
            break;
alpar@1
  4360
         default:
alpar@1
  4361
            xassert(info != info);
alpar@1
  4362
      }
alpar@1
  4363
      return 0;
alpar@1
  4364
}
alpar@1
  4365
alpar@1
  4366
ELEMSET *eval_elemset(MPL *mpl, CODE *code)
alpar@1
  4367
{     ELEMSET *value;
alpar@1
  4368
      xassert(code != NULL);
alpar@1
  4369
      xassert(code->type == A_ELEMSET);
alpar@1
  4370
      xassert(code->dim > 0);
alpar@1
  4371
      /* if the operation has a side effect, invalidate and delete the
alpar@1
  4372
         resultant value */
alpar@1
  4373
      if (code->vflag && code->valid)
alpar@1
  4374
      {  code->valid = 0;
alpar@1
  4375
         delete_value(mpl, code->type, &code->value);
alpar@1
  4376
      }
alpar@1
  4377
      /* if resultant value is valid, no evaluation is needed */
alpar@1
  4378
      if (code->valid)
alpar@1
  4379
      {  value = copy_elemset(mpl, code->value.set);
alpar@1
  4380
         goto done;
alpar@1
  4381
      }
alpar@1
  4382
      /* evaluate pseudo-code recursively */
alpar@1
  4383
      switch (code->op)
alpar@1
  4384
      {  case O_MEMSET:
alpar@1
  4385
            /* take member of set */
alpar@1
  4386
            {  TUPLE *tuple;
alpar@1
  4387
               ARG_LIST *e;
alpar@1
  4388
               tuple = create_tuple(mpl);
alpar@1
  4389
               for (e = code->arg.set.list; e != NULL; e = e->next)
alpar@1
  4390
                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
alpar@1
  4391
                     e->x));
alpar@1
  4392
               value = copy_elemset(mpl,
alpar@1
  4393
                  eval_member_set(mpl, code->arg.set.set, tuple));
alpar@1
  4394
               delete_tuple(mpl, tuple);
alpar@1
  4395
            }
alpar@1
  4396
            break;
alpar@1
  4397
         case O_MAKE:
alpar@1
  4398
            /* make elemental set of n-tuples */
alpar@1
  4399
            {  ARG_LIST *e;
alpar@1
  4400
               value = create_elemset(mpl, code->dim);
alpar@1
  4401
               for (e = code->arg.list; e != NULL; e = e->next)
alpar@1
  4402
                  check_then_add(mpl, value, eval_tuple(mpl, e->x));
alpar@1
  4403
            }
alpar@1
  4404
            break;
alpar@1
  4405
         case O_UNION:
alpar@1
  4406
            /* union of two elemental sets */
alpar@1
  4407
            value = set_union(mpl,
alpar@1
  4408
               eval_elemset(mpl, code->arg.arg.x),
alpar@1
  4409
               eval_elemset(mpl, code->arg.arg.y));
alpar@1
  4410
            break;
alpar@1
  4411
         case O_DIFF:
alpar@1
  4412
            /* difference between two elemental sets */
alpar@1
  4413
            value = set_diff(mpl,
alpar@1
  4414
               eval_elemset(mpl, code->arg.arg.x),
alpar@1
  4415
               eval_elemset(mpl, code->arg.arg.y));
alpar@1
  4416
            break;
alpar@1
  4417
         case O_SYMDIFF:
alpar@1
  4418
            /* symmetric difference between two elemental sets */
alpar@1
  4419
            value = set_symdiff(mpl,
alpar@1
  4420
               eval_elemset(mpl, code->arg.arg.x),
alpar@1
  4421
               eval_elemset(mpl, code->arg.arg.y));
alpar@1
  4422
            break;
alpar@1
  4423
         case O_INTER:
alpar@1
  4424
            /* intersection of two elemental sets */
alpar@1
  4425
            value = set_inter(mpl,
alpar@1
  4426
               eval_elemset(mpl, code->arg.arg.x),
alpar@1
  4427
               eval_elemset(mpl, code->arg.arg.y));
alpar@1
  4428
            break;
alpar@1
  4429
         case O_CROSS:
alpar@1
  4430
            /* cross (Cartesian) product of two elemental sets */
alpar@1
  4431
            value = set_cross(mpl,
alpar@1
  4432
               eval_elemset(mpl, code->arg.arg.x),
alpar@1
  4433
               eval_elemset(mpl, code->arg.arg.y));
alpar@1
  4434
            break;
alpar@1
  4435
         case O_DOTS:
alpar@1
  4436
            /* build "arithmetic" elemental set */
alpar@1
  4437
            value = create_arelset(mpl,
alpar@1
  4438
               eval_numeric(mpl, code->arg.arg.x),
alpar@1
  4439
               eval_numeric(mpl, code->arg.arg.y),
alpar@1
  4440
               code->arg.arg.z == NULL ? 1.0 : eval_numeric(mpl,
alpar@1
  4441
                  code->arg.arg.z));
alpar@1
  4442
            break;
alpar@1
  4443
         case O_FORK:
alpar@1
  4444
            /* if-then-else */
alpar@1
  4445
            if (eval_logical(mpl, code->arg.arg.x))
alpar@1
  4446
               value = eval_elemset(mpl, code->arg.arg.y);
alpar@1
  4447
            else
alpar@1
  4448
               value = eval_elemset(mpl, code->arg.arg.z);
alpar@1
  4449
            break;
alpar@1
  4450
         case O_SETOF:
alpar@1
  4451
            /* compute elemental set */
alpar@1
  4452
            {  struct iter_set_info _info, *info = &_info;
alpar@1
  4453
               info->code = code;
alpar@1
  4454
               info->value = create_elemset(mpl, code->dim);
alpar@1
  4455
               loop_within_domain(mpl, code->arg.loop.domain, info,
alpar@1
  4456
                  iter_set_func);
alpar@1
  4457
               value = info->value;
alpar@1
  4458
            }
alpar@1
  4459
            break;
alpar@1
  4460
         case O_BUILD:
alpar@1
  4461
            /* build elemental set identical to domain set */
alpar@1
  4462
            {  struct iter_set_info _info, *info = &_info;
alpar@1
  4463
               info->code = code;
alpar@1
  4464
               info->value = create_elemset(mpl, code->dim);
alpar@1
  4465
               loop_within_domain(mpl, code->arg.loop.domain, info,
alpar@1
  4466
                  iter_set_func);
alpar@1
  4467
               value = info->value;
alpar@1
  4468
            }
alpar@1
  4469
            break;
alpar@1
  4470
         default:
alpar@1
  4471
            xassert(code != code);
alpar@1
  4472
      }
alpar@1
  4473
      /* save resultant value */
alpar@1
  4474
      xassert(!code->valid);
alpar@1
  4475
      code->valid = 1;
alpar@1
  4476
      code->value.set = copy_elemset(mpl, value);
alpar@1
  4477
done: return value;
alpar@1
  4478
}
alpar@1
  4479
alpar@1
  4480
/*----------------------------------------------------------------------
alpar@1
  4481
-- is_member - check if n-tuple is in set specified by pseudo-code.
alpar@1
  4482
--
alpar@1
  4483
-- This routine checks if given n-tuple is a member of elemental set
alpar@1
  4484
-- specified in the form of pseudo-code (i.e. by expression).
alpar@1
  4485
--
alpar@1
  4486
-- The n-tuple may have more components that dimension of the elemental
alpar@1
  4487
-- set, in which case the extra components are ignored. */
alpar@1
  4488
alpar@1
  4489
static void null_func(MPL *mpl, void *info)
alpar@1
  4490
{     /* this is dummy routine used to enter the domain scope */
alpar@1
  4491
      xassert(mpl == mpl);
alpar@1
  4492
      xassert(info == NULL);
alpar@1
  4493
      return;
alpar@1
  4494
}
alpar@1
  4495
alpar@1
  4496
int is_member(MPL *mpl, CODE *code, TUPLE *tuple)
alpar@1
  4497
{     int value;
alpar@1
  4498
      xassert(code != NULL);
alpar@1
  4499
      xassert(code->type == A_ELEMSET);
alpar@1
  4500
      xassert(code->dim > 0);
alpar@1
  4501
      xassert(tuple != NULL);
alpar@1
  4502
      switch (code->op)
alpar@1
  4503
      {  case O_MEMSET:
alpar@1
  4504
            /* check if given n-tuple is member of elemental set, which
alpar@1
  4505
               is assigned to member of model set */
alpar@1
  4506
            {  ARG_LIST *e;
alpar@1
  4507
               TUPLE *temp;
alpar@1
  4508
               ELEMSET *set;
alpar@1
  4509
               /* evaluate reference to elemental set */
alpar@1
  4510
               temp = create_tuple(mpl);
alpar@1
  4511
               for (e = code->arg.set.list; e != NULL; e = e->next)
alpar@1
  4512
                  temp = expand_tuple(mpl, temp, eval_symbolic(mpl,
alpar@1
  4513
                     e->x));
alpar@1
  4514
               set = eval_member_set(mpl, code->arg.set.set, temp);
alpar@1
  4515
               delete_tuple(mpl, temp);
alpar@1
  4516
               /* check if the n-tuple is contained in the set array */
alpar@1
  4517
               temp = build_subtuple(mpl, tuple, set->dim);
alpar@1
  4518
               value = (find_tuple(mpl, set, temp) != NULL);
alpar@1
  4519
               delete_tuple(mpl, temp);
alpar@1
  4520
            }
alpar@1
  4521
            break;
alpar@1
  4522
         case O_MAKE:
alpar@1
  4523
            /* check if given n-tuple is member of literal set */
alpar@1
  4524
            {  ARG_LIST *e;
alpar@1
  4525
               TUPLE *temp, *that;
alpar@1
  4526
               value = 0;
alpar@1
  4527
               temp = build_subtuple(mpl, tuple, code->dim);
alpar@1
  4528
               for (e = code->arg.list; e != NULL; e = e->next)
alpar@1
  4529
               {  that = eval_tuple(mpl, e->x);
alpar@1
  4530
                  value = (compare_tuples(mpl, temp, that) == 0);
alpar@1
  4531
                  delete_tuple(mpl, that);
alpar@1
  4532
                  if (value) break;
alpar@1
  4533
               }
alpar@1
  4534
               delete_tuple(mpl, temp);
alpar@1
  4535
            }
alpar@1
  4536
            break;
alpar@1
  4537
         case O_UNION:
alpar@1
  4538
            value = is_member(mpl, code->arg.arg.x, tuple) ||
alpar@1
  4539
                    is_member(mpl, code->arg.arg.y, tuple);
alpar@1
  4540
            break;
alpar@1
  4541
         case O_DIFF:
alpar@1
  4542
            value = is_member(mpl, code->arg.arg.x, tuple) &&
alpar@1
  4543
                   !is_member(mpl, code->arg.arg.y, tuple);
alpar@1
  4544
            break;
alpar@1
  4545
         case O_SYMDIFF:
alpar@1
  4546
            {  int in1 = is_member(mpl, code->arg.arg.x, tuple);
alpar@1
  4547
               int in2 = is_member(mpl, code->arg.arg.y, tuple);
alpar@1
  4548
               value = (in1 && !in2) || (!in1 && in2);
alpar@1
  4549
            }
alpar@1
  4550
            break;
alpar@1
  4551
         case O_INTER:
alpar@1
  4552
            value = is_member(mpl, code->arg.arg.x, tuple) &&
alpar@1
  4553
                    is_member(mpl, code->arg.arg.y, tuple);
alpar@1
  4554
            break;
alpar@1
  4555
         case O_CROSS:
alpar@1
  4556
            {  int j;
alpar@1
  4557
               value = is_member(mpl, code->arg.arg.x, tuple);
alpar@1
  4558
               if (value)
alpar@1
  4559
               {  for (j = 1; j <= code->arg.arg.x->dim; j++)
alpar@1
  4560
                  {  xassert(tuple != NULL);
alpar@1
  4561
                     tuple = tuple->next;
alpar@1
  4562
                  }
alpar@1
  4563
                  value = is_member(mpl, code->arg.arg.y, tuple);
alpar@1
  4564
               }
alpar@1
  4565
            }
alpar@1
  4566
            break;
alpar@1
  4567
         case O_DOTS:
alpar@1
  4568
            /* check if given 1-tuple is member of "arithmetic" set */
alpar@1
  4569
            {  int j;
alpar@1
  4570
               double x, t0, tf, dt;
alpar@1
  4571
               xassert(code->dim == 1);
alpar@1
  4572
               /* compute "parameters" of the "arithmetic" set */
alpar@1
  4573
               t0 = eval_numeric(mpl, code->arg.arg.x);
alpar@1
  4574
               tf = eval_numeric(mpl, code->arg.arg.y);
alpar@1
  4575
               if (code->arg.arg.z == NULL)
alpar@1
  4576
                  dt = 1.0;
alpar@1
  4577
               else
alpar@1
  4578
                  dt = eval_numeric(mpl, code->arg.arg.z);
alpar@1
  4579
               /* make sure the parameters are correct */
alpar@1
  4580
               arelset_size(mpl, t0, tf, dt);
alpar@1
  4581
               /* if component of 1-tuple is symbolic, not numeric, the
alpar@1
  4582
                  1-tuple cannot be member of "arithmetic" set */
alpar@1
  4583
               xassert(tuple->sym != NULL);
alpar@1
  4584
               if (tuple->sym->str != NULL)
alpar@1
  4585
               {  value = 0;
alpar@1
  4586
                  break;
alpar@1
  4587
               }
alpar@1
  4588
               /* determine numeric value of the component */
alpar@1
  4589
               x = tuple->sym->num;
alpar@1
  4590
               /* if the component value is out of the set range, the
alpar@1
  4591
                  1-tuple is not in the set */
alpar@1
  4592
               if (dt > 0.0 && !(t0 <= x && x <= tf) ||
alpar@1
  4593
                   dt < 0.0 && !(tf <= x && x <= t0))
alpar@1
  4594
               {  value = 0;
alpar@1
  4595
                  break;
alpar@1
  4596
               }
alpar@1
  4597
               /* estimate ordinal number of the 1-tuple in the set */
alpar@1
  4598
               j = (int)(((x - t0) / dt) + 0.5) + 1;
alpar@1
  4599
               /* perform the main check */
alpar@1
  4600
               value = (arelset_member(mpl, t0, tf, dt, j) == x);
alpar@1
  4601
            }
alpar@1
  4602
            break;
alpar@1
  4603
         case O_FORK:
alpar@1
  4604
            /* check if given n-tuple is member of conditional set */
alpar@1
  4605
            if (eval_logical(mpl, code->arg.arg.x))
alpar@1
  4606
               value = is_member(mpl, code->arg.arg.y, tuple);
alpar@1
  4607
            else
alpar@1
  4608
               value = is_member(mpl, code->arg.arg.z, tuple);
alpar@1
  4609
            break;
alpar@1
  4610
         case O_SETOF:
alpar@1
  4611
            /* check if given n-tuple is member of computed set */
alpar@1
  4612
            /* it is not clear how to efficiently perform the check not
alpar@1
  4613
               computing the entire elemental set :+( */
alpar@1
  4614
            error(mpl, "implementation restriction; in/within setof{} n"
alpar@1
  4615
               "ot allowed");
alpar@1
  4616
            break;
alpar@1
  4617
         case O_BUILD:
alpar@1
  4618
            /* check if given n-tuple is member of domain set */
alpar@1
  4619
            {  TUPLE *temp;
alpar@1
  4620
               temp = build_subtuple(mpl, tuple, code->dim);
alpar@1
  4621
               /* try to enter the domain scope; if it is successful,
alpar@1
  4622
                  the n-tuple is in the domain set */
alpar@1
  4623
               value = (eval_within_domain(mpl, code->arg.loop.domain,
alpar@1
  4624
                  temp, NULL, null_func) == 0);
alpar@1
  4625
               delete_tuple(mpl, temp);
alpar@1
  4626
            }
alpar@1
  4627
            break;
alpar@1
  4628
         default:
alpar@1
  4629
            xassert(code != code);
alpar@1
  4630
      }
alpar@1
  4631
      return value;
alpar@1
  4632
}
alpar@1
  4633
alpar@1
  4634
/*----------------------------------------------------------------------
alpar@1
  4635
-- eval_formula - evaluate pseudo-code to construct linear form.
alpar@1
  4636
--
alpar@1
  4637
-- This routine evaluates specified pseudo-code to construct resultant
alpar@1
  4638
-- linear form, which is returned on exit. */
alpar@1
  4639
alpar@1
  4640
struct iter_form_info
alpar@1
  4641
{     /* working info used by the routine iter_form_func */
alpar@1
  4642
      CODE *code;
alpar@1
  4643
      /* pseudo-code for iterated operation to be performed */
alpar@1
  4644
      FORMULA *value;
alpar@1
  4645
      /* resultant value */
alpar@1
  4646
      FORMULA *tail;
alpar@1
  4647
      /* pointer to the last term */
alpar@1
  4648
};
alpar@1
  4649
alpar@1
  4650
static int iter_form_func(MPL *mpl, void *_info)
alpar@1
  4651
{     /* this is auxiliary routine used to perform iterated operation
alpar@1
  4652
         on linear form "integrand" within domain scope */
alpar@1
  4653
      struct iter_form_info *info = _info;
alpar@1
  4654
      switch (info->code->op)
alpar@1
  4655
      {  case O_SUM:
alpar@1
  4656
            /* summation over domain */
alpar@1
  4657
#if 0
alpar@1
  4658
            info->value =
alpar@1
  4659
               linear_comb(mpl,
alpar@1
  4660
                  +1.0, info->value,
alpar@1
  4661
                  +1.0, eval_formula(mpl, info->code->arg.loop.x));
alpar@1
  4662
#else
alpar@1
  4663
            /* the routine linear_comb needs to look through all terms
alpar@1
  4664
               of both linear forms to reduce identical terms, so using
alpar@1
  4665
               it here is not a good idea (for example, evaluation of
alpar@1
  4666
               sum{i in 1..n} x[i] required quadratic time); the better
alpar@1
  4667
               idea is to gather all terms of the integrand in one list
alpar@1
  4668
               and reduce identical terms only once after all terms of
alpar@1
  4669
               the resultant linear form have been evaluated */
alpar@1
  4670
            {  FORMULA *form, *term;
alpar@1
  4671
               form = eval_formula(mpl, info->code->arg.loop.x);
alpar@1
  4672
               if (info->value == NULL)
alpar@1
  4673
               {  xassert(info->tail == NULL);
alpar@1
  4674
                  info->value = form;
alpar@1
  4675
               }
alpar@1
  4676
               else
alpar@1
  4677
               {  xassert(info->tail != NULL);
alpar@1
  4678
                  info->tail->next = form;
alpar@1
  4679
               }
alpar@1
  4680
               for (term = form; term != NULL; term = term->next)
alpar@1
  4681
                  info->tail = term;
alpar@1
  4682
            }
alpar@1
  4683
#endif
alpar@1
  4684
            break;
alpar@1
  4685
         default:
alpar@1
  4686
            xassert(info != info);
alpar@1
  4687
      }
alpar@1
  4688
      return 0;
alpar@1
  4689
}
alpar@1
  4690
alpar@1
  4691
FORMULA *eval_formula(MPL *mpl, CODE *code)
alpar@1
  4692
{     FORMULA *value;
alpar@1
  4693
      xassert(code != NULL);
alpar@1
  4694
      xassert(code->type == A_FORMULA);
alpar@1
  4695
      xassert(code->dim == 0);
alpar@1
  4696
      /* if the operation has a side effect, invalidate and delete the
alpar@1
  4697
         resultant value */
alpar@1
  4698
      if (code->vflag && code->valid)
alpar@1
  4699
      {  code->valid = 0;
alpar@1
  4700
         delete_value(mpl, code->type, &code->value);
alpar@1
  4701
      }
alpar@1
  4702
      /* if resultant value is valid, no evaluation is needed */
alpar@1
  4703
      if (code->valid)
alpar@1
  4704
      {  value = copy_formula(mpl, code->value.form);
alpar@1
  4705
         goto done;
alpar@1
  4706
      }
alpar@1
  4707
      /* evaluate pseudo-code recursively */
alpar@1
  4708
      switch (code->op)
alpar@1
  4709
      {  case O_MEMVAR:
alpar@1
  4710
            /* take member of variable */
alpar@1
  4711
            {  TUPLE *tuple;
alpar@1
  4712
               ARG_LIST *e;
alpar@1
  4713
               tuple = create_tuple(mpl);
alpar@1
  4714
               for (e = code->arg.var.list; e != NULL; e = e->next)
alpar@1
  4715
                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
alpar@1
  4716
                     e->x));
alpar@1
  4717
#if 1 /* 15/V-2010 */
alpar@1
  4718
               xassert(code->arg.var.suff == DOT_NONE);
alpar@1
  4719
#endif
alpar@1
  4720
               value = single_variable(mpl,
alpar@1
  4721
                  eval_member_var(mpl, code->arg.var.var, tuple));
alpar@1
  4722
               delete_tuple(mpl, tuple);
alpar@1
  4723
            }
alpar@1
  4724
            break;
alpar@1
  4725
         case O_CVTLFM:
alpar@1
  4726
            /* convert to linear form */
alpar@1
  4727
            value = constant_term(mpl, eval_numeric(mpl,
alpar@1
  4728
               code->arg.arg.x));
alpar@1
  4729
            break;
alpar@1
  4730
         case O_PLUS:
alpar@1
  4731
            /* unary plus */
alpar@1
  4732
            value = linear_comb(mpl,
alpar@1
  4733
                0.0, constant_term(mpl, 0.0),
alpar@1
  4734
               +1.0, eval_formula(mpl, code->arg.arg.x));
alpar@1
  4735
            break;
alpar@1
  4736
         case O_MINUS:
alpar@1
  4737
            /* unary minus */
alpar@1
  4738
            value = linear_comb(mpl,
alpar@1
  4739
                0.0, constant_term(mpl, 0.0),
alpar@1
  4740
               -1.0, eval_formula(mpl, code->arg.arg.x));
alpar@1
  4741
            break;
alpar@1
  4742
         case O_ADD:
alpar@1
  4743
            /* addition */
alpar@1
  4744
            value = linear_comb(mpl,
alpar@1
  4745
               +1.0, eval_formula(mpl, code->arg.arg.x),
alpar@1
  4746
               +1.0, eval_formula(mpl, code->arg.arg.y));
alpar@1
  4747
            break;
alpar@1
  4748
         case O_SUB:
alpar@1
  4749
            /* subtraction */
alpar@1
  4750
            value = linear_comb(mpl,
alpar@1
  4751
               +1.0, eval_formula(mpl, code->arg.arg.x),
alpar@1
  4752
               -1.0, eval_formula(mpl, code->arg.arg.y));
alpar@1
  4753
            break;
alpar@1
  4754
         case O_MUL:
alpar@1
  4755
            /* multiplication */
alpar@1
  4756
            xassert(code->arg.arg.x != NULL);
alpar@1
  4757
            xassert(code->arg.arg.y != NULL);
alpar@1
  4758
            if (code->arg.arg.x->type == A_NUMERIC)
alpar@1
  4759
            {  xassert(code->arg.arg.y->type == A_FORMULA);
alpar@1
  4760
               value = linear_comb(mpl,
alpar@1
  4761
                  eval_numeric(mpl, code->arg.arg.x),
alpar@1
  4762
                  eval_formula(mpl, code->arg.arg.y),
alpar@1
  4763
                  0.0, constant_term(mpl, 0.0));
alpar@1
  4764
            }
alpar@1
  4765
            else
alpar@1
  4766
            {  xassert(code->arg.arg.x->type == A_FORMULA);
alpar@1
  4767
               xassert(code->arg.arg.y->type == A_NUMERIC);
alpar@1
  4768
               value = linear_comb(mpl,
alpar@1
  4769
                  eval_numeric(mpl, code->arg.arg.y),
alpar@1
  4770
                  eval_formula(mpl, code->arg.arg.x),
alpar@1
  4771
                  0.0, constant_term(mpl, 0.0));
alpar@1
  4772
            }
alpar@1
  4773
            break;
alpar@1
  4774
         case O_DIV:
alpar@1
  4775
            /* division */
alpar@1
  4776
            value = linear_comb(mpl,
alpar@1
  4777
               fp_div(mpl, 1.0, eval_numeric(mpl, code->arg.arg.y)),
alpar@1
  4778
               eval_formula(mpl, code->arg.arg.x),
alpar@1
  4779
               0.0, constant_term(mpl, 0.0));
alpar@1
  4780
            break;
alpar@1
  4781
         case O_FORK:
alpar@1
  4782
            /* if-then-else */
alpar@1
  4783
            if (eval_logical(mpl, code->arg.arg.x))
alpar@1
  4784
               value = eval_formula(mpl, code->arg.arg.y);
alpar@1
  4785
            else if (code->arg.arg.z == NULL)
alpar@1
  4786
               value = constant_term(mpl, 0.0);
alpar@1
  4787
            else
alpar@1
  4788
               value = eval_formula(mpl, code->arg.arg.z);
alpar@1
  4789
            break;
alpar@1
  4790
         case O_SUM:
alpar@1
  4791
            /* summation over domain */
alpar@1
  4792
            {  struct iter_form_info _info, *info = &_info;
alpar@1
  4793
               info->code = code;
alpar@1
  4794
               info->value = constant_term(mpl, 0.0);
alpar@1
  4795
               info->tail = NULL;
alpar@1
  4796
               loop_within_domain(mpl, code->arg.loop.domain, info,
alpar@1
  4797
                  iter_form_func);
alpar@1
  4798
               value = reduce_terms(mpl, info->value);
alpar@1
  4799
            }
alpar@1
  4800
            break;
alpar@1
  4801
         default:
alpar@1
  4802
            xassert(code != code);
alpar@1
  4803
      }
alpar@1
  4804
      /* save resultant value */
alpar@1
  4805
      xassert(!code->valid);
alpar@1
  4806
      code->valid = 1;
alpar@1
  4807
      code->value.form = copy_formula(mpl, value);
alpar@1
  4808
done: return value;
alpar@1
  4809
}
alpar@1
  4810
alpar@1
  4811
/*----------------------------------------------------------------------
alpar@1
  4812
-- clean_code - clean pseudo-code.
alpar@1
  4813
--
alpar@1
  4814
-- This routine recursively cleans specified pseudo-code that assumes
alpar@1
  4815
-- deleting all temporary resultant values. */
alpar@1
  4816
alpar@1
  4817
void clean_code(MPL *mpl, CODE *code)
alpar@1
  4818
{     ARG_LIST *e;
alpar@1
  4819
      /* if no pseudo-code is specified, do nothing */
alpar@1
  4820
      if (code == NULL) goto done;
alpar@1
  4821
      /* if resultant value is valid (exists), delete it */
alpar@1
  4822
      if (code->valid)
alpar@1
  4823
      {  code->valid = 0;
alpar@1
  4824
         delete_value(mpl, code->type, &code->value);
alpar@1
  4825
      }
alpar@1
  4826
      /* recursively clean pseudo-code for operands */
alpar@1
  4827
      switch (code->op)
alpar@1
  4828
      {  case O_NUMBER:
alpar@1
  4829
         case O_STRING:
alpar@1
  4830
         case O_INDEX:
alpar@1
  4831
            break;
alpar@1
  4832
         case O_MEMNUM:
alpar@1
  4833
         case O_MEMSYM:
alpar@1
  4834
            for (e = code->arg.par.list; e != NULL; e = e->next)
alpar@1
  4835
               clean_code(mpl, e->x);
alpar@1
  4836
            break;
alpar@1
  4837
         case O_MEMSET:
alpar@1
  4838
            for (e = code->arg.set.list; e != NULL; e = e->next)
alpar@1
  4839
               clean_code(mpl, e->x);
alpar@1
  4840
            break;
alpar@1
  4841
         case O_MEMVAR:
alpar@1
  4842
            for (e = code->arg.var.list; e != NULL; e = e->next)
alpar@1
  4843
               clean_code(mpl, e->x);
alpar@1
  4844
            break;
alpar@1
  4845
#if 1 /* 15/V-2010 */
alpar@1
  4846
         case O_MEMCON:
alpar@1
  4847
            for (e = code->arg.con.list; e != NULL; e = e->next)
alpar@1
  4848
               clean_code(mpl, e->x);
alpar@1
  4849
            break;
alpar@1
  4850
#endif
alpar@1
  4851
         case O_TUPLE:
alpar@1
  4852
         case O_MAKE:
alpar@1
  4853
            for (e = code->arg.list; e != NULL; e = e->next)
alpar@1
  4854
               clean_code(mpl, e->x);
alpar@1
  4855
            break;
alpar@1
  4856
         case O_SLICE:
alpar@1
  4857
            xassert(code != code);
alpar@1
  4858
         case O_IRAND224:
alpar@1
  4859
         case O_UNIFORM01:
alpar@1
  4860
         case O_NORMAL01:
alpar@1
  4861
         case O_GMTIME:
alpar@1
  4862
            break;
alpar@1
  4863
         case O_CVTNUM:
alpar@1
  4864
         case O_CVTSYM:
alpar@1
  4865
         case O_CVTLOG:
alpar@1
  4866
         case O_CVTTUP:
alpar@1
  4867
         case O_CVTLFM:
alpar@1
  4868
         case O_PLUS:
alpar@1
  4869
         case O_MINUS:
alpar@1
  4870
         case O_NOT:
alpar@1
  4871
         case O_ABS:
alpar@1
  4872
         case O_CEIL:
alpar@1
  4873
         case O_FLOOR:
alpar@1
  4874
         case O_EXP:
alpar@1
  4875
         case O_LOG:
alpar@1
  4876
         case O_LOG10:
alpar@1
  4877
         case O_SQRT:
alpar@1
  4878
         case O_SIN:
alpar@1
  4879
         case O_COS:
alpar@1
  4880
         case O_ATAN:
alpar@1
  4881
         case O_ROUND:
alpar@1
  4882
         case O_TRUNC:
alpar@1
  4883
         case O_CARD:
alpar@1
  4884
         case O_LENGTH:
alpar@1
  4885
            /* unary operation */
alpar@1
  4886
            clean_code(mpl, code->arg.arg.x);
alpar@1
  4887
            break;
alpar@1
  4888
         case O_ADD:
alpar@1
  4889
         case O_SUB:
alpar@1
  4890
         case O_LESS:
alpar@1
  4891
         case O_MUL:
alpar@1
  4892
         case O_DIV:
alpar@1
  4893
         case O_IDIV:
alpar@1
  4894
         case O_MOD:
alpar@1
  4895
         case O_POWER:
alpar@1
  4896
         case O_ATAN2:
alpar@1
  4897
         case O_ROUND2:
alpar@1
  4898
         case O_TRUNC2:
alpar@1
  4899
         case O_UNIFORM:
alpar@1
  4900
         case O_NORMAL:
alpar@1
  4901
         case O_CONCAT:
alpar@1
  4902
         case O_LT:
alpar@1
  4903
         case O_LE:
alpar@1
  4904
         case O_EQ:
alpar@1
  4905
         case O_GE:
alpar@1
  4906
         case O_GT:
alpar@1
  4907
         case O_NE:
alpar@1
  4908
         case O_AND:
alpar@1
  4909
         case O_OR:
alpar@1
  4910
         case O_UNION:
alpar@1
  4911
         case O_DIFF:
alpar@1
  4912
         case O_SYMDIFF:
alpar@1
  4913
         case O_INTER:
alpar@1
  4914
         case O_CROSS:
alpar@1
  4915
         case O_IN:
alpar@1
  4916
         case O_NOTIN:
alpar@1
  4917
         case O_WITHIN:
alpar@1
  4918
         case O_NOTWITHIN:
alpar@1
  4919
         case O_SUBSTR:
alpar@1
  4920
         case O_STR2TIME:
alpar@1
  4921
         case O_TIME2STR:
alpar@1
  4922
            /* binary operation */
alpar@1
  4923
            clean_code(mpl, code->arg.arg.x);
alpar@1
  4924
            clean_code(mpl, code->arg.arg.y);
alpar@1
  4925
            break;
alpar@1
  4926
         case O_DOTS:
alpar@1
  4927
         case O_FORK:
alpar@1
  4928
         case O_SUBSTR3:
alpar@1
  4929
            /* ternary operation */
alpar@1
  4930
            clean_code(mpl, code->arg.arg.x);
alpar@1
  4931
            clean_code(mpl, code->arg.arg.y);
alpar@1
  4932
            clean_code(mpl, code->arg.arg.z);
alpar@1
  4933
            break;
alpar@1
  4934
         case O_MIN:
alpar@1
  4935
         case O_MAX:
alpar@1
  4936
            /* n-ary operation */
alpar@1
  4937
            for (e = code->arg.list; e != NULL; e = e->next)
alpar@1
  4938
               clean_code(mpl, e->x);
alpar@1
  4939
            break;
alpar@1
  4940
         case O_SUM:
alpar@1
  4941
         case O_PROD:
alpar@1
  4942
         case O_MINIMUM:
alpar@1
  4943
         case O_MAXIMUM:
alpar@1
  4944
         case O_FORALL:
alpar@1
  4945
         case O_EXISTS:
alpar@1
  4946
         case O_SETOF:
alpar@1
  4947
         case O_BUILD:
alpar@1
  4948
            /* iterated operation */
alpar@1
  4949
            clean_domain(mpl, code->arg.loop.domain);
alpar@1
  4950
            clean_code(mpl, code->arg.loop.x);
alpar@1
  4951
            break;
alpar@1
  4952
         default:
alpar@1
  4953
            xassert(code->op != code->op);
alpar@1
  4954
      }
alpar@1
  4955
done: return;
alpar@1
  4956
}
alpar@1
  4957
alpar@1
  4958
#if 1 /* 11/II-2008 */
alpar@1
  4959
/**********************************************************************/
alpar@1
  4960
/* * *                        DATA TABLES                         * * */
alpar@1
  4961
/**********************************************************************/
alpar@1
  4962
alpar@1
  4963
int mpl_tab_num_args(TABDCA *dca)
alpar@1
  4964
{     /* returns the number of arguments */
alpar@1
  4965
      return dca->na;
alpar@1
  4966
}
alpar@1
  4967
alpar@1
  4968
const char *mpl_tab_get_arg(TABDCA *dca, int k)
alpar@1
  4969
{     /* returns pointer to k-th argument */
alpar@1
  4970
      xassert(1 <= k && k <= dca->na);
alpar@1
  4971
      return dca->arg[k];
alpar@1
  4972
}
alpar@1
  4973
alpar@1
  4974
int mpl_tab_num_flds(TABDCA *dca)
alpar@1
  4975
{     /* returns the number of fields */
alpar@1
  4976
      return dca->nf;
alpar@1
  4977
}
alpar@1
  4978
alpar@1
  4979
const char *mpl_tab_get_name(TABDCA *dca, int k)
alpar@1
  4980
{     /* returns pointer to name of k-th field */
alpar@1
  4981
      xassert(1 <= k && k <= dca->nf);
alpar@1
  4982
      return dca->name[k];
alpar@1
  4983
}
alpar@1
  4984
alpar@1
  4985
int mpl_tab_get_type(TABDCA *dca, int k)
alpar@1
  4986
{     /* returns type of k-th field */
alpar@1
  4987
      xassert(1 <= k && k <= dca->nf);
alpar@1
  4988
      return dca->type[k];
alpar@1
  4989
}
alpar@1
  4990
alpar@1
  4991
double mpl_tab_get_num(TABDCA *dca, int k)
alpar@1
  4992
{     /* returns numeric value of k-th field */
alpar@1
  4993
      xassert(1 <= k && k <= dca->nf);
alpar@1
  4994
      xassert(dca->type[k] == 'N');
alpar@1
  4995
      return dca->num[k];
alpar@1
  4996
}
alpar@1
  4997
alpar@1
  4998
const char *mpl_tab_get_str(TABDCA *dca, int k)
alpar@1
  4999
{     /* returns pointer to string value of k-th field */
alpar@1
  5000
      xassert(1 <= k && k <= dca->nf);
alpar@1
  5001
      xassert(dca->type[k] == 'S');
alpar@1
  5002
      xassert(dca->str[k] != NULL);
alpar@1
  5003
      return dca->str[k];
alpar@1
  5004
}
alpar@1
  5005
alpar@1
  5006
void mpl_tab_set_num(TABDCA *dca, int k, double num)
alpar@1
  5007
{     /* assign numeric value to k-th field */
alpar@1
  5008
      xassert(1 <= k && k <= dca->nf);
alpar@1
  5009
      xassert(dca->type[k] == '?');
alpar@1
  5010
      dca->type[k] = 'N';
alpar@1
  5011
      dca->num[k] = num;
alpar@1
  5012
      return;
alpar@1
  5013
}
alpar@1
  5014
alpar@1
  5015
void mpl_tab_set_str(TABDCA *dca, int k, const char *str)
alpar@1
  5016
{     /* assign string value to k-th field */
alpar@1
  5017
      xassert(1 <= k && k <= dca->nf);
alpar@1
  5018
      xassert(dca->type[k] == '?');
alpar@1
  5019
      xassert(strlen(str) <= MAX_LENGTH);
alpar@1
  5020
      xassert(dca->str[k] != NULL);
alpar@1
  5021
      dca->type[k] = 'S';
alpar@1
  5022
      strcpy(dca->str[k], str);
alpar@1
  5023
      return;
alpar@1
  5024
}
alpar@1
  5025
alpar@1
  5026
static int write_func(MPL *mpl, void *info)
alpar@1
  5027
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  5028
      TABLE *tab = info;
alpar@1
  5029
      TABDCA *dca = mpl->dca;
alpar@1
  5030
      TABOUT *out;
alpar@1
  5031
      SYMBOL *sym;
alpar@1
  5032
      int k;
alpar@1
  5033
      char buf[MAX_LENGTH+1];
alpar@1
  5034
      /* evaluate field values */
alpar@1
  5035
      k = 0;
alpar@1
  5036
      for (out = tab->u.out.list; out != NULL; out = out->next)
alpar@1
  5037
      {  k++;
alpar@1
  5038
         switch (out->code->type)
alpar@1
  5039
         {  case A_NUMERIC:
alpar@1
  5040
               dca->type[k] = 'N';
alpar@1
  5041
               dca->num[k] = eval_numeric(mpl, out->code);
alpar@1
  5042
               dca->str[k][0] = '\0';
alpar@1
  5043
               break;
alpar@1
  5044
            case A_SYMBOLIC:
alpar@1
  5045
               sym = eval_symbolic(mpl, out->code);
alpar@1
  5046
               if (sym->str == NULL)
alpar@1
  5047
               {  dca->type[k] = 'N';
alpar@1
  5048
                  dca->num[k] = sym->num;
alpar@1
  5049
                  dca->str[k][0] = '\0';
alpar@1
  5050
               }
alpar@1
  5051
               else
alpar@1
  5052
               {  dca->type[k] = 'S';
alpar@1
  5053
                  dca->num[k] = 0.0;
alpar@1
  5054
                  fetch_string(mpl, sym->str, buf);
alpar@1
  5055
                  strcpy(dca->str[k], buf);
alpar@1
  5056
               }
alpar@1
  5057
               delete_symbol(mpl, sym);
alpar@1
  5058
               break;
alpar@1
  5059
            default:
alpar@1
  5060
               xassert(out != out);
alpar@1
  5061
         }
alpar@1
  5062
      }
alpar@1
  5063
      /* write record to output table */
alpar@1
  5064
      mpl_tab_drv_write(mpl);
alpar@1
  5065
      return 0;
alpar@1
  5066
}
alpar@1
  5067
alpar@1
  5068
void execute_table(MPL *mpl, TABLE *tab)
alpar@1
  5069
{     /* execute table statement */
alpar@1
  5070
      TABARG *arg;
alpar@1
  5071
      TABFLD *fld;
alpar@1
  5072
      TABIN *in;
alpar@1
  5073
      TABOUT *out;
alpar@1
  5074
      TABDCA *dca;
alpar@1
  5075
      SET *set;
alpar@1
  5076
      int k;
alpar@1
  5077
      char buf[MAX_LENGTH+1];
alpar@1
  5078
      /* allocate table driver communication area */
alpar@1
  5079
      xassert(mpl->dca == NULL);
alpar@1
  5080
      mpl->dca = dca = xmalloc(sizeof(TABDCA));
alpar@1
  5081
      dca->id = 0;
alpar@1
  5082
      dca->link = NULL;
alpar@1
  5083
      dca->na = 0;
alpar@1
  5084
      dca->arg = NULL;
alpar@1
  5085
      dca->nf = 0;
alpar@1
  5086
      dca->name = NULL;
alpar@1
  5087
      dca->type = NULL;
alpar@1
  5088
      dca->num = NULL;
alpar@1
  5089
      dca->str = NULL;
alpar@1
  5090
      /* allocate arguments */
alpar@1
  5091
      xassert(dca->na == 0);
alpar@1
  5092
      for (arg = tab->arg; arg != NULL; arg = arg->next)
alpar@1
  5093
         dca->na++;
alpar@1
  5094
      dca->arg = xcalloc(1+dca->na, sizeof(char *));
alpar@1
  5095
#if 1 /* 28/IX-2008 */
alpar@1
  5096
      for (k = 1; k <= dca->na; k++) dca->arg[k] = NULL;
alpar@1
  5097
#endif
alpar@1
  5098
      /* evaluate argument values */
alpar@1
  5099
      k = 0;
alpar@1
  5100
      for (arg = tab->arg; arg != NULL; arg = arg->next)
alpar@1
  5101
      {  SYMBOL *sym;
alpar@1
  5102
         k++;
alpar@1
  5103
         xassert(arg->code->type == A_SYMBOLIC);
alpar@1
  5104
         sym = eval_symbolic(mpl, arg->code);
alpar@1
  5105
         if (sym->str == NULL)
alpar@1
  5106
            sprintf(buf, "%.*g", DBL_DIG, sym->num);
alpar@1
  5107
         else
alpar@1
  5108
            fetch_string(mpl, sym->str, buf);
alpar@1
  5109
         delete_symbol(mpl, sym);
alpar@1
  5110
         dca->arg[k] = xmalloc(strlen(buf)+1);
alpar@1
  5111
         strcpy(dca->arg[k], buf);
alpar@1
  5112
      }
alpar@1
  5113
      /* perform table input/output */
alpar@1
  5114
      switch (tab->type)
alpar@1
  5115
      {  case A_INPUT:  goto read_table;
alpar@1
  5116
         case A_OUTPUT: goto write_table;
alpar@1
  5117
         default:       xassert(tab != tab);
alpar@1
  5118
      }
alpar@1
  5119
read_table:
alpar@1
  5120
      /* read data from input table */
alpar@1
  5121
      /* add the only member to the control set and assign it empty
alpar@1
  5122
         elemental set */
alpar@1
  5123
      set = tab->u.in.set;
alpar@1
  5124
      if (set != NULL)
alpar@1
  5125
      {  if (set->data)
alpar@1
  5126
            error(mpl, "%s already provided with data", set->name);
alpar@1
  5127
         xassert(set->array->head == NULL);
alpar@1
  5128
         add_member(mpl, set->array, NULL)->value.set =
alpar@1
  5129
            create_elemset(mpl, set->dimen);
alpar@1
  5130
         set->data = 1;
alpar@1
  5131
      }
alpar@1
  5132
      /* check parameters specified in the input list */
alpar@1
  5133
      for (in = tab->u.in.list; in != NULL; in = in->next)
alpar@1
  5134
      {  if (in->par->data)
alpar@1
  5135
            error(mpl, "%s already provided with data", in->par->name);
alpar@1
  5136
         in->par->data = 1;
alpar@1
  5137
      }
alpar@1
  5138
      /* allocate and initialize fields */
alpar@1
  5139
      xassert(dca->nf == 0);
alpar@1
  5140
      for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
alpar@1
  5141
         dca->nf++;
alpar@1
  5142
      for (in = tab->u.in.list; in != NULL; in = in->next)
alpar@1
  5143
         dca->nf++;
alpar@1
  5144
      dca->name = xcalloc(1+dca->nf, sizeof(char *));
alpar@1
  5145
      dca->type = xcalloc(1+dca->nf, sizeof(int));
alpar@1
  5146
      dca->num = xcalloc(1+dca->nf, sizeof(double));
alpar@1
  5147
      dca->str = xcalloc(1+dca->nf, sizeof(char *));
alpar@1
  5148
      k = 0;
alpar@1
  5149
      for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
alpar@1
  5150
      {  k++;
alpar@1
  5151
         dca->name[k] = fld->name;
alpar@1
  5152
         dca->type[k] = '?';
alpar@1
  5153
         dca->num[k] = 0.0;
alpar@1
  5154
         dca->str[k] = xmalloc(MAX_LENGTH+1);
alpar@1
  5155
         dca->str[k][0] = '\0';
alpar@1
  5156
      }
alpar@1
  5157
      for (in = tab->u.in.list; in != NULL; in = in->next)
alpar@1
  5158
      {  k++;
alpar@1
  5159
         dca->name[k] = in->name;
alpar@1
  5160
         dca->type[k] = '?';
alpar@1
  5161
         dca->num[k] = 0.0;
alpar@1
  5162
         dca->str[k] = xmalloc(MAX_LENGTH+1);
alpar@1
  5163
         dca->str[k][0] = '\0';
alpar@1
  5164
      }
alpar@1
  5165
      /* open input table */
alpar@1
  5166
      mpl_tab_drv_open(mpl, 'R');
alpar@1
  5167
      /* read and process records */
alpar@1
  5168
      for (;;)
alpar@1
  5169
      {  TUPLE *tup;
alpar@1
  5170
         /* reset field types */
alpar@1
  5171
         for (k = 1; k <= dca->nf; k++)
alpar@1
  5172
            dca->type[k] = '?';
alpar@1
  5173
         /* read next record */
alpar@1
  5174
         if (mpl_tab_drv_read(mpl)) break;
alpar@1
  5175
         /* all fields must be set by the driver */
alpar@1
  5176
         for (k = 1; k <= dca->nf; k++)
alpar@1
  5177
         {  if (dca->type[k] == '?')
alpar@1
  5178
               error(mpl, "field %s missing in input table",
alpar@1
  5179
                  dca->name[k]);
alpar@1
  5180
         }
alpar@1
  5181
         /* construct n-tuple */
alpar@1
  5182
         tup = create_tuple(mpl);
alpar@1
  5183
         k = 0;
alpar@1
  5184
         for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
alpar@1
  5185
         {  k++;
alpar@1
  5186
            xassert(k <= dca->nf);
alpar@1
  5187
            switch (dca->type[k])
alpar@1
  5188
            {  case 'N':
alpar@1
  5189
                  tup = expand_tuple(mpl, tup, create_symbol_num(mpl,
alpar@1
  5190
                     dca->num[k]));
alpar@1
  5191
                  break;
alpar@1
  5192
               case 'S':
alpar@1
  5193
                  xassert(strlen(dca->str[k]) <= MAX_LENGTH);
alpar@1
  5194
                  tup = expand_tuple(mpl, tup, create_symbol_str(mpl,
alpar@1
  5195
                     create_string(mpl, dca->str[k])));
alpar@1
  5196
                  break;
alpar@1
  5197
               default:
alpar@1
  5198
                  xassert(dca != dca);
alpar@1
  5199
            }
alpar@1
  5200
         }
alpar@1
  5201
         /* add n-tuple just read to the control set */
alpar@1
  5202
         if (tab->u.in.set != NULL)
alpar@1
  5203
            check_then_add(mpl, tab->u.in.set->array->head->value.set,
alpar@1
  5204
               copy_tuple(mpl, tup));
alpar@1
  5205
         /* assign values to the parameters in the input list */
alpar@1
  5206
         for (in = tab->u.in.list; in != NULL; in = in->next)
alpar@1
  5207
         {  MEMBER *memb;
alpar@1
  5208
            k++;
alpar@1
  5209
            xassert(k <= dca->nf);
alpar@1
  5210
            /* there must be no member with the same n-tuple */
alpar@1
  5211
            if (find_member(mpl, in->par->array, tup) != NULL)
alpar@1
  5212
               error(mpl, "%s%s already defined", in->par->name,
alpar@1
  5213
               format_tuple(mpl, '[', tup));
alpar@1
  5214
            /* create new parameter member with given n-tuple */
alpar@1
  5215
            memb = add_member(mpl, in->par->array, copy_tuple(mpl, tup))
alpar@1
  5216
               ;
alpar@1
  5217
            /* assign value to the parameter member */
alpar@1
  5218
            switch (in->par->type)
alpar@1
  5219
            {  case A_NUMERIC:
alpar@1
  5220
               case A_INTEGER:
alpar@1
  5221
               case A_BINARY:
alpar@1
  5222
                  if (dca->type[k] != 'N')
alpar@1
  5223
                     error(mpl, "%s requires numeric data",
alpar@1
  5224
                        in->par->name);
alpar@1
  5225
                  memb->value.num = dca->num[k];
alpar@1
  5226
                  break;
alpar@1
  5227
               case A_SYMBOLIC:
alpar@1
  5228
                  switch (dca->type[k])
alpar@1
  5229
                  {  case 'N':
alpar@1
  5230
                        memb->value.sym = create_symbol_num(mpl,
alpar@1
  5231
                           dca->num[k]);
alpar@1
  5232
                        break;
alpar@1
  5233
                     case 'S':
alpar@1
  5234
                        xassert(strlen(dca->str[k]) <= MAX_LENGTH);
alpar@1
  5235
                        memb->value.sym = create_symbol_str(mpl,
alpar@1
  5236
                           create_string(mpl,dca->str[k]));
alpar@1
  5237
                        break;
alpar@1
  5238
                     default:
alpar@1
  5239
                        xassert(dca != dca);
alpar@1
  5240
                  }
alpar@1
  5241
                  break;
alpar@1
  5242
               default:
alpar@1
  5243
                  xassert(in != in);
alpar@1
  5244
            }
alpar@1
  5245
         }
alpar@1
  5246
         /* n-tuple is no more needed */
alpar@1
  5247
         delete_tuple(mpl, tup);
alpar@1
  5248
      }
alpar@1
  5249
      /* close input table */
alpar@1
  5250
      mpl_tab_drv_close(mpl);
alpar@1
  5251
      goto done;
alpar@1
  5252
write_table:
alpar@1
  5253
      /* write data to output table */
alpar@1
  5254
      /* allocate and initialize fields */
alpar@1
  5255
      xassert(dca->nf == 0);
alpar@1
  5256
      for (out = tab->u.out.list; out != NULL; out = out->next)
alpar@1
  5257
         dca->nf++;
alpar@1
  5258
      dca->name = xcalloc(1+dca->nf, sizeof(char *));
alpar@1
  5259
      dca->type = xcalloc(1+dca->nf, sizeof(int));
alpar@1
  5260
      dca->num = xcalloc(1+dca->nf, sizeof(double));
alpar@1
  5261
      dca->str = xcalloc(1+dca->nf, sizeof(char *));
alpar@1
  5262
      k = 0;
alpar@1
  5263
      for (out = tab->u.out.list; out != NULL; out = out->next)
alpar@1
  5264
      {  k++;
alpar@1
  5265
         dca->name[k] = out->name;
alpar@1
  5266
         dca->type[k] = '?';
alpar@1
  5267
         dca->num[k] = 0.0;
alpar@1
  5268
         dca->str[k] = xmalloc(MAX_LENGTH+1);
alpar@1
  5269
         dca->str[k][0] = '\0';
alpar@1
  5270
      }
alpar@1
  5271
      /* open output table */
alpar@1
  5272
      mpl_tab_drv_open(mpl, 'W');
alpar@1
  5273
      /* evaluate fields and write records */
alpar@1
  5274
      loop_within_domain(mpl, tab->u.out.domain, tab, write_func);
alpar@1
  5275
      /* close output table */
alpar@1
  5276
      mpl_tab_drv_close(mpl);
alpar@1
  5277
done: /* free table driver communication area */
alpar@1
  5278
      free_dca(mpl);
alpar@1
  5279
      return;
alpar@1
  5280
}
alpar@1
  5281
alpar@1
  5282
void free_dca(MPL *mpl)
alpar@1
  5283
{     /* free table driver communucation area */
alpar@1
  5284
      TABDCA *dca = mpl->dca;
alpar@1
  5285
      int k;
alpar@1
  5286
      if (dca != NULL)
alpar@1
  5287
      {  if (dca->link != NULL)
alpar@1
  5288
            mpl_tab_drv_close(mpl);
alpar@1
  5289
         if (dca->arg != NULL)
alpar@1
  5290
         {  for (k = 1; k <= dca->na; k++)
alpar@1
  5291
#if 1 /* 28/IX-2008 */
alpar@1
  5292
               if (dca->arg[k] != NULL)
alpar@1
  5293
#endif
alpar@1
  5294
               xfree(dca->arg[k]);
alpar@1
  5295
            xfree(dca->arg);
alpar@1
  5296
         }
alpar@1
  5297
         if (dca->name != NULL) xfree(dca->name);
alpar@1
  5298
         if (dca->type != NULL) xfree(dca->type);
alpar@1
  5299
         if (dca->num != NULL) xfree(dca->num);
alpar@1
  5300
         if (dca->str != NULL)
alpar@1
  5301
         {  for (k = 1; k <= dca->nf; k++)
alpar@1
  5302
               xfree(dca->str[k]);
alpar@1
  5303
            xfree(dca->str);
alpar@1
  5304
         }
alpar@1
  5305
         xfree(dca), mpl->dca = NULL;
alpar@1
  5306
      }
alpar@1
  5307
      return;
alpar@1
  5308
}
alpar@1
  5309
alpar@1
  5310
void clean_table(MPL *mpl, TABLE *tab)
alpar@1
  5311
{     /* clean table statement */
alpar@1
  5312
      TABARG *arg;
alpar@1
  5313
      TABOUT *out;
alpar@1
  5314
      /* clean string list */
alpar@1
  5315
      for (arg = tab->arg; arg != NULL; arg = arg->next)
alpar@1
  5316
         clean_code(mpl, arg->code);
alpar@1
  5317
      switch (tab->type)
alpar@1
  5318
      {  case A_INPUT:
alpar@1
  5319
            break;
alpar@1
  5320
         case A_OUTPUT:
alpar@1
  5321
            /* clean subscript domain */
alpar@1
  5322
            clean_domain(mpl, tab->u.out.domain);
alpar@1
  5323
            /* clean output list */
alpar@1
  5324
            for (out = tab->u.out.list; out != NULL; out = out->next)
alpar@1
  5325
               clean_code(mpl, out->code);
alpar@1
  5326
            break;
alpar@1
  5327
         default:
alpar@1
  5328
            xassert(tab != tab);
alpar@1
  5329
      }
alpar@1
  5330
      return;
alpar@1
  5331
}
alpar@1
  5332
#endif
alpar@1
  5333
alpar@1
  5334
/**********************************************************************/
alpar@1
  5335
/* * *                      MODEL STATEMENTS                      * * */
alpar@1
  5336
/**********************************************************************/
alpar@1
  5337
alpar@1
  5338
/*----------------------------------------------------------------------
alpar@1
  5339
-- execute_check - execute check statement.
alpar@1
  5340
--
alpar@1
  5341
-- This routine executes specified check statement. */
alpar@1
  5342
alpar@1
  5343
static int check_func(MPL *mpl, void *info)
alpar@1
  5344
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  5345
      CHECK *chk = (CHECK *)info;
alpar@1
  5346
      if (!eval_logical(mpl, chk->code))
alpar@1
  5347
         error(mpl, "check%s failed", format_tuple(mpl, '[',
alpar@1
  5348
            get_domain_tuple(mpl, chk->domain)));
alpar@1
  5349
      return 0;
alpar@1
  5350
}
alpar@1
  5351
alpar@1
  5352
void execute_check(MPL *mpl, CHECK *chk)
alpar@1
  5353
{     loop_within_domain(mpl, chk->domain, chk, check_func);
alpar@1
  5354
      return;
alpar@1
  5355
}
alpar@1
  5356
alpar@1
  5357
/*----------------------------------------------------------------------
alpar@1
  5358
-- clean_check - clean check statement.
alpar@1
  5359
--
alpar@1
  5360
-- This routine cleans specified check statement that assumes deleting
alpar@1
  5361
-- all stuff dynamically allocated on generating/postsolving phase. */
alpar@1
  5362
alpar@1
  5363
void clean_check(MPL *mpl, CHECK *chk)
alpar@1
  5364
{     /* clean subscript domain */
alpar@1
  5365
      clean_domain(mpl, chk->domain);
alpar@1
  5366
      /* clean pseudo-code for computing predicate */
alpar@1
  5367
      clean_code(mpl, chk->code);
alpar@1
  5368
      return;
alpar@1
  5369
}
alpar@1
  5370
alpar@1
  5371
/*----------------------------------------------------------------------
alpar@1
  5372
-- execute_display - execute display statement.
alpar@1
  5373
--
alpar@1
  5374
-- This routine executes specified display statement. */
alpar@1
  5375
alpar@1
  5376
static void display_set(MPL *mpl, SET *set, MEMBER *memb)
alpar@1
  5377
{     /* display member of model set */
alpar@1
  5378
      ELEMSET *s = memb->value.set;
alpar@1
  5379
      MEMBER *m;
alpar@1
  5380
      write_text(mpl, "%s%s%s\n", set->name,
alpar@1
  5381
         format_tuple(mpl, '[', memb->tuple),
alpar@1
  5382
         s->head == NULL ? " is empty" : ":");
alpar@1
  5383
      for (m = s->head; m != NULL; m = m->next)
alpar@1
  5384
         write_text(mpl, "   %s\n", format_tuple(mpl, '(', m->tuple));
alpar@1
  5385
      return;
alpar@1
  5386
}
alpar@1
  5387
alpar@1
  5388
static void display_par(MPL *mpl, PARAMETER *par, MEMBER *memb)
alpar@1
  5389
{     /* display member of model parameter */
alpar@1
  5390
      switch (par->type)
alpar@1
  5391
      {  case A_NUMERIC:
alpar@1
  5392
         case A_INTEGER:
alpar@1
  5393
         case A_BINARY:
alpar@1
  5394
            write_text(mpl, "%s%s = %.*g\n", par->name,
alpar@1
  5395
               format_tuple(mpl, '[', memb->tuple),
alpar@1
  5396
               DBL_DIG, memb->value.num);
alpar@1
  5397
            break;
alpar@1
  5398
         case A_SYMBOLIC:
alpar@1
  5399
            write_text(mpl, "%s%s = %s\n", par->name,
alpar@1
  5400
               format_tuple(mpl, '[', memb->tuple),
alpar@1
  5401
               format_symbol(mpl, memb->value.sym));
alpar@1
  5402
            break;
alpar@1
  5403
         default:
alpar@1
  5404
            xassert(par != par);
alpar@1
  5405
      }
alpar@1
  5406
      return;
alpar@1
  5407
}
alpar@1
  5408
alpar@1
  5409
#if 1 /* 15/V-2010 */
alpar@1
  5410
static void display_var(MPL *mpl, VARIABLE *var, MEMBER *memb,
alpar@1
  5411
      int suff)
alpar@1
  5412
{     /* display member of model variable */
alpar@1
  5413
      if (suff == DOT_NONE || suff == DOT_VAL)
alpar@1
  5414
         write_text(mpl, "%s%s.val = %.*g\n", var->name,
alpar@1
  5415
            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
alpar@1
  5416
            memb->value.var->prim);
alpar@1
  5417
      else if (suff == DOT_LB)
alpar@1
  5418
         write_text(mpl, "%s%s.lb = %.*g\n", var->name,
alpar@1
  5419
            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
alpar@1
  5420
            memb->value.var->var->lbnd == NULL ? -DBL_MAX :
alpar@1
  5421
            memb->value.var->lbnd);
alpar@1
  5422
      else if (suff == DOT_UB)
alpar@1
  5423
         write_text(mpl, "%s%s.ub = %.*g\n", var->name,
alpar@1
  5424
            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
alpar@1
  5425
            memb->value.var->var->ubnd == NULL ? +DBL_MAX :
alpar@1
  5426
            memb->value.var->ubnd);
alpar@1
  5427
      else if (suff == DOT_STATUS)
alpar@1
  5428
         write_text(mpl, "%s%s.status = %d\n", var->name, format_tuple
alpar@1
  5429
            (mpl, '[', memb->tuple), memb->value.var->stat);
alpar@1
  5430
      else if (suff == DOT_DUAL)
alpar@1
  5431
         write_text(mpl, "%s%s.dual = %.*g\n", var->name,
alpar@1
  5432
            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
alpar@1
  5433
            memb->value.var->dual);
alpar@1
  5434
      else
alpar@1
  5435
         xassert(suff != suff);
alpar@1
  5436
      return;
alpar@1
  5437
}
alpar@1
  5438
#endif
alpar@1
  5439
alpar@1
  5440
#if 1 /* 15/V-2010 */
alpar@1
  5441
static void display_con(MPL *mpl, CONSTRAINT *con, MEMBER *memb,
alpar@1
  5442
      int suff)
alpar@1
  5443
{     /* display member of model constraint */
alpar@1
  5444
      if (suff == DOT_NONE || suff == DOT_VAL)
alpar@1
  5445
         write_text(mpl, "%s%s.val = %.*g\n", con->name,
alpar@1
  5446
            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
alpar@1
  5447
            memb->value.con->prim);
alpar@1
  5448
      else if (suff == DOT_LB)
alpar@1
  5449
         write_text(mpl, "%s%s.lb = %.*g\n", con->name,
alpar@1
  5450
            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
alpar@1
  5451
            memb->value.con->con->lbnd == NULL ? -DBL_MAX :
alpar@1
  5452
            memb->value.con->lbnd);
alpar@1
  5453
      else if (suff == DOT_UB)
alpar@1
  5454
         write_text(mpl, "%s%s.ub = %.*g\n", con->name,
alpar@1
  5455
            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
alpar@1
  5456
            memb->value.con->con->ubnd == NULL ? +DBL_MAX :
alpar@1
  5457
            memb->value.con->ubnd);
alpar@1
  5458
      else if (suff == DOT_STATUS)
alpar@1
  5459
         write_text(mpl, "%s%s.status = %d\n", con->name, format_tuple
alpar@1
  5460
            (mpl, '[', memb->tuple), memb->value.con->stat);
alpar@1
  5461
      else if (suff == DOT_DUAL)
alpar@1
  5462
         write_text(mpl, "%s%s.dual = %.*g\n", con->name,
alpar@1
  5463
            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
alpar@1
  5464
            memb->value.con->dual);
alpar@1
  5465
      else
alpar@1
  5466
         xassert(suff != suff);
alpar@1
  5467
      return;
alpar@1
  5468
}
alpar@1
  5469
#endif
alpar@1
  5470
alpar@1
  5471
static void display_memb(MPL *mpl, CODE *code)
alpar@1
  5472
{     /* display member specified by pseudo-code */
alpar@1
  5473
      MEMBER memb;
alpar@1
  5474
      ARG_LIST *e;
alpar@1
  5475
      xassert(code->op == O_MEMNUM || code->op == O_MEMSYM
alpar@1
  5476
         || code->op == O_MEMSET || code->op == O_MEMVAR
alpar@1
  5477
         || code->op == O_MEMCON);
alpar@1
  5478
      memb.tuple = create_tuple(mpl);
alpar@1
  5479
      for (e = code->arg.par.list; e != NULL; e = e->next)
alpar@1
  5480
         memb.tuple = expand_tuple(mpl, memb.tuple, eval_symbolic(mpl,
alpar@1
  5481
            e->x));
alpar@1
  5482
      switch (code->op)
alpar@1
  5483
      {  case O_MEMNUM:
alpar@1
  5484
            memb.value.num = eval_member_num(mpl, code->arg.par.par,
alpar@1
  5485
               memb.tuple);
alpar@1
  5486
            display_par(mpl, code->arg.par.par, &memb);
alpar@1
  5487
            break;
alpar@1
  5488
         case O_MEMSYM:
alpar@1
  5489
            memb.value.sym = eval_member_sym(mpl, code->arg.par.par,
alpar@1
  5490
               memb.tuple);
alpar@1
  5491
            display_par(mpl, code->arg.par.par, &memb);
alpar@1
  5492
            delete_symbol(mpl, memb.value.sym);
alpar@1
  5493
            break;
alpar@1
  5494
         case O_MEMSET:
alpar@1
  5495
            memb.value.set = eval_member_set(mpl, code->arg.set.set,
alpar@1
  5496
               memb.tuple);
alpar@1
  5497
            display_set(mpl, code->arg.set.set, &memb);
alpar@1
  5498
            break;
alpar@1
  5499
         case O_MEMVAR:
alpar@1
  5500
            memb.value.var = eval_member_var(mpl, code->arg.var.var,
alpar@1
  5501
               memb.tuple);
alpar@1
  5502
            display_var
alpar@1
  5503
               (mpl, code->arg.var.var, &memb, code->arg.var.suff);
alpar@1
  5504
            break;
alpar@1
  5505
         case O_MEMCON:
alpar@1
  5506
            memb.value.con = eval_member_con(mpl, code->arg.con.con,
alpar@1
  5507
               memb.tuple);
alpar@1
  5508
            display_con
alpar@1
  5509
               (mpl, code->arg.con.con, &memb, code->arg.con.suff);
alpar@1
  5510
            break;
alpar@1
  5511
         default:
alpar@1
  5512
            xassert(code != code);
alpar@1
  5513
      }
alpar@1
  5514
      delete_tuple(mpl, memb.tuple);
alpar@1
  5515
      return;
alpar@1
  5516
}
alpar@1
  5517
alpar@1
  5518
static void display_code(MPL *mpl, CODE *code)
alpar@1
  5519
{     /* display value of expression */
alpar@1
  5520
      switch (code->type)
alpar@1
  5521
      {  case A_NUMERIC:
alpar@1
  5522
            /* numeric value */
alpar@1
  5523
            {  double num;
alpar@1
  5524
               num = eval_numeric(mpl, code);
alpar@1
  5525
               write_text(mpl, "%.*g\n", DBL_DIG, num);
alpar@1
  5526
            }
alpar@1
  5527
            break;
alpar@1
  5528
         case A_SYMBOLIC:
alpar@1
  5529
            /* symbolic value */
alpar@1
  5530
            {  SYMBOL *sym;
alpar@1
  5531
               sym = eval_symbolic(mpl, code);
alpar@1
  5532
               write_text(mpl, "%s\n", format_symbol(mpl, sym));
alpar@1
  5533
               delete_symbol(mpl, sym);
alpar@1
  5534
            }
alpar@1
  5535
            break;
alpar@1
  5536
         case A_LOGICAL:
alpar@1
  5537
            /* logical value */
alpar@1
  5538
            {  int bit;
alpar@1
  5539
               bit = eval_logical(mpl, code);
alpar@1
  5540
               write_text(mpl, "%s\n", bit ? "true" : "false");
alpar@1
  5541
            }
alpar@1
  5542
            break;
alpar@1
  5543
         case A_TUPLE:
alpar@1
  5544
            /* n-tuple */
alpar@1
  5545
            {  TUPLE *tuple;
alpar@1
  5546
               tuple = eval_tuple(mpl, code);
alpar@1
  5547
               write_text(mpl, "%s\n", format_tuple(mpl, '(', tuple));
alpar@1
  5548
               delete_tuple(mpl, tuple);
alpar@1
  5549
            }
alpar@1
  5550
            break;
alpar@1
  5551
         case A_ELEMSET:
alpar@1
  5552
            /* elemental set */
alpar@1
  5553
            {  ELEMSET *set;
alpar@1
  5554
               MEMBER *memb;
alpar@1
  5555
               set = eval_elemset(mpl, code);
alpar@1
  5556
               if (set->head == 0)
alpar@1
  5557
                  write_text(mpl, "set is empty\n");
alpar@1
  5558
               for (memb = set->head; memb != NULL; memb = memb->next)
alpar@1
  5559
                  write_text(mpl, "   %s\n", format_tuple(mpl, '(',
alpar@1
  5560
                     memb->tuple));
alpar@1
  5561
               delete_elemset(mpl, set);
alpar@1
  5562
            }
alpar@1
  5563
            break;
alpar@1
  5564
         case A_FORMULA:
alpar@1
  5565
            /* linear form */
alpar@1
  5566
            {  FORMULA *form, *term;
alpar@1
  5567
               form = eval_formula(mpl, code);
alpar@1
  5568
               if (form == NULL)
alpar@1
  5569
                  write_text(mpl, "linear form is empty\n");
alpar@1
  5570
               for (term = form; term != NULL; term = term->next)
alpar@1
  5571
               {  if (term->var == NULL)
alpar@1
  5572
                     write_text(mpl, "   %.*g\n", term->coef);
alpar@1
  5573
                  else
alpar@1
  5574
                     write_text(mpl, "   %.*g %s%s\n", DBL_DIG,
alpar@1
  5575
                        term->coef, term->var->var->name,
alpar@1
  5576
                        format_tuple(mpl, '[', term->var->memb->tuple));
alpar@1
  5577
               }
alpar@1
  5578
               delete_formula(mpl, form);
alpar@1
  5579
            }
alpar@1
  5580
            break;
alpar@1
  5581
         default:
alpar@1
  5582
            xassert(code != code);
alpar@1
  5583
      }
alpar@1
  5584
      return;
alpar@1
  5585
}
alpar@1
  5586
alpar@1
  5587
static int display_func(MPL *mpl, void *info)
alpar@1
  5588
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  5589
      DISPLAY *dpy = (DISPLAY *)info;
alpar@1
  5590
      DISPLAY1 *entry;
alpar@1
  5591
      for (entry = dpy->list; entry != NULL; entry = entry->next)
alpar@1
  5592
      {  if (entry->type == A_INDEX)
alpar@1
  5593
         {  /* dummy index */
alpar@1
  5594
            DOMAIN_SLOT *slot = entry->u.slot;
alpar@1
  5595
            write_text(mpl, "%s = %s\n", slot->name,
alpar@1
  5596
            format_symbol(mpl, slot->value));
alpar@1
  5597
         }
alpar@1
  5598
         else if (entry->type == A_SET)
alpar@1
  5599
         {  /* model set */
alpar@1
  5600
            SET *set = entry->u.set;
alpar@1
  5601
            MEMBER *memb;
alpar@1
  5602
            if (set->assign != NULL)
alpar@1
  5603
            {  /* the set has assignment expression; evaluate all its
alpar@1
  5604
                  members over entire domain */
alpar@1
  5605
               eval_whole_set(mpl, set);
alpar@1
  5606
            }
alpar@1
  5607
            else
alpar@1
  5608
            {  /* the set has no assignment expression; refer to its
alpar@1
  5609
                  any existing member ignoring resultant value to check
alpar@1
  5610
                  the data provided the data section */
alpar@1
  5611
#if 1 /* 12/XII-2008 */
alpar@1
  5612
               if (set->gadget != NULL && set->data == 0)
alpar@1
  5613
               {  /* initialize the set with data from a plain set */
alpar@1
  5614
                  saturate_set(mpl, set);
alpar@1
  5615
               }
alpar@1
  5616
#endif
alpar@1
  5617
               if (set->array->head != NULL)
alpar@1
  5618
                  eval_member_set(mpl, set, set->array->head->tuple);
alpar@1
  5619
            }
alpar@1
  5620
            /* display all members of the set array */
alpar@1
  5621
            if (set->array->head == NULL)
alpar@1
  5622
               write_text(mpl, "%s has empty content\n", set->name);
alpar@1
  5623
            for (memb = set->array->head; memb != NULL; memb =
alpar@1
  5624
               memb->next) display_set(mpl, set, memb);
alpar@1
  5625
         }
alpar@1
  5626
         else if (entry->type == A_PARAMETER)
alpar@1
  5627
         {  /* model parameter */
alpar@1
  5628
            PARAMETER *par = entry->u.par;
alpar@1
  5629
            MEMBER *memb;
alpar@1
  5630
            if (par->assign != NULL)
alpar@1
  5631
            {  /* the parameter has an assignment expression; evaluate
alpar@1
  5632
                  all its member over entire domain */
alpar@1
  5633
               eval_whole_par(mpl, par);
alpar@1
  5634
            }
alpar@1
  5635
            else
alpar@1
  5636
            {  /* the parameter has no assignment expression; refer to
alpar@1
  5637
                  its any existing member ignoring resultant value to
alpar@1
  5638
                  check the data provided in the data section */
alpar@1
  5639
               if (par->array->head != NULL)
alpar@1
  5640
               {  if (par->type != A_SYMBOLIC)
alpar@1
  5641
                     eval_member_num(mpl, par, par->array->head->tuple);
alpar@1
  5642
                  else
alpar@1
  5643
                     delete_symbol(mpl, eval_member_sym(mpl, par,
alpar@1
  5644
                        par->array->head->tuple));
alpar@1
  5645
               }
alpar@1
  5646
            }
alpar@1
  5647
            /* display all members of the parameter array */
alpar@1
  5648
            if (par->array->head == NULL)
alpar@1
  5649
               write_text(mpl, "%s has empty content\n", par->name);
alpar@1
  5650
            for (memb = par->array->head; memb != NULL; memb =
alpar@1
  5651
               memb->next) display_par(mpl, par, memb);
alpar@1
  5652
         }
alpar@1
  5653
         else if (entry->type == A_VARIABLE)
alpar@1
  5654
         {  /* model variable */
alpar@1
  5655
            VARIABLE *var = entry->u.var;
alpar@1
  5656
            MEMBER *memb;
alpar@1
  5657
            xassert(mpl->flag_p);
alpar@1
  5658
            /* display all members of the variable array */
alpar@1
  5659
            if (var->array->head == NULL)
alpar@1
  5660
               write_text(mpl, "%s has empty content\n", var->name);
alpar@1
  5661
            for (memb = var->array->head; memb != NULL; memb =
alpar@1
  5662
               memb->next) display_var(mpl, var, memb, DOT_NONE);
alpar@1
  5663
         }
alpar@1
  5664
         else if (entry->type == A_CONSTRAINT)
alpar@1
  5665
         {  /* model constraint */
alpar@1
  5666
            CONSTRAINT *con = entry->u.con;
alpar@1
  5667
            MEMBER *memb;
alpar@1
  5668
            xassert(mpl->flag_p);
alpar@1
  5669
            /* display all members of the constraint array */
alpar@1
  5670
            if (con->array->head == NULL)
alpar@1
  5671
               write_text(mpl, "%s has empty content\n", con->name);
alpar@1
  5672
            for (memb = con->array->head; memb != NULL; memb =
alpar@1
  5673
               memb->next) display_con(mpl, con, memb, DOT_NONE);
alpar@1
  5674
         }
alpar@1
  5675
         else if (entry->type == A_EXPRESSION)
alpar@1
  5676
         {  /* expression */
alpar@1
  5677
            CODE *code = entry->u.code;
alpar@1
  5678
            if (code->op == O_MEMNUM || code->op == O_MEMSYM ||
alpar@1
  5679
                code->op == O_MEMSET || code->op == O_MEMVAR ||
alpar@1
  5680
                code->op == O_MEMCON)
alpar@1
  5681
               display_memb(mpl, code);
alpar@1
  5682
            else
alpar@1
  5683
               display_code(mpl, code);
alpar@1
  5684
         }
alpar@1
  5685
         else
alpar@1
  5686
            xassert(entry != entry);
alpar@1
  5687
      }
alpar@1
  5688
      return 0;
alpar@1
  5689
}
alpar@1
  5690
alpar@1
  5691
void execute_display(MPL *mpl, DISPLAY *dpy)
alpar@1
  5692
{     loop_within_domain(mpl, dpy->domain, dpy, display_func);
alpar@1
  5693
      return;
alpar@1
  5694
}
alpar@1
  5695
alpar@1
  5696
/*----------------------------------------------------------------------
alpar@1
  5697
-- clean_display - clean display statement.
alpar@1
  5698
--
alpar@1
  5699
-- This routine cleans specified display statement that assumes deleting
alpar@1
  5700
-- all stuff dynamically allocated on generating/postsolving phase. */
alpar@1
  5701
alpar@1
  5702
void clean_display(MPL *mpl, DISPLAY *dpy)
alpar@1
  5703
{     DISPLAY1 *d;
alpar@1
  5704
#if 0 /* 15/V-2010 */
alpar@1
  5705
      ARG_LIST *e;
alpar@1
  5706
#endif
alpar@1
  5707
      /* clean subscript domain */
alpar@1
  5708
      clean_domain(mpl, dpy->domain);
alpar@1
  5709
      /* clean display list */
alpar@1
  5710
      for (d = dpy->list; d != NULL; d = d->next)
alpar@1
  5711
      {  /* clean pseudo-code for computing expression */
alpar@1
  5712
         if (d->type == A_EXPRESSION)
alpar@1
  5713
            clean_code(mpl, d->u.code);
alpar@1
  5714
#if 0 /* 15/V-2010 */
alpar@1
  5715
         /* clean pseudo-code for computing subscripts */
alpar@1
  5716
         for (e = d->list; e != NULL; e = e->next)
alpar@1
  5717
            clean_code(mpl, e->x);
alpar@1
  5718
#endif
alpar@1
  5719
      }
alpar@1
  5720
      return;
alpar@1
  5721
}
alpar@1
  5722
alpar@1
  5723
/*----------------------------------------------------------------------
alpar@1
  5724
-- execute_printf - execute printf statement.
alpar@1
  5725
--
alpar@1
  5726
-- This routine executes specified printf statement. */
alpar@1
  5727
alpar@1
  5728
#if 1 /* 14/VII-2006 */
alpar@1
  5729
static void print_char(MPL *mpl, int c)
alpar@1
  5730
{     if (mpl->prt_fp == NULL)
alpar@1
  5731
         write_char(mpl, c);
alpar@1
  5732
      else
alpar@1
  5733
         xfputc(c, mpl->prt_fp);
alpar@1
  5734
      return;
alpar@1
  5735
}
alpar@1
  5736
alpar@1
  5737
static void print_text(MPL *mpl, char *fmt, ...)
alpar@1
  5738
{     va_list arg;
alpar@1
  5739
      char buf[OUTBUF_SIZE], *c;
alpar@1
  5740
      va_start(arg, fmt);
alpar@1
  5741
      vsprintf(buf, fmt, arg);
alpar@1
  5742
      xassert(strlen(buf) < sizeof(buf));
alpar@1
  5743
      va_end(arg);
alpar@1
  5744
      for (c = buf; *c != '\0'; c++) print_char(mpl, *c);
alpar@1
  5745
      return;
alpar@1
  5746
}
alpar@1
  5747
#endif
alpar@1
  5748
alpar@1
  5749
static int printf_func(MPL *mpl, void *info)
alpar@1
  5750
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  5751
      PRINTF *prt = (PRINTF *)info;
alpar@1
  5752
      PRINTF1 *entry;
alpar@1
  5753
      SYMBOL *sym;
alpar@1
  5754
      char fmt[MAX_LENGTH+1], *c, *from, save;
alpar@1
  5755
      /* evaluate format control string */
alpar@1
  5756
      sym = eval_symbolic(mpl, prt->fmt);
alpar@1
  5757
      if (sym->str == NULL)
alpar@1
  5758
         sprintf(fmt, "%.*g", DBL_DIG, sym->num);
alpar@1
  5759
      else
alpar@1
  5760
         fetch_string(mpl, sym->str, fmt);
alpar@1
  5761
      delete_symbol(mpl, sym);
alpar@1
  5762
      /* scan format control string and perform formatting output */
alpar@1
  5763
      entry = prt->list;
alpar@1
  5764
      for (c = fmt; *c != '\0'; c++)
alpar@1
  5765
      {  if (*c == '%')
alpar@1
  5766
         {  /* scan format specifier */
alpar@1
  5767
            from = c++;
alpar@1
  5768
            if (*c == '%')
alpar@1
  5769
            {  print_char(mpl, '%');
alpar@1
  5770
               continue;
alpar@1
  5771
            }
alpar@1
  5772
            if (entry == NULL) break;
alpar@1
  5773
            /* scan optional flags */
alpar@1
  5774
            while (*c == '-' || *c == '+' || *c == ' ' || *c == '#' ||
alpar@1
  5775
                   *c == '0') c++;
alpar@1
  5776
            /* scan optional minimum field width */
alpar@1
  5777
            while (isdigit((unsigned char)*c)) c++;
alpar@1
  5778
            /* scan optional precision */
alpar@1
  5779
            if (*c == '.')
alpar@1
  5780
            {  c++;
alpar@1
  5781
               while (isdigit((unsigned char)*c)) c++;
alpar@1
  5782
            }
alpar@1
  5783
            /* scan conversion specifier and perform formatting */
alpar@1
  5784
            save = *(c+1), *(c+1) = '\0';
alpar@1
  5785
            if (*c == 'd' || *c == 'i' || *c == 'e' || *c == 'E' ||
alpar@1
  5786
                *c == 'f' || *c == 'F' || *c == 'g' || *c == 'G')
alpar@1
  5787
            {  /* the specifier requires numeric value */
alpar@1
  5788
               double value;
alpar@1
  5789
               xassert(entry != NULL);
alpar@1
  5790
               switch (entry->code->type)
alpar@1
  5791
               {  case A_NUMERIC:
alpar@1
  5792
                     value = eval_numeric(mpl, entry->code);
alpar@1
  5793
                     break;
alpar@1
  5794
                  case A_SYMBOLIC:
alpar@1
  5795
                     sym = eval_symbolic(mpl, entry->code);
alpar@1
  5796
                     if (sym->str != NULL)
alpar@1
  5797
                        error(mpl, "cannot convert %s to floating-point"
alpar@1
  5798
                           " number", format_symbol(mpl, sym));
alpar@1
  5799
                     value = sym->num;
alpar@1
  5800
                     delete_symbol(mpl, sym);
alpar@1
  5801
                     break;
alpar@1
  5802
                  case A_LOGICAL:
alpar@1
  5803
                     if (eval_logical(mpl, entry->code))
alpar@1
  5804
                        value = 1.0;
alpar@1
  5805
                     else
alpar@1
  5806
                        value = 0.0;
alpar@1
  5807
                     break;
alpar@1
  5808
                  default:
alpar@1
  5809
                     xassert(entry != entry);
alpar@1
  5810
               }
alpar@1
  5811
               if (*c == 'd' || *c == 'i')
alpar@1
  5812
               {  double int_max = (double)INT_MAX;
alpar@1
  5813
                  if (!(-int_max <= value && value <= +int_max))
alpar@1
  5814
                     error(mpl, "cannot convert %.*g to integer",
alpar@1
  5815
                        DBL_DIG, value);
alpar@1
  5816
                  print_text(mpl, from, (int)floor(value + 0.5));
alpar@1
  5817
               }
alpar@1
  5818
               else
alpar@1
  5819
                  print_text(mpl, from, value);
alpar@1
  5820
            }
alpar@1
  5821
            else if (*c == 's')
alpar@1
  5822
            {  /* the specifier requires symbolic value */
alpar@1
  5823
               char value[MAX_LENGTH+1];
alpar@1
  5824
               switch (entry->code->type)
alpar@1
  5825
               {  case A_NUMERIC:
alpar@1
  5826
                     sprintf(value, "%.*g", DBL_DIG, eval_numeric(mpl,
alpar@1
  5827
                        entry->code));
alpar@1
  5828
                     break;
alpar@1
  5829
                  case A_LOGICAL:
alpar@1
  5830
                     if (eval_logical(mpl, entry->code))
alpar@1
  5831
                        strcpy(value, "T");
alpar@1
  5832
                     else
alpar@1
  5833
                        strcpy(value, "F");
alpar@1
  5834
                     break;
alpar@1
  5835
                  case A_SYMBOLIC:
alpar@1
  5836
                     sym = eval_symbolic(mpl, entry->code);
alpar@1
  5837
                     if (sym->str == NULL)
alpar@1
  5838
                        sprintf(value, "%.*g", DBL_DIG, sym->num);
alpar@1
  5839
                     else
alpar@1
  5840
                        fetch_string(mpl, sym->str, value);
alpar@1
  5841
                     delete_symbol(mpl, sym);
alpar@1
  5842
                     break;
alpar@1
  5843
                  default:
alpar@1
  5844
                     xassert(entry != entry);
alpar@1
  5845
               }
alpar@1
  5846
               print_text(mpl, from, value);
alpar@1
  5847
            }
alpar@1
  5848
            else
alpar@1
  5849
               error(mpl, "format specifier missing or invalid");
alpar@1
  5850
            *(c+1) = save;
alpar@1
  5851
            entry = entry->next;
alpar@1
  5852
         }
alpar@1
  5853
         else if (*c == '\\')
alpar@1
  5854
         {  /* write some control character */
alpar@1
  5855
            c++;
alpar@1
  5856
            if (*c == 't')
alpar@1
  5857
               print_char(mpl, '\t');
alpar@1
  5858
            else if (*c == 'n')
alpar@1
  5859
               print_char(mpl, '\n');
alpar@1
  5860
#if 1 /* 28/X-2010 */
alpar@1
  5861
            else if (*c == '\0')
alpar@1
  5862
            {  /* format string ends with backslash */
alpar@1
  5863
               error(mpl, "invalid use of escape character \\ in format"
alpar@1
  5864
                  " control string");
alpar@1
  5865
            }
alpar@1
  5866
#endif
alpar@1
  5867
            else
alpar@1
  5868
               print_char(mpl, *c);
alpar@1
  5869
         }
alpar@1
  5870
         else
alpar@1
  5871
         {  /* write character without formatting */
alpar@1
  5872
            print_char(mpl, *c);
alpar@1
  5873
         }
alpar@1
  5874
      }
alpar@1
  5875
      return 0;
alpar@1
  5876
}
alpar@1
  5877
alpar@1
  5878
#if 0 /* 14/VII-2006 */
alpar@1
  5879
void execute_printf(MPL *mpl, PRINTF *prt)
alpar@1
  5880
{     loop_within_domain(mpl, prt->domain, prt, printf_func);
alpar@1
  5881
      return;
alpar@1
  5882
}
alpar@1
  5883
#else
alpar@1
  5884
void execute_printf(MPL *mpl, PRINTF *prt)
alpar@1
  5885
{     if (prt->fname == NULL)
alpar@1
  5886
      {  /* switch to the standard output */
alpar@1
  5887
         if (mpl->prt_fp != NULL)
alpar@1
  5888
         {  xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
alpar@1
  5889
            xfree(mpl->prt_file), mpl->prt_file = NULL;
alpar@1
  5890
         }
alpar@1
  5891
      }
alpar@1
  5892
      else
alpar@1
  5893
      {  /* evaluate file name string */
alpar@1
  5894
         SYMBOL *sym;
alpar@1
  5895
         char fname[MAX_LENGTH+1];
alpar@1
  5896
         sym = eval_symbolic(mpl, prt->fname);
alpar@1
  5897
         if (sym->str == NULL)
alpar@1
  5898
            sprintf(fname, "%.*g", DBL_DIG, sym->num);
alpar@1
  5899
         else
alpar@1
  5900
            fetch_string(mpl, sym->str, fname);
alpar@1
  5901
         delete_symbol(mpl, sym);
alpar@1
  5902
         /* close the current print file, if necessary */
alpar@1
  5903
         if (mpl->prt_fp != NULL &&
alpar@1
  5904
            (!prt->app || strcmp(mpl->prt_file, fname) != 0))
alpar@1
  5905
         {  xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
alpar@1
  5906
            xfree(mpl->prt_file), mpl->prt_file = NULL;
alpar@1
  5907
         }
alpar@1
  5908
         /* open the specified print file, if necessary */
alpar@1
  5909
         if (mpl->prt_fp == NULL)
alpar@1
  5910
         {  mpl->prt_fp = xfopen(fname, prt->app ? "a" : "w");
alpar@1
  5911
            if (mpl->prt_fp == NULL)
alpar@1
  5912
               error(mpl, "unable to open `%s' for writing - %s",
alpar@1
  5913
                  fname, xerrmsg());
alpar@1
  5914
            mpl->prt_file = xmalloc(strlen(fname)+1);
alpar@1
  5915
            strcpy(mpl->prt_file, fname);
alpar@1
  5916
         }
alpar@1
  5917
      }
alpar@1
  5918
      loop_within_domain(mpl, prt->domain, prt, printf_func);
alpar@1
  5919
      if (mpl->prt_fp != NULL)
alpar@1
  5920
      {  xfflush(mpl->prt_fp);
alpar@1
  5921
         if (xferror(mpl->prt_fp))
alpar@1
  5922
            error(mpl, "writing error to `%s' - %s", mpl->prt_file,
alpar@1
  5923
               xerrmsg());
alpar@1
  5924
      }
alpar@1
  5925
      return;
alpar@1
  5926
}
alpar@1
  5927
#endif
alpar@1
  5928
alpar@1
  5929
/*----------------------------------------------------------------------
alpar@1
  5930
-- clean_printf - clean printf statement.
alpar@1
  5931
--
alpar@1
  5932
-- This routine cleans specified printf statement that assumes deleting
alpar@1
  5933
-- all stuff dynamically allocated on generating/postsolving phase. */
alpar@1
  5934
alpar@1
  5935
void clean_printf(MPL *mpl, PRINTF *prt)
alpar@1
  5936
{     PRINTF1 *p;
alpar@1
  5937
      /* clean subscript domain */
alpar@1
  5938
      clean_domain(mpl, prt->domain);
alpar@1
  5939
      /* clean pseudo-code for computing format string */
alpar@1
  5940
      clean_code(mpl, prt->fmt);
alpar@1
  5941
      /* clean printf list */
alpar@1
  5942
      for (p = prt->list; p != NULL; p = p->next)
alpar@1
  5943
      {  /* clean pseudo-code for computing value to be printed */
alpar@1
  5944
         clean_code(mpl, p->code);
alpar@1
  5945
      }
alpar@1
  5946
#if 1 /* 14/VII-2006 */
alpar@1
  5947
      /* clean pseudo-code for computing file name string */
alpar@1
  5948
      clean_code(mpl, prt->fname);
alpar@1
  5949
#endif
alpar@1
  5950
      return;
alpar@1
  5951
}
alpar@1
  5952
alpar@1
  5953
/*----------------------------------------------------------------------
alpar@1
  5954
-- execute_for - execute for statement.
alpar@1
  5955
--
alpar@1
  5956
-- This routine executes specified for statement. */
alpar@1
  5957
alpar@1
  5958
static int for_func(MPL *mpl, void *info)
alpar@1
  5959
{     /* this is auxiliary routine to work within domain scope */
alpar@1
  5960
      FOR *fur = (FOR *)info;
alpar@1
  5961
      STATEMENT *stmt, *save;
alpar@1
  5962
      save = mpl->stmt;
alpar@1
  5963
      for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
alpar@1
  5964
         execute_statement(mpl, stmt);
alpar@1
  5965
      mpl->stmt = save;
alpar@1
  5966
      return 0;
alpar@1
  5967
}
alpar@1
  5968
alpar@1
  5969
void execute_for(MPL *mpl, FOR *fur)
alpar@1
  5970
{     loop_within_domain(mpl, fur->domain, fur, for_func);
alpar@1
  5971
      return;
alpar@1
  5972
}
alpar@1
  5973
alpar@1
  5974
/*----------------------------------------------------------------------
alpar@1
  5975
-- clean_for - clean for statement.
alpar@1
  5976
--
alpar@1
  5977
-- This routine cleans specified for statement that assumes deleting all
alpar@1
  5978
-- stuff dynamically allocated on generating/postsolving phase. */
alpar@1
  5979
alpar@1
  5980
void clean_for(MPL *mpl, FOR *fur)
alpar@1
  5981
{     STATEMENT *stmt;
alpar@1
  5982
      /* clean subscript domain */
alpar@1
  5983
      clean_domain(mpl, fur->domain);
alpar@1
  5984
      /* clean all sub-statements */
alpar@1
  5985
      for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
alpar@1
  5986
         clean_statement(mpl, stmt);
alpar@1
  5987
      return;
alpar@1
  5988
}
alpar@1
  5989
alpar@1
  5990
/*----------------------------------------------------------------------
alpar@1
  5991
-- execute_statement - execute specified model statement.
alpar@1
  5992
--
alpar@1
  5993
-- This routine executes specified model statement. */
alpar@1
  5994
alpar@1
  5995
void execute_statement(MPL *mpl, STATEMENT *stmt)
alpar@1
  5996
{     mpl->stmt = stmt;
alpar@1
  5997
      switch (stmt->type)
alpar@1
  5998
      {  case A_SET:
alpar@1
  5999
         case A_PARAMETER:
alpar@1
  6000
         case A_VARIABLE:
alpar@1
  6001
            break;
alpar@1
  6002
         case A_CONSTRAINT:
alpar@1
  6003
            xprintf("Generating %s...\n", stmt->u.con->name);
alpar@1
  6004
            eval_whole_con(mpl, stmt->u.con);
alpar@1
  6005
            break;
alpar@1
  6006
         case A_TABLE:
alpar@1
  6007
            switch (stmt->u.tab->type)
alpar@1
  6008
            {  case A_INPUT:
alpar@1
  6009
                  xprintf("Reading %s...\n", stmt->u.tab->name);
alpar@1
  6010
                  break;
alpar@1
  6011
               case A_OUTPUT:
alpar@1
  6012
                  xprintf("Writing %s...\n", stmt->u.tab->name);
alpar@1
  6013
                  break;
alpar@1
  6014
               default:
alpar@1
  6015
                  xassert(stmt != stmt);
alpar@1
  6016
            }
alpar@1
  6017
            execute_table(mpl, stmt->u.tab);
alpar@1
  6018
            break;
alpar@1
  6019
         case A_SOLVE:
alpar@1
  6020
            break;
alpar@1
  6021
         case A_CHECK:
alpar@1
  6022
            xprintf("Checking (line %d)...\n", stmt->line);
alpar@1
  6023
            execute_check(mpl, stmt->u.chk);
alpar@1
  6024
            break;
alpar@1
  6025
         case A_DISPLAY:
alpar@1
  6026
            write_text(mpl, "Display statement at line %d\n",
alpar@1
  6027
               stmt->line);
alpar@1
  6028
            execute_display(mpl, stmt->u.dpy);
alpar@1
  6029
            break;
alpar@1
  6030
         case A_PRINTF:
alpar@1
  6031
            execute_printf(mpl, stmt->u.prt);
alpar@1
  6032
            break;
alpar@1
  6033
         case A_FOR:
alpar@1
  6034
            execute_for(mpl, stmt->u.fur);
alpar@1
  6035
            break;
alpar@1
  6036
         default:
alpar@1
  6037
            xassert(stmt != stmt);
alpar@1
  6038
      }
alpar@1
  6039
      return;
alpar@1
  6040
}
alpar@1
  6041
alpar@1
  6042
/*----------------------------------------------------------------------
alpar@1
  6043
-- clean_statement - clean specified model statement.
alpar@1
  6044
--
alpar@1
  6045
-- This routine cleans specified model statement that assumes deleting
alpar@1
  6046
-- all stuff dynamically allocated on generating/postsolving phase. */
alpar@1
  6047
alpar@1
  6048
void clean_statement(MPL *mpl, STATEMENT *stmt)
alpar@1
  6049
{     switch(stmt->type)
alpar@1
  6050
      {  case A_SET:
alpar@1
  6051
            clean_set(mpl, stmt->u.set); break;
alpar@1
  6052
         case A_PARAMETER:
alpar@1
  6053
            clean_parameter(mpl, stmt->u.par); break;
alpar@1
  6054
         case A_VARIABLE:
alpar@1
  6055
            clean_variable(mpl, stmt->u.var); break;
alpar@1
  6056
         case A_CONSTRAINT:
alpar@1
  6057
            clean_constraint(mpl, stmt->u.con); break;
alpar@1
  6058
#if 1 /* 11/II-2008 */
alpar@1
  6059
         case A_TABLE:
alpar@1
  6060
            clean_table(mpl, stmt->u.tab); break;
alpar@1
  6061
#endif
alpar@1
  6062
         case A_SOLVE:
alpar@1
  6063
            break;
alpar@1
  6064
         case A_CHECK:
alpar@1
  6065
            clean_check(mpl, stmt->u.chk); break;
alpar@1
  6066
         case A_DISPLAY:
alpar@1
  6067
            clean_display(mpl, stmt->u.dpy); break;
alpar@1
  6068
         case A_PRINTF:
alpar@1
  6069
            clean_printf(mpl, stmt->u.prt); break;
alpar@1
  6070
         case A_FOR:
alpar@1
  6071
            clean_for(mpl, stmt->u.fur); break;
alpar@1
  6072
         default:
alpar@1
  6073
            xassert(stmt != stmt);
alpar@1
  6074
      }
alpar@1
  6075
      return;
alpar@1
  6076
}
alpar@1
  6077
alpar@1
  6078
/* eof */