File: glpmpl02.c

package info (click to toggle)
r-cran-igraph 0.7.1-1~bpo8%2B1
  • links: PTS, VCS
  • area: main
  • in suites: jessie-backports
  • size: 14,280 kB
  • sloc: ansic: 150,105; cpp: 19,404; fortran: 3,777; yacc: 1,164; tcl: 931; lex: 484; makefile: 13; sh: 9
file content (1205 lines) | stat: -rw-r--r-- 45,522 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
/* glpmpl02.c */

/***********************************************************************
*  This code is part of GLPK (GNU Linear Programming Kit).
*
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
*  E-mail: <mao@gnu.org>.
*
*  GLPK is free software: you can redistribute it and/or modify it
*  under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
*  License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
***********************************************************************/

#define _GLPSTD_STDIO
#include "glpenv.h"
#include "glpmpl.h"

/**********************************************************************/
/* * *                  PROCESSING DATA SECTION                   * * */
/**********************************************************************/

/*----------------------------------------------------------------------
-- create_slice - create slice.
--
-- This routine creates a slice, which initially has no components. */

SLICE *create_slice(MPL *mpl)
{     SLICE *slice;
      xassert(mpl == mpl);
      slice = NULL;
      return slice;
}

/*----------------------------------------------------------------------
-- expand_slice - append new component to slice.
--
-- This routine expands slice appending to it either a given symbol or
-- null component, which becomes the last component of the slice. */

SLICE *expand_slice
(     MPL *mpl,
      SLICE *slice,           /* destroyed */
      SYMBOL *sym             /* destroyed */
)
{     SLICE *tail, *temp;
      /* create a new component */
      tail = dmp_get_atom(mpl->tuples, sizeof(SLICE));
      tail->sym = sym;
      tail->next = NULL;
      /* and append it to the component list */
      if (slice == NULL)
         slice = tail;
      else
      {  for (temp = slice; temp->next != NULL; temp = temp->next);
         temp->next = tail;
      }
      return slice;
}

/*----------------------------------------------------------------------
-- slice_dimen - determine dimension of slice.
--
-- This routine returns dimension of slice, which is number of all its
-- components including null ones. */

int slice_dimen
(     MPL *mpl,
      SLICE *slice            /* not changed */
)
{     SLICE *temp;
      int dim;
      xassert(mpl == mpl);
      dim = 0;
      for (temp = slice; temp != NULL; temp = temp->next) dim++;
      return dim;
}

/*----------------------------------------------------------------------
-- slice_arity - determine arity of slice.
--
-- This routine returns arity of slice, i.e. number of null components
-- (indicated by asterisks) in the slice. */

int slice_arity
(     MPL *mpl,
      SLICE *slice            /* not changed */
)
{     SLICE *temp;
      int arity;
      xassert(mpl == mpl);
      arity = 0;
      for (temp = slice; temp != NULL; temp = temp->next)
         if (temp->sym == NULL) arity++;
      return arity;
}

/*----------------------------------------------------------------------
-- fake_slice - create fake slice of all asterisks.
--
-- This routine creates a fake slice of given dimension, which contains
-- asterisks in all components. Zero dimension is allowed. */

SLICE *fake_slice(MPL *mpl, int dim)
{     SLICE *slice;
      slice = create_slice(mpl);
      while (dim-- > 0) slice = expand_slice(mpl, slice, NULL);
      return slice;
}

/*----------------------------------------------------------------------
-- delete_slice - delete slice.
--
-- This routine deletes specified slice. */

void delete_slice
(     MPL *mpl,
      SLICE *slice            /* destroyed */
)
{     SLICE *temp;
      while (slice != NULL)
      {  temp = slice;
         slice = temp->next;
         if (temp->sym != NULL) delete_symbol(mpl, temp->sym);
xassert(sizeof(SLICE) == sizeof(TUPLE));
         dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
      }
      return;
}

/*----------------------------------------------------------------------
-- is_number - check if current token is number.
--
-- If the current token is a number, this routine returns non-zero.
-- Otherwise zero is returned. */

int is_number(MPL *mpl)
{     return
         mpl->token == T_NUMBER;
}

/*----------------------------------------------------------------------
-- is_symbol - check if current token is symbol.
--
-- If the current token is suitable to be a symbol, the routine returns
-- non-zero. Otherwise zero is returned. */

int is_symbol(MPL *mpl)
{     return
         mpl->token == T_NUMBER ||
         mpl->token == T_SYMBOL ||
         mpl->token == T_STRING;
}

/*----------------------------------------------------------------------
-- is_literal - check if current token is given symbolic literal.
--
-- If the current token is given symbolic literal, this routine returns
-- non-zero. Otherwise zero is returned.
--
-- This routine is used on processing the data section in the same way
-- as the routine is_keyword on processing the model section. */

int is_literal(MPL *mpl, char *literal)
{     return
         is_symbol(mpl) && strcmp(mpl->image, literal) == 0;
}

/*----------------------------------------------------------------------
-- read_number - read number.
--
-- This routine reads the current token, which must be a number, and
-- returns its numeric value. */

double read_number(MPL *mpl)
{     double num;
      xassert(is_number(mpl));
      num = mpl->value;
      get_token(mpl /* <number> */);
      return num;
}

/*----------------------------------------------------------------------
-- read_symbol - read symbol.
--
-- This routine reads the current token, which must be a symbol, and
-- returns its symbolic value. */

SYMBOL *read_symbol(MPL *mpl)
{     SYMBOL *sym;
      xassert(is_symbol(mpl));
      if (is_number(mpl))
         sym = create_symbol_num(mpl, mpl->value);
      else
         sym = create_symbol_str(mpl, create_string(mpl, mpl->image));
      get_token(mpl /* <symbol> */);
      return sym;
}

/*----------------------------------------------------------------------
-- read_slice - read slice.
--
-- This routine reads slice using the syntax:
--
-- <slice> ::= [ <symbol list> ]
-- <slice> ::= ( <symbol list> )
-- <symbol list> ::= <symbol or star>
-- <symbol list> ::= <symbol list> , <symbol or star>
-- <symbol or star> ::= <symbol>
-- <symbol or star> ::= *
--
-- The bracketed form of slice is used for members of multi-dimensional
-- objects while the parenthesized form is used for elemental sets. */

SLICE *read_slice
(     MPL *mpl,
      char *name,             /* not changed */
      int dim
)
{     SLICE *slice;
      int close;
      xassert(name != NULL);
      switch (mpl->token)
      {  case T_LBRACKET:
            close = T_RBRACKET;
            break;
         case T_LEFT:
            xassert(dim > 0);
            close = T_RIGHT;
            break;
         default:
            xassert(mpl != mpl);
      }
      if (dim == 0)
         error(mpl, "%s cannot be subscripted", name);
      get_token(mpl /* ( | [ */);
      /* read slice components */
      slice = create_slice(mpl);
      for (;;)
      {  /* the current token must be a symbol or asterisk */
         if (is_symbol(mpl))
            slice = expand_slice(mpl, slice, read_symbol(mpl));
         else if (mpl->token == T_ASTERISK)
         {  slice = expand_slice(mpl, slice, NULL);
            get_token(mpl /* * */);
         }
         else
            error(mpl, "number, symbol, or asterisk missing where expec"
               "ted");
         /* check a token that follows the symbol */
         if (mpl->token == T_COMMA)
            get_token(mpl /* , */);
         else if (mpl->token == close)
            break;
         else
            error(mpl, "syntax error in slice");
      }
      /* number of slice components must be the same as the appropriate
         dimension */
      if (slice_dimen(mpl, slice) != dim)
      {  switch (close)
         {  case T_RBRACKET:
               error(mpl, "%s must have %d subscript%s, not %d", name,
                  dim, dim == 1 ? "" : "s", slice_dimen(mpl, slice));
               break;
            case T_RIGHT:
               error(mpl, "%s has dimension %d, not %d", name, dim,
                  slice_dimen(mpl, slice));
               break;
            default:
               xassert(close != close);
         }
      }
      get_token(mpl /* ) | ] */);
      return slice;
}

/*----------------------------------------------------------------------
-- select_set - select set to saturate it with elemental sets.
--
-- This routine selects set to saturate it with elemental sets provided
-- in the data section. */

SET *select_set
(     MPL *mpl,
      char *name              /* not changed */
)
{     SET *set;
      AVLNODE *node;
      xassert(name != NULL);
      node = avl_find_node(mpl->tree, name);
      if (node == NULL || avl_get_node_type(node) != A_SET)
         error(mpl, "%s not a set", name);
      set = (SET *)avl_get_node_link(node);
      if (set->assign != NULL || set->gadget != NULL)
         error(mpl, "%s needs no data", name);
      set->data = 1;
      return set;
}

/*----------------------------------------------------------------------
-- simple_format - read set data block in simple format.
--
-- This routine reads set data block using the syntax:
--
-- <simple format> ::= <symbol> , <symbol> , ... , <symbol>
--
-- where <symbols> are used to construct a complete n-tuple, which is
-- included in elemental set assigned to the set member. Commae between
-- symbols are optional and may be omitted anywhere.
--
-- Number of components in the slice must be the same as dimension of
-- n-tuples in elemental sets assigned to the set members. To construct
-- complete n-tuple the routine replaces null positions in the slice by
-- corresponding <symbols>.
--
-- If the slice contains at least one null position, the current token
-- must be symbol. Otherwise, the routine reads no symbols to construct
-- the n-tuple, so the current token is not checked. */

void simple_format
(     MPL *mpl,
      SET *set,               /* not changed */
      MEMBER *memb,           /* modified */
      SLICE *slice            /* not changed */
)
{     TUPLE *tuple;
      SLICE *temp;
      SYMBOL *sym, *with = NULL;
      xassert(set != NULL);
      xassert(memb != NULL);
      xassert(slice != NULL);
      xassert(set->dimen == slice_dimen(mpl, slice));
      xassert(memb->value.set->dim == set->dimen);
      if (slice_arity(mpl, slice) > 0) xassert(is_symbol(mpl));
      /* read symbols and construct complete n-tuple */
      tuple = create_tuple(mpl);
      for (temp = slice; temp != NULL; temp = temp->next)
      {  if (temp->sym == NULL)
         {  /* substitution is needed; read symbol */
            if (!is_symbol(mpl))
            {  int lack = slice_arity(mpl, temp);
               /* with cannot be null due to assertion above */
               xassert(with != NULL);
               if (lack == 1)
                  error(mpl, "one item missing in data group beginning "
                     "with %s", format_symbol(mpl, with));
               else
                  error(mpl, "%d items missing in data group beginning "
                     "with %s", lack, format_symbol(mpl, with));
            }
            sym = read_symbol(mpl);
            if (with == NULL) with = sym;
         }
         else
         {  /* copy symbol from the slice */
            sym = copy_symbol(mpl, temp->sym);
         }
         /* append the symbol to the n-tuple */
         tuple = expand_tuple(mpl, tuple, sym);
         /* skip optional comma *between* <symbols> */
         if (temp->next != NULL && mpl->token == T_COMMA)
            get_token(mpl /* , */);
      }
      /* add constructed n-tuple to elemental set */
      check_then_add(mpl, memb->value.set, tuple);
      return;
}

/*----------------------------------------------------------------------
-- matrix_format - read set data block in matrix format.
--
-- This routine reads set data block using the syntax:
--
-- <matrix format> ::= <column> <column> ... <column> :=
--               <row>   +/-      +/-    ...   +/-
--               <row>   +/-      +/-    ...   +/-
--                 .  .  .  .  .  .  .  .  .  .  .
--               <row>   +/-      +/-    ...   +/-
--
-- where <rows> are symbols that denote rows of the matrix, <columns>
-- are symbols that denote columns of the matrix, "+" and "-" indicate
-- whether corresponding n-tuple needs to be included in the elemental
-- set or not, respectively.
--
-- Number of the slice components must be the same as dimension of the
-- elemental set. The slice must have two null positions. To construct
-- complete n-tuple for particular element of the matrix the routine
-- replaces first null position of the slice by the corresponding <row>
-- (or <column>, if the flag tr is on) and second null position by the
-- corresponding <column> (or by <row>, if the flag tr is on). */

void matrix_format
(     MPL *mpl,
      SET *set,               /* not changed */
      MEMBER *memb,           /* modified */
      SLICE *slice,           /* not changed */
      int tr
)
{     SLICE *list, *col, *temp;
      TUPLE *tuple;
      SYMBOL *row;
      xassert(set != NULL);
      xassert(memb != NULL);
      xassert(slice != NULL);
      xassert(set->dimen == slice_dimen(mpl, slice));
      xassert(memb->value.set->dim == set->dimen);
      xassert(slice_arity(mpl, slice) == 2);
      /* read the matrix heading that contains column symbols (there
         may be no columns at all) */
      list = create_slice(mpl);
      while (mpl->token != T_ASSIGN)
      {  /* read column symbol and append it to the column list */
         if (!is_symbol(mpl))
            error(mpl, "number, symbol, or := missing where expected");
         list = expand_slice(mpl, list, read_symbol(mpl));
      }
      get_token(mpl /* := */);
      /* read zero or more rows that contain matrix data */
      while (is_symbol(mpl))
      {  /* read row symbol (if the matrix has no columns, row symbols
            are just ignored) */
         row = read_symbol(mpl);
         /* read the matrix row accordingly to the column list */
         for (col = list; col != NULL; col = col->next)
         {  int which = 0;
            /* check indicator */
            if (is_literal(mpl, "+"))
               ;
            else if (is_literal(mpl, "-"))
            {  get_token(mpl /* - */);
               continue;
            }
            else
            {  int lack = slice_dimen(mpl, col);
               if (lack == 1)
                  error(mpl, "one item missing in data group beginning "
                     "with %s", format_symbol(mpl, row));
               else
                  error(mpl, "%d items missing in data group beginning "
                     "with %s", lack, format_symbol(mpl, row));
            }
            /* construct complete n-tuple */
            tuple = create_tuple(mpl);
            for (temp = slice; temp != NULL; temp = temp->next)
            {  if (temp->sym == NULL)
               {  /* substitution is needed */
                  switch (++which)
                  {  case 1:
                        /* substitute in the first null position */
                        tuple = expand_tuple(mpl, tuple,
                           copy_symbol(mpl, tr ? col->sym : row));
                        break;
                     case 2:
                        /* substitute in the second null position */
                        tuple = expand_tuple(mpl, tuple,
                           copy_symbol(mpl, tr ? row : col->sym));
                        break;
                     default:
                        xassert(which != which);
                  }
               }
               else
               {  /* copy symbol from the slice */
                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
                     temp->sym));
               }
            }
            xassert(which == 2);
            /* add constructed n-tuple to elemental set */
            check_then_add(mpl, memb->value.set, tuple);
            get_token(mpl /* + */);
         }
         /* delete the row symbol */
         delete_symbol(mpl, row);
      }
      /* delete the column list */
      delete_slice(mpl, list);
      return;
}

/*----------------------------------------------------------------------
-- set_data - read set data.
--
-- This routine reads set data using the syntax:
--
-- <set data> ::= set <set name> <assignments> ;
-- <set data> ::= set <set name> [ <symbol list> ] <assignments> ;
-- <set name> ::= <symbolic name>
-- <assignments> ::= <empty>
-- <assignments> ::= <assignments> , :=
-- <assignments> ::= <assignments> , ( <symbol list> )
-- <assignments> ::= <assignments> , <simple format>
-- <assignments> ::= <assignments> , : <matrix format>
-- <assignments> ::= <assignments> , (tr) <matrix format>
-- <assignments> ::= <assignments> , (tr) : <matrix format>
--
-- Commae in <assignments> are optional and may be omitted anywhere. */

void set_data(MPL *mpl)
{     SET *set;
      TUPLE *tuple;
      MEMBER *memb;
      SLICE *slice;
      int tr = 0;
      xassert(is_literal(mpl, "set"));
      get_token(mpl /* set */);
      /* symbolic name of set must follows the keyword 'set' */
      if (!is_symbol(mpl))
         error(mpl, "set name missing where expected");
      /* select the set to saturate it with data */
      set = select_set(mpl, mpl->image);
      get_token(mpl /* <symbolic name> */);
      /* read optional subscript list, which identifies member of the
         set to be read */
      tuple = create_tuple(mpl);
      if (mpl->token == T_LBRACKET)
      {  /* subscript list is specified */
         if (set->dim == 0)
            error(mpl, "%s cannot be subscripted", set->name);
         get_token(mpl /* [ */);
         /* read symbols and construct subscript list */
         for (;;)
         {  if (!is_symbol(mpl))
               error(mpl, "number or symbol missing where expected");
            tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
            if (mpl->token == T_COMMA)
               get_token(mpl /* , */);
            else if (mpl->token == T_RBRACKET)
               break;
            else
               error(mpl, "syntax error in subscript list");
         }
         if (set->dim != tuple_dimen(mpl, tuple))
            error(mpl, "%s must have %d subscript%s rather than %d",
               set->name, set->dim, set->dim == 1 ? "" : "s",
               tuple_dimen(mpl, tuple));
         get_token(mpl /* ] */);
      }
      else
      {  /* subscript list is not specified */
         if (set->dim != 0)
            error(mpl, "%s must be subscripted", set->name);
      }
      /* there must be no member with the same subscript list */
      if (find_member(mpl, set->array, tuple) != NULL)
         error(mpl, "%s%s already defined",
            set->name, format_tuple(mpl, '[', tuple));
      /* add new member to the set and assign it empty elemental set */
      memb = add_member(mpl, set->array, tuple);
      memb->value.set = create_elemset(mpl, set->dimen);
      /* create an initial fake slice of all asterisks */
      slice = fake_slice(mpl, set->dimen);
      /* read zero or more data assignments */
      for (;;)
      {  /* skip optional comma */
         if (mpl->token == T_COMMA) get_token(mpl /* , */);
         /* process assignment element */
         if (mpl->token == T_ASSIGN)
         {  /* assignment ligature is non-significant element */
            get_token(mpl /* := */);
         }
         else if (mpl->token == T_LEFT)
         {  /* left parenthesis begins either new slice or "transpose"
               indicator */
            int is_tr;
            get_token(mpl /* ( */);
            is_tr = is_literal(mpl, "tr");
            unget_token(mpl /* ( */);
            if (is_tr) goto left;
            /* delete the current slice and read new one */
            delete_slice(mpl, slice);
            slice = read_slice(mpl, set->name, set->dimen);
            /* each new slice resets the "transpose" indicator */
            tr = 0;
            /* if the new slice is 0-ary, formally there is one 0-tuple
               (in the simple format) that follows it */
            if (slice_arity(mpl, slice) == 0)
               simple_format(mpl, set, memb, slice);
         }
         else if (is_symbol(mpl))
         {  /* number or symbol begins data in the simple format */
            simple_format(mpl, set, memb, slice);
         }
         else if (mpl->token == T_COLON)
         {  /* colon begins data in the matrix format */
            if (slice_arity(mpl, slice) != 2)
err1:          error(mpl, "slice currently used must specify 2 asterisk"
                  "s, not %d", slice_arity(mpl, slice));
            get_token(mpl /* : */);
            /* read elemental set data in the matrix format */
            matrix_format(mpl, set, memb, slice, tr);
         }
         else if (mpl->token == T_LEFT)
left:    {  /* left parenthesis begins the "transpose" indicator, which
               is followed by data in the matrix format */
            get_token(mpl /* ( */);
            if (!is_literal(mpl, "tr"))
err2:          error(mpl, "transpose indicator (tr) incomplete");
            if (slice_arity(mpl, slice) != 2) goto err1;
            get_token(mpl /* tr */);
            if (mpl->token != T_RIGHT) goto err2;
            get_token(mpl /* ) */);
            /* in this case the colon is optional */
            if (mpl->token == T_COLON) get_token(mpl /* : */);
            /* set the "transpose" indicator */
            tr = 1;
            /* read elemental set data in the matrix format */
            matrix_format(mpl, set, memb, slice, tr);
         }
         else if (mpl->token == T_SEMICOLON)
         {  /* semicolon terminates the data block */
            get_token(mpl /* ; */);
            break;
         }
         else
            error(mpl, "syntax error in set data block");
      }
      /* delete the current slice */
      delete_slice(mpl, slice);
      return;
}

/*----------------------------------------------------------------------
-- select_parameter - select parameter to saturate it with data.
--
-- This routine selects parameter to saturate it with data provided in
-- the data section. */

PARAMETER *select_parameter
(     MPL *mpl,
      char *name              /* not changed */
)
{     PARAMETER *par;
      AVLNODE *node;
      xassert(name != NULL);
      node = avl_find_node(mpl->tree, name);
      if (node == NULL || avl_get_node_type(node) != A_PARAMETER)
         error(mpl, "%s not a parameter", name);
      par = (PARAMETER *)avl_get_node_link(node);
      if (par->assign != NULL)
         error(mpl, "%s needs no data", name);
      if (par->data)
         error(mpl, "%s already provided with data", name);
      par->data = 1;
      return par;
}

/*----------------------------------------------------------------------
-- set_default - set default parameter value.
--
-- This routine sets default value for specified parameter. */

void set_default
(     MPL *mpl,
      PARAMETER *par,         /* not changed */
      SYMBOL *altval          /* destroyed */
)
{     xassert(par != NULL);
      xassert(altval != NULL);
      if (par->option != NULL)
         error(mpl, "default value for %s already specified in model se"
            "ction", par->name);
      xassert(par->defval == NULL);
      par->defval = altval;
      return;
}

/*----------------------------------------------------------------------
-- read_value - read value and assign it to parameter member.
--
-- This routine reads numeric or symbolic value from the input stream
-- and assigns to new parameter member specified by its n-tuple, which
-- (the member) is created and added to the parameter array. */

MEMBER *read_value
(     MPL *mpl,
      PARAMETER *par,         /* not changed */
      TUPLE *tuple            /* destroyed */
)
{     MEMBER *memb;
      xassert(par != NULL);
      xassert(is_symbol(mpl));
      /* there must be no member with the same n-tuple */
      if (find_member(mpl, par->array, tuple) != NULL)
         error(mpl, "%s%s already defined",
            par->name, format_tuple(mpl, '[', tuple));
      /* create new parameter member with given n-tuple */
      memb = add_member(mpl, par->array, tuple);
      /* read value and assigns it to the new parameter member */
      switch (par->type)
      {  case A_NUMERIC:
         case A_INTEGER:
         case A_BINARY:
            if (!is_number(mpl))
               error(mpl, "%s requires numeric data", par->name);
            memb->value.num = read_number(mpl);
            break;
         case A_SYMBOLIC:
            memb->value.sym = read_symbol(mpl);
            break;
         default:
            xassert(par != par);
      }
      return memb;
}

/*----------------------------------------------------------------------
-- plain_format - read parameter data block in plain format.
--
-- This routine reads parameter data block using the syntax:
--
-- <plain format> ::= <symbol> , <symbol> , ... , <symbol> , <value>
--
-- where <symbols> are used to determine a complete subscript list for
-- parameter member, <value> is a numeric or symbolic value assigned to
-- the parameter member. Commae between data items are optional and may
-- be omitted anywhere.
--
-- Number of components in the slice must be the same as dimension of
-- the parameter. To construct the complete subscript list the routine
-- replaces null positions in the slice by corresponding <symbols>. */

void plain_format
(     MPL *mpl,
      PARAMETER *par,         /* not changed */
      SLICE *slice            /* not changed */
)
{     TUPLE *tuple;
      SLICE *temp;
      SYMBOL *sym, *with = NULL;
      xassert(par != NULL);
      xassert(par->dim == slice_dimen(mpl, slice));
      xassert(is_symbol(mpl));
      /* read symbols and construct complete subscript list */
      tuple = create_tuple(mpl);
      for (temp = slice; temp != NULL; temp = temp->next)
      {  if (temp->sym == NULL)
         {  /* substitution is needed; read symbol */
            if (!is_symbol(mpl))
            {  int lack = slice_arity(mpl, temp) + 1;
               xassert(with != NULL);
               xassert(lack > 1);
               error(mpl, "%d items missing in data group beginning wit"
                  "h %s", lack, format_symbol(mpl, with));
            }
            sym = read_symbol(mpl);
            if (with == NULL) with = sym;
         }
         else
         {  /* copy symbol from the slice */
            sym = copy_symbol(mpl, temp->sym);
         }
         /* append the symbol to the subscript list */
         tuple = expand_tuple(mpl, tuple, sym);
         /* skip optional comma */
         if (mpl->token == T_COMMA) get_token(mpl /* , */);
      }
      /* read value and assign it to new parameter member */
      if (!is_symbol(mpl))
      {  xassert(with != NULL);
         error(mpl, "one item missing in data group beginning with %s",
            format_symbol(mpl, with));
      }
      read_value(mpl, par, tuple);
      return;
}

/*----------------------------------------------------------------------
-- tabular_format - read parameter data block in tabular format.
--
-- This routine reads parameter data block using the syntax:
--
-- <tabular format> ::= <column> <column> ... <column> :=
--                <row> <value>  <value>  ... <value>
--                <row> <value>  <value>  ... <value>
--                  .  .  .  .  .  .  .  .  .  .  .
--                <row> <value>  <value>  ... <value>
--
-- where <rows> are symbols that denote rows of the table, <columns>
-- are symbols that denote columns of the table, <values> are numeric
-- or symbolic values assigned to the corresponding parameter members.
-- If <value> is specified as single point, no value is provided.
--
-- Number of components in the slice must be the same as dimension of
-- the parameter. The slice must have two null positions. To construct
-- complete subscript list for particular <value> the routine replaces
-- the first null position of the slice by the corresponding <row> (or
-- <column>, if the flag tr is on) and the second null position by the
-- corresponding <column> (or by <row>, if the flag tr is on). */

void tabular_format
(     MPL *mpl,
      PARAMETER *par,         /* not changed */
      SLICE *slice,           /* not changed */
      int tr
)
{     SLICE *list, *col, *temp;
      TUPLE *tuple;
      SYMBOL *row;
      xassert(par != NULL);
      xassert(par->dim == slice_dimen(mpl, slice));
      xassert(slice_arity(mpl, slice) == 2);
      /* read the table heading that contains column symbols (the table
         may have no columns) */
      list = create_slice(mpl);
      while (mpl->token != T_ASSIGN)
      {  /* read column symbol and append it to the column list */
         if (!is_symbol(mpl))
            error(mpl, "number, symbol, or := missing where expected");
         list = expand_slice(mpl, list, read_symbol(mpl));
      }
      get_token(mpl /* := */);
      /* read zero or more rows that contain tabular data */
      while (is_symbol(mpl))
      {  /* read row symbol (if the table has no columns, these symbols
            are just ignored) */
         row = read_symbol(mpl);
         /* read values accordingly to the column list */
         for (col = list; col != NULL; col = col->next)
         {  int which = 0;
            /* if the token is single point, no value is provided */
            if (is_literal(mpl, "."))
            {  get_token(mpl /* . */);
               continue;
            }
            /* construct complete subscript list */
            tuple = create_tuple(mpl);
            for (temp = slice; temp != NULL; temp = temp->next)
            {  if (temp->sym == NULL)
               {  /* substitution is needed */
                  switch (++which)
                  {  case 1:
                        /* substitute in the first null position */
                        tuple = expand_tuple(mpl, tuple,
                           copy_symbol(mpl, tr ? col->sym : row));
                        break;
                     case 2:
                        /* substitute in the second null position */
                        tuple = expand_tuple(mpl, tuple,
                           copy_symbol(mpl, tr ? row : col->sym));
                        break;
                     default:
                        xassert(which != which);
                  }
               }
               else
               {  /* copy symbol from the slice */
                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
                     temp->sym));
               }
            }
            xassert(which == 2);
            /* read value and assign it to new parameter member */
            if (!is_symbol(mpl))
            {  int lack = slice_dimen(mpl, col);
               if (lack == 1)
                  error(mpl, "one item missing in data group beginning "
                     "with %s", format_symbol(mpl, row));
               else
                  error(mpl, "%d items missing in data group beginning "
                     "with %s", lack, format_symbol(mpl, row));
            }
            read_value(mpl, par, tuple);
         }
         /* delete the row symbol */
         delete_symbol(mpl, row);
      }
      /* delete the column list */
      delete_slice(mpl, list);
      return;
}

/*----------------------------------------------------------------------
-- tabbing_format - read parameter data block in tabbing format.
--
-- This routine reads parameter data block using the syntax:
--
-- <tabbing format> ::=  <prefix> <name>  , ... , <name>  , := ,
--    <symbol> , ... , <symbol> , <value> , ... , <value> ,
--    <symbol> , ... , <symbol> , <value> , ... , <value> ,
--     .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
--    <symbol> , ... , <symbol> , <value> , ... , <value>
-- <prefix> ::= <empty>
-- <prefix> ::= <set name> :
--
-- where <names> are names of parameters (all the parameters must be
-- subscripted and have identical dimensions), <symbols> are symbols
-- used to define subscripts of parameter members, <values> are numeric
-- or symbolic values assigned to the corresponding parameter members.
-- Optional <prefix> may specify a simple set, in which case n-tuples
-- built of <symbols> for each row of the data table (i.e. subscripts
-- of parameter members) are added to the specified set. Commae between
-- data items are optional and may be omitted anywhere.
--
-- If the parameter altval is not NULL, it specifies a default value
-- provided for all the parameters specified in the data block.  */

void tabbing_format
(     MPL *mpl,
      SYMBOL *altval          /* not changed */
)
{     SET *set = NULL;
      PARAMETER *par;
      SLICE *list, *col;
      TUPLE *tuple;
      int next_token, j, dim = 0;
      char *last_name = NULL;
      /* read the optional <prefix> */
      if (is_symbol(mpl))
      {  get_token(mpl /* <symbol> */);
         next_token = mpl->token;
         unget_token(mpl /* <symbol> */);
         if (next_token == T_COLON)
         {  /* select the set to saturate it with data */
            set = select_set(mpl, mpl->image);
            /* the set must be simple (i.e. not set of sets) */
            if (set->dim != 0)
               error(mpl, "%s must be a simple set", set->name);
            /* and must not be defined yet */
            if (set->array->head != NULL)
               error(mpl, "%s already defined", set->name);
            /* add new (the only) member to the set and assign it empty
               elemental set */
            add_member(mpl, set->array, NULL)->value.set =
               create_elemset(mpl, set->dimen);
            last_name = set->name, dim = set->dimen;
            get_token(mpl /* <symbol> */);
            xassert(mpl->token == T_COLON);
            get_token(mpl /* : */);
         }
      }
      /* read the table heading that contains parameter names */
      list = create_slice(mpl);
      while (mpl->token != T_ASSIGN)
      {  /* there must be symbolic name of parameter */
         if (!is_symbol(mpl))
            error(mpl, "parameter name or := missing where expected");
         /* select the parameter to saturate it with data */
         par = select_parameter(mpl, mpl->image);
         /* the parameter must be subscripted */
         if (par->dim == 0)
            error(mpl, "%s not a subscripted parameter", mpl->image);
         /* the set (if specified) and all the parameters in the data
            block must have identical dimension */
         if (dim != 0 && par->dim != dim)
         {  xassert(last_name != NULL);
            error(mpl, "%s has dimension %d while %s has dimension %d",
               last_name, dim, par->name, par->dim);
         }
         /* set default value for the parameter (if specified) */
         if (altval != NULL)
            set_default(mpl, par, copy_symbol(mpl, altval));
         /* append the parameter to the column list */
         list = expand_slice(mpl, list, (SYMBOL *)par);
         last_name = par->name, dim = par->dim;
         get_token(mpl /* <symbol> */);
         /* skip optional comma */
         if (mpl->token == T_COMMA) get_token(mpl /* , */);
      }
      if (slice_dimen(mpl, list) == 0)
         error(mpl, "at least one parameter name required");
      get_token(mpl /* := */);
      /* skip optional comma */
      if (mpl->token == T_COMMA) get_token(mpl /* , */);
      /* read rows that contain tabbing data */
      while (is_symbol(mpl))
      {  /* read subscript list */
         tuple = create_tuple(mpl);
         for (j = 1; j <= dim; j++)
         {  /* read j-th subscript */
            if (!is_symbol(mpl))
            {  int lack = slice_dimen(mpl, list) + dim - j + 1;
               xassert(tuple != NULL);
               xassert(lack > 1);
               error(mpl, "%d items missing in data group beginning wit"
                  "h %s", lack, format_symbol(mpl, tuple->sym));
            }
            /* read and append j-th subscript to the n-tuple */
            tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
            /* skip optional comma *between* <symbols> */
            if (j < dim && mpl->token == T_COMMA)
               get_token(mpl /* , */);
         }
         /* if the set is specified, add to it new n-tuple, which is a
            copy of the subscript list just read */
         if (set != NULL)
            check_then_add(mpl, set->array->head->value.set,
               copy_tuple(mpl, tuple));
         /* skip optional comma between <symbol> and <value> */
         if (mpl->token == T_COMMA) get_token(mpl /* , */);
         /* read values accordingly to the column list */
         for (col = list; col != NULL; col = col->next)
         {  /* if the token is single point, no value is provided */
            if (is_literal(mpl, "."))
            {  get_token(mpl /* . */);
               continue;
            }
            /* read value and assign it to new parameter member */
            if (!is_symbol(mpl))
            {  int lack = slice_dimen(mpl, col);
               xassert(tuple != NULL);
               if (lack == 1)
                  error(mpl, "one item missing in data group beginning "
                     "with %s", format_symbol(mpl, tuple->sym));
               else
                  error(mpl, "%d items missing in data group beginning "
                     "with %s", lack, format_symbol(mpl, tuple->sym));
            }
            read_value(mpl, (PARAMETER *)col->sym, copy_tuple(mpl,
               tuple));
            /* skip optional comma preceding the next value */
            if (col->next != NULL && mpl->token == T_COMMA)
               get_token(mpl /* , */);
         }
         /* delete the original subscript list */
         delete_tuple(mpl, tuple);
         /* skip optional comma (only if there is next data group) */
         if (mpl->token == T_COMMA)
         {  get_token(mpl /* , */);
            if (!is_symbol(mpl)) unget_token(mpl /* , */);
         }
      }
      /* delete the column list (it contains parameters, not symbols,
         so nullify it before) */
      for (col = list; col != NULL; col = col->next) col->sym = NULL;
      delete_slice(mpl, list);
      return;
}

/*----------------------------------------------------------------------
-- parameter_data - read parameter data.
--
-- This routine reads parameter data using the syntax:
--
-- <parameter data> ::= param <default value> : <tabbing format> ;
-- <parameter data> ::= param <parameter name> <default value>
--                      <assignments> ;
-- <parameter name> ::= <symbolic name>
-- <default value> ::= <empty>
-- <default value> ::= default <symbol>
-- <assignments> ::= <empty>
-- <assignments> ::= <assignments> , :=
-- <assignments> ::= <assignments> , [ <symbol list> ]
-- <assignments> ::= <assignments> , <plain format>
-- <assignemnts> ::= <assignments> , : <tabular format>
-- <assignments> ::= <assignments> , (tr) <tabular format>
-- <assignments> ::= <assignments> , (tr) : <tabular format>
--
-- Commae in <assignments> are optional and may be omitted anywhere. */

void parameter_data(MPL *mpl)
{     PARAMETER *par;
      SYMBOL *altval = NULL;
      SLICE *slice;
      int tr = 0;
      xassert(is_literal(mpl, "param"));
      get_token(mpl /* param */);
      /* read optional default value */
      if (is_literal(mpl, "default"))
      {  get_token(mpl /* default */);
         if (!is_symbol(mpl))
            error(mpl, "default value missing where expected");
         altval = read_symbol(mpl);
         /* if the default value follows the keyword 'param', the next
            token must be only the colon */
         if (mpl->token != T_COLON)
            error(mpl, "colon missing where expected");
      }
      /* being used after the keyword 'param' or the optional default
         value the colon begins data in the tabbing format */
      if (mpl->token == T_COLON)
      {  get_token(mpl /* : */);
         /* skip optional comma */
         if (mpl->token == T_COMMA) get_token(mpl /* , */);
         /* read parameter data in the tabbing format */
         tabbing_format(mpl, altval);
         /* on reading data in the tabbing format the default value is
            always copied, so delete the original symbol */
         if (altval != NULL) delete_symbol(mpl, altval);
         /* the next token must be only semicolon */
         if (mpl->token != T_SEMICOLON)
            error(mpl, "symbol, number, or semicolon missing where expe"
               "cted");
         get_token(mpl /* ; */);
         goto done;
      }
      /* in other cases there must be symbolic name of parameter, which
         follows the keyword 'param' */
      if (!is_symbol(mpl))
         error(mpl, "parameter name missing where expected");
      /* select the parameter to saturate it with data */
      par = select_parameter(mpl, mpl->image);
      get_token(mpl /* <symbol> */);
      /* read optional default value */
      if (is_literal(mpl, "default"))
      {  get_token(mpl /* default */);
         if (!is_symbol(mpl))
            error(mpl, "default value missing where expected");
         altval = read_symbol(mpl);
         /* set default value for the parameter */
         set_default(mpl, par, altval);
      }
      /* create initial fake slice of all asterisks */
      slice = fake_slice(mpl, par->dim);
      /* read zero or more data assignments */
      for (;;)
      {  /* skip optional comma */
         if (mpl->token == T_COMMA) get_token(mpl /* , */);
         /* process current assignment */
         if (mpl->token == T_ASSIGN)
         {  /* assignment ligature is non-significant element */
            get_token(mpl /* := */);
         }
         else if (mpl->token == T_LBRACKET)
         {  /* left bracket begins new slice; delete the current slice
               and read new one */
            delete_slice(mpl, slice);
            slice = read_slice(mpl, par->name, par->dim);
            /* each new slice resets the "transpose" indicator */
            tr = 0;
         }
         else if (is_symbol(mpl))
         {  /* number or symbol begins data in the plain format */
            plain_format(mpl, par, slice);
         }
         else if (mpl->token == T_COLON)
         {  /* colon begins data in the tabular format */
            if (par->dim == 0)
err1:          error(mpl, "%s not a subscripted parameter",
                  par->name);
            if (slice_arity(mpl, slice) != 2)
err2:          error(mpl, "slice currently used must specify 2 asterisk"
                  "s, not %d", slice_arity(mpl, slice));
            get_token(mpl /* : */);
            /* read parameter data in the tabular format */
            tabular_format(mpl, par, slice, tr);
         }
         else if (mpl->token == T_LEFT)
         {  /* left parenthesis begins the "transpose" indicator, which
               is followed by data in the tabular format */
            get_token(mpl /* ( */);
            if (!is_literal(mpl, "tr"))
err3:          error(mpl, "transpose indicator (tr) incomplete");
            if (par->dim == 0) goto err1;
            if (slice_arity(mpl, slice) != 2) goto err2;
            get_token(mpl /* tr */);
            if (mpl->token != T_RIGHT) goto err3;
            get_token(mpl /* ) */);
            /* in this case the colon is optional */
            if (mpl->token == T_COLON) get_token(mpl /* : */);
            /* set the "transpose" indicator */
            tr = 1;
            /* read parameter data in the tabular format */
            tabular_format(mpl, par, slice, tr);
         }
         else if (mpl->token == T_SEMICOLON)
         {  /* semicolon terminates the data block */
            get_token(mpl /* ; */);
            break;
         }
         else
            error(mpl, "syntax error in parameter data block");
      }
      /* delete the current slice */
      delete_slice(mpl, slice);
done: return;
}

/*----------------------------------------------------------------------
-- data_section - read data section.
--
-- This routine reads data section using the syntax:
--
-- <data section> ::= <empty>
-- <data section> ::= <data section> <data block> ;
-- <data block> ::= <set data>
-- <data block> ::= <parameter data>
--
-- Reading data section is terminated by either the keyword 'end' or
-- the end of file. */

void data_section(MPL *mpl)
{     while (!(mpl->token == T_EOF || is_literal(mpl, "end")))
      {  if (is_literal(mpl, "set"))
            set_data(mpl);
         else if (is_literal(mpl, "param"))
            parameter_data(mpl);
         else
            error(mpl, "syntax error in data section");
      }
      return;
}

/* eof */