aboutsummaryrefslogtreecommitdiffstats
path: root/test/monniaux/glpk-4.65
diff options
context:
space:
mode:
authorDavid Monniaux <david.monniaux@univ-grenoble-alpes.fr>2019-06-06 20:09:32 +0200
committerDavid Monniaux <david.monniaux@univ-grenoble-alpes.fr>2019-06-06 20:09:32 +0200
commitfeb8ebaeb76fa1c94de2dd7c4e5a0999b313f8c6 (patch)
tree273140847406f67c338677fcd1a8a1bed79579ce /test/monniaux/glpk-4.65
parentf3a13e7cb3d2f0758eb418050d48a240798f2f86 (diff)
downloadcompcert-kvx-feb8ebaeb76fa1c94de2dd7c4e5a0999b313f8c6.tar.gz
compcert-kvx-feb8ebaeb76fa1c94de2dd7c4e5a0999b313f8c6.zip
GLPK 4.65
Diffstat (limited to 'test/monniaux/glpk-4.65')
-rw-r--r--test/monniaux/glpk-4.65/Makefile36
-rw-r--r--test/monniaux/glpk-4.65/config.h31
-rw-r--r--test/monniaux/glpk-4.65/examples/glpsol.c1584
-rw-r--r--test/monniaux/glpk-4.65/src/amd/COPYING502
-rw-r--r--test/monniaux/glpk-4.65/src/amd/README58
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd.h67
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_1.c181
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_2.c1842
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_aat.c185
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_control.c64
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_defaults.c38
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_dump.c180
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_info.c120
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_internal.h117
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_order.c200
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_post_tree.c121
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_postorder.c207
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_preprocess.c119
-rw-r--r--test/monniaux/glpk-4.65/src/amd/amd_valid.c93
-rw-r--r--test/monniaux/glpk-4.65/src/api/advbas.c155
-rw-r--r--test/monniaux/glpk-4.65/src/api/asnhall.c163
-rw-r--r--test/monniaux/glpk-4.65/src/api/asnlp.c104
-rw-r--r--test/monniaux/glpk-4.65/src/api/asnokalg.c154
-rw-r--r--test/monniaux/glpk-4.65/src/api/ckasn.c78
-rw-r--r--test/monniaux/glpk-4.65/src/api/ckcnf.c82
-rw-r--r--test/monniaux/glpk-4.65/src/api/cplex.c1283
-rw-r--r--test/monniaux/glpk-4.65/src/api/cpp.c185
-rw-r--r--test/monniaux/glpk-4.65/src/api/cpxbas.c269
-rw-r--r--test/monniaux/glpk-4.65/src/api/graph.c504
-rw-r--r--test/monniaux/glpk-4.65/src/api/gridgen.c769
-rw-r--r--test/monniaux/glpk-4.65/src/api/intfeas1.c267
-rw-r--r--test/monniaux/glpk-4.65/src/api/maxffalg.c130
-rw-r--r--test/monniaux/glpk-4.65/src/api/maxflp.c114
-rw-r--r--test/monniaux/glpk-4.65/src/api/mcflp.c114
-rw-r--r--test/monniaux/glpk-4.65/src/api/mcfokalg.c221
-rw-r--r--test/monniaux/glpk-4.65/src/api/mcfrelax.c251
-rw-r--r--test/monniaux/glpk-4.65/src/api/minisat1.c161
-rw-r--r--test/monniaux/glpk-4.65/src/api/mpl.c269
-rw-r--r--test/monniaux/glpk-4.65/src/api/mps.c1452
-rw-r--r--test/monniaux/glpk-4.65/src/api/netgen.c1020
-rw-r--r--test/monniaux/glpk-4.65/src/api/npp.c143
-rw-r--r--test/monniaux/glpk-4.65/src/api/pript.c186
-rw-r--r--test/monniaux/glpk-4.65/src/api/prmip.c155
-rw-r--r--test/monniaux/glpk-4.65/src/api/prob.h286
-rw-r--r--test/monniaux/glpk-4.65/src/api/prob1.c1588
-rw-r--r--test/monniaux/glpk-4.65/src/api/prob2.c491
-rw-r--r--test/monniaux/glpk-4.65/src/api/prob3.c166
-rw-r--r--test/monniaux/glpk-4.65/src/api/prob4.c156
-rw-r--r--test/monniaux/glpk-4.65/src/api/prob5.c168
-rw-r--r--test/monniaux/glpk-4.65/src/api/prrngs.c302
-rw-r--r--test/monniaux/glpk-4.65/src/api/prsol.c202
-rw-r--r--test/monniaux/glpk-4.65/src/api/rdasn.c164
-rw-r--r--test/monniaux/glpk-4.65/src/api/rdcc.c162
-rw-r--r--test/monniaux/glpk-4.65/src/api/rdcnf.c136
-rw-r--r--test/monniaux/glpk-4.65/src/api/rdipt.c185
-rw-r--r--test/monniaux/glpk-4.65/src/api/rdmaxf.c163
-rw-r--r--test/monniaux/glpk-4.65/src/api/rdmcf.c186
-rw-r--r--test/monniaux/glpk-4.65/src/api/rdmip.c172
-rw-r--r--test/monniaux/glpk-4.65/src/api/rdprob.c377
-rw-r--r--test/monniaux/glpk-4.65/src/api/rdsol.c225
-rw-r--r--test/monniaux/glpk-4.65/src/api/rmfgen.c368
-rw-r--r--test/monniaux/glpk-4.65/src/api/strong.c110
-rw-r--r--test/monniaux/glpk-4.65/src/api/topsort.c123
-rw-r--r--test/monniaux/glpk-4.65/src/api/wcliqex.c122
-rw-r--r--test/monniaux/glpk-4.65/src/api/weak.c150
-rw-r--r--test/monniaux/glpk-4.65/src/api/wrasn.c107
-rw-r--r--test/monniaux/glpk-4.65/src/api/wrcc.c102
-rw-r--r--test/monniaux/glpk-4.65/src/api/wrcnf.c87
-rw-r--r--test/monniaux/glpk-4.65/src/api/wript.c124
-rw-r--r--test/monniaux/glpk-4.65/src/api/wrmaxf.c104
-rw-r--r--test/monniaux/glpk-4.65/src/api/wrmcf.c122
-rw-r--r--test/monniaux/glpk-4.65/src/api/wrmip.c122
-rw-r--r--test/monniaux/glpk-4.65/src/api/wrprob.c166
-rw-r--r--test/monniaux/glpk-4.65/src/api/wrsol.c174
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/btf.c569
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/btf.h207
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/btfint.c407
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/btfint.h73
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/fhv.c586
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/fhv.h114
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/fhvint.c168
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/fhvint.h78
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/ifu.c392
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/ifu.h99
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/luf.c713
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/luf.h227
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/lufint.c182
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/lufint.h73
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/scf.c523
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/scf.h211
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/scfint.c255
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/scfint.h89
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/sgf.c1443
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/sgf.h203
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/sva.c572
-rw-r--r--test/monniaux/glpk-4.65/src/bflib/sva.h161
-rw-r--r--test/monniaux/glpk-4.65/src/colamd/COPYING502
-rw-r--r--test/monniaux/glpk-4.65/src/colamd/README98
-rw-r--r--test/monniaux/glpk-4.65/src/colamd/colamd.c3622
-rw-r--r--test/monniaux/glpk-4.65/src/colamd/colamd.h69
-rw-r--r--test/monniaux/glpk-4.65/src/draft/bfd.c544
-rw-r--r--test/monniaux/glpk-4.65/src/draft/bfd.h107
-rw-r--r--test/monniaux/glpk-4.65/src/draft/bfx.c89
-rw-r--r--test/monniaux/glpk-4.65/src/draft/bfx.h67
-rw-r--r--test/monniaux/glpk-4.65/src/draft/draft.h22
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpapi06.c860
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpapi07.c499
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpapi08.c388
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpapi09.c798
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpapi10.c305
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpapi12.c2185
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpapi13.c710
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glphbm.c533
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glphbm.h127
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpios01.c1685
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpios02.c826
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpios03.c1512
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpios07.c551
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpios09.c664
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpios11.c435
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpios12.c177
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpipm.c1144
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpipm.h36
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpmat.c924
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpmat.h198
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glprgr.c173
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glprgr.h34
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpscl.c478
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpspm.c847
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpspm.h165
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpssx.h437
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpssx01.c839
-rw-r--r--test/monniaux/glpk-4.65/src/draft/glpssx02.c523
-rw-r--r--test/monniaux/glpk-4.65/src/draft/ios.h547
-rw-r--r--test/monniaux/glpk-4.65/src/draft/lux.c1030
-rw-r--r--test/monniaux/glpk-4.65/src/draft/lux.h220
-rw-r--r--test/monniaux/glpk-4.65/src/env/alloc.c252
-rw-r--r--test/monniaux/glpk-4.65/src/env/dlsup.c167
-rw-r--r--test/monniaux/glpk-4.65/src/env/env.c316
-rw-r--r--test/monniaux/glpk-4.65/src/env/env.h274
-rw-r--r--test/monniaux/glpk-4.65/src/env/error.c200
-rw-r--r--test/monniaux/glpk-4.65/src/env/stdc.c98
-rw-r--r--test/monniaux/glpk-4.65/src/env/stdc.h73
-rw-r--r--test/monniaux/glpk-4.65/src/env/stdout.c262
-rw-r--r--test/monniaux/glpk-4.65/src/env/stream.c517
-rw-r--r--test/monniaux/glpk-4.65/src/env/time.c150
-rw-r--r--test/monniaux/glpk-4.65/src/env/tls.c128
-rw-r--r--test/monniaux/glpk-4.65/src/glpk.h1175
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/cfg.c409
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/cfg.h138
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/cfg1.c703
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/cfg2.c91
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/clqcut.c134
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/covgen.c885
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/fpump.c360
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/gmicut.c284
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/gmigen.c142
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/mirgen.c1529
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/spv.c303
-rw-r--r--test/monniaux/glpk-4.65/src/intopt/spv.h83
-rw-r--r--test/monniaux/glpk-4.65/src/minisat/LICENSE20
-rw-r--r--test/monniaux/glpk-4.65/src/minisat/README22
-rw-r--r--test/monniaux/glpk-4.65/src/minisat/minisat.c1315
-rw-r--r--test/monniaux/glpk-4.65/src/minisat/minisat.h230
-rw-r--r--test/monniaux/glpk-4.65/src/misc/avl.c405
-rw-r--r--test/monniaux/glpk-4.65/src/misc/avl.h73
-rw-r--r--test/monniaux/glpk-4.65/src/misc/bignum.c286
-rw-r--r--test/monniaux/glpk-4.65/src/misc/bignum.h37
-rw-r--r--test/monniaux/glpk-4.65/src/misc/dimacs.c147
-rw-r--r--test/monniaux/glpk-4.65/src/misc/dimacs.h81
-rw-r--r--test/monniaux/glpk-4.65/src/misc/dmp.c243
-rw-r--r--test/monniaux/glpk-4.65/src/misc/dmp.h63
-rw-r--r--test/monniaux/glpk-4.65/src/misc/ffalg.c221
-rw-r--r--test/monniaux/glpk-4.65/src/misc/ffalg.h34
-rw-r--r--test/monniaux/glpk-4.65/src/misc/fp2rat.c164
-rw-r--r--test/monniaux/glpk-4.65/src/misc/fvs.c137
-rw-r--r--test/monniaux/glpk-4.65/src/misc/fvs.h76
-rw-r--r--test/monniaux/glpk-4.65/src/misc/gcd.c102
-rw-r--r--test/monniaux/glpk-4.65/src/misc/jd.c152
-rw-r--r--test/monniaux/glpk-4.65/src/misc/jd.h32
-rw-r--r--test/monniaux/glpk-4.65/src/misc/keller.c235
-rw-r--r--test/monniaux/glpk-4.65/src/misc/keller.h34
-rw-r--r--test/monniaux/glpk-4.65/src/misc/ks.c466
-rw-r--r--test/monniaux/glpk-4.65/src/misc/ks.h44
-rw-r--r--test/monniaux/glpk-4.65/src/misc/mc13d.c314
-rw-r--r--test/monniaux/glpk-4.65/src/misc/mc13d.h34
-rw-r--r--test/monniaux/glpk-4.65/src/misc/mc21a.c301
-rw-r--r--test/monniaux/glpk-4.65/src/misc/mc21a.h34
-rw-r--r--test/monniaux/glpk-4.65/src/misc/misc.h61
-rw-r--r--test/monniaux/glpk-4.65/src/misc/mt1.c1110
-rw-r--r--test/monniaux/glpk-4.65/src/misc/mt1.f277
-rw-r--r--test/monniaux/glpk-4.65/src/misc/mt1.h34
-rw-r--r--test/monniaux/glpk-4.65/src/misc/mygmp.c1162
-rw-r--r--test/monniaux/glpk-4.65/src/misc/mygmp.h254
-rw-r--r--test/monniaux/glpk-4.65/src/misc/okalg.c382
-rw-r--r--test/monniaux/glpk-4.65/src/misc/okalg.h35
-rw-r--r--test/monniaux/glpk-4.65/src/misc/qmd.c584
-rw-r--r--test/monniaux/glpk-4.65/src/misc/qmd.h58
-rw-r--r--test/monniaux/glpk-4.65/src/misc/relax4.c2850
-rw-r--r--test/monniaux/glpk-4.65/src/misc/relax4.h102
-rw-r--r--test/monniaux/glpk-4.65/src/misc/rng.c227
-rw-r--r--test/monniaux/glpk-4.65/src/misc/rng.h67
-rw-r--r--test/monniaux/glpk-4.65/src/misc/rng1.c73
-rw-r--r--test/monniaux/glpk-4.65/src/misc/round2n.c64
-rw-r--r--test/monniaux/glpk-4.65/src/misc/str2int.c92
-rw-r--r--test/monniaux/glpk-4.65/src/misc/str2num.c110
-rw-r--r--test/monniaux/glpk-4.65/src/misc/strspx.c60
-rw-r--r--test/monniaux/glpk-4.65/src/misc/strtrim.c62
-rw-r--r--test/monniaux/glpk-4.65/src/misc/triang.c311
-rw-r--r--test/monniaux/glpk-4.65/src/misc/triang.h34
-rw-r--r--test/monniaux/glpk-4.65/src/misc/wclique.c242
-rw-r--r--test/monniaux/glpk-4.65/src/misc/wclique.h33
-rw-r--r--test/monniaux/glpk-4.65/src/misc/wclique1.c317
-rw-r--r--test/monniaux/glpk-4.65/src/misc/wclique1.h34
-rw-r--r--test/monniaux/glpk-4.65/src/mpl/mpl.h2598
-rw-r--r--test/monniaux/glpk-4.65/src/mpl/mpl1.c4718
-rw-r--r--test/monniaux/glpk-4.65/src/mpl/mpl2.c1202
-rw-r--r--test/monniaux/glpk-4.65/src/mpl/mpl3.c6100
-rw-r--r--test/monniaux/glpk-4.65/src/mpl/mpl4.c1426
-rw-r--r--test/monniaux/glpk-4.65/src/mpl/mpl5.c566
-rw-r--r--test/monniaux/glpk-4.65/src/mpl/mpl6.c1039
-rw-r--r--test/monniaux/glpk-4.65/src/mpl/mplsql.c1659
-rw-r--r--test/monniaux/glpk-4.65/src/mpl/mplsql.h63
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp.h645
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp1.c937
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp2.c1433
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp3.c2861
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp4.c1414
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp5.c809
-rw-r--r--test/monniaux/glpk-4.65/src/npp/npp6.c1500
-rw-r--r--test/monniaux/glpk-4.65/src/proxy/main.c.disabled87
-rw-r--r--test/monniaux/glpk-4.65/src/proxy/proxy.c1073
-rw-r--r--test/monniaux/glpk-4.65/src/proxy/proxy.h36
-rw-r--r--test/monniaux/glpk-4.65/src/proxy/proxy1.c88
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/simplex.h39
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxat.c265
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxat.h80
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxchuzc.c381
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxchuzc.h85
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxchuzr.c594
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxchuzr.h77
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxlp.c819
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxlp.h234
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxnt.c303
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxnt.h96
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxprim.c1860
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxprob.c679
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spxprob.h64
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spychuzc.c567
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spychuzc.h85
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spychuzr.c483
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spychuzr.h97
-rw-r--r--test/monniaux/glpk-4.65/src/simplex/spydual.c2101
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/README45
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/adler32.c169
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/compress.c80
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/crc32.c442
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/crc32.h441
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/deflate.c1834
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/deflate.h342
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/gzclose.c25
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/gzguts.h74
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/gzlib.c537
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/gzread.c653
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/gzwrite.c531
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/inffast.c340
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/inffast.h11
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/inffixed.h94
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/inflate.c1480
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/inflate.h122
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/inftrees.c330
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/inftrees.h62
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/trees.c1244
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/trees.h128
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/uncompr.c59
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/zconf.h168
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/zio.c92
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/zio.h37
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/zlib.h1613
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/zutil.c318
-rw-r--r--test/monniaux/glpk-4.65/src/zlib/zutil.h93
281 files changed, 126536 insertions, 0 deletions
diff --git a/test/monniaux/glpk-4.65/Makefile b/test/monniaux/glpk-4.65/Makefile
new file mode 100644
index 00000000..a069ed55
--- /dev/null
+++ b/test/monniaux/glpk-4.65/Makefile
@@ -0,0 +1,36 @@
+ALL_CFLAGS += -I src/amd -I src/colamd -I src/mpl -I src/simplex -I src/api -I src/intopt -I src/minisat -I src/npp -I src/zlib -I src/bflib -I src/env -I src/misc -I src/draft -I src
+
+include ../rules.mk
+
+LIBS = -lm
+
+src=examples/glpsol.c $(wildcard src/*/*.c)
+
+PRODUCTS?=glpsol.gcc.host glpsol.ccomp.host glpsol.gcc.k1c glpsol.gcc.o1.k1c glpsol.ccomp.k1c
+PRODUCTS_OUT=$(addsuffix .out,$(PRODUCTS))
+
+all: $(PRODUCTS)
+
+.PHONY:
+run: measures.csv
+
+
+glpsol.gcc.host: $(src:.c=.gcc.host.o) ../clock.gcc.host.o
+ $(CC) $(CFLAGS) $+ $(LIBS) -o $@
+glpsol.ccomp.host: $(src:.c=.ccomp.host.o) ../clock.gcc.host.o
+ $(CCOMP) $(CCOMPFLAGS) $+ $(LIBS) -o $@
+glpsol.gcc.k1c: $(src:.c=.gcc.k1c.o) ../clock.gcc.k1c.o
+ $(K1C_CC) $(K1C_CFLAGS) $+ $(LIBS) -o $@
+glpsol.gcc.o1.k1c: $(src:.c=.gcc.o1.k1c.o) ../clock.gcc.k1c.o
+ $(K1C_CC) $(K1C_CFLAGS_O1) $+ $(LIBS) -o $@
+glpsol.ccomp.k1c: $(src:.c=.ccomp.k1c.o) ../clock.gcc.k1c.o
+ $(K1C_CCOMP) $(K1C_CCOMPFLAGS) $+ $(LIBS) -o $@
+measures.csv: $(PRODUCTS_OUT)
+ echo "benches, gcc host,ccomp host,gcc k1c,gcc o1 k1c,ccomp k1c" > $@
+
+.SECONDARY:
+
+.PHONY:
+clean:
+ rm -f *.o *.s *.k1c *.csv
+
diff --git a/test/monniaux/glpk-4.65/config.h b/test/monniaux/glpk-4.65/config.h
new file mode 100644
index 00000000..35a44f00
--- /dev/null
+++ b/test/monniaux/glpk-4.65/config.h
@@ -0,0 +1,31 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in (GLPK configuration template file) */
+
+#define HAVE_SYS_TIME_H 1
+/* defined if the <sys/time.h> header can be used */
+
+#define HAVE_GETTIMEOFDAY 1
+/* defined if the gettimeofday function can be used */
+
+/* #undef HAVE_GMP */
+/* defined if the GNU MP bignum library is available */
+/* requires <gmp.h> and -lgmp */
+
+/* #undef HAVE_LTDL */
+/* defined if the GNU Libtool shared library support is enabled */
+/* requires <ltdl.h> and -lltdl */
+
+/* #undef HAVE_DLFCN */
+/* defined if the POSIX shared library support is enabled */
+/* requires <dlfcn.h> */
+
+/* #undef ODBC_DLNAME */
+/* ODBC shared library name if this feature is enabled */
+
+/* #undef MYSQL_DLNAME */
+/* MySQL shared library name if this feature is enabled */
+
+/* #undef TLS */
+/* thread local storage-class specifier for re-entrancy (if any) */
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/examples/glpsol.c b/test/monniaux/glpk-4.65/examples/glpsol.c
new file mode 100644
index 00000000..7a0c42c8
--- /dev/null
+++ b/test/monniaux/glpk-4.65/examples/glpsol.c
@@ -0,0 +1,1584 @@
+/* glpsol.c (stand-alone GLPK LP/MIP solver) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2017 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/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glpk.h>
+
+#define xassert glp_assert
+#define xerror glp_error
+#define xprintf glp_printf
+
+struct csa
+{ /* common storage area */
+ glp_prob *prob;
+ /* LP/MIP problem object */
+ glp_bfcp bfcp;
+ /* basis factorization control parameters */
+ glp_smcp smcp;
+ /* simplex method control parameters */
+ glp_iptcp iptcp;
+ /* interior-point method control parameters */
+ glp_iocp iocp;
+ /* integer optimizer control parameters */
+ glp_tran *tran;
+ /* model translator workspace */
+ glp_graph *graph;
+ /* network problem object */
+ int format;
+ /* problem file format: */
+#define FMT_MPS_DECK 1 /* fixed MPS */
+#define FMT_MPS_FILE 2 /* free MPS */
+#define FMT_LP 3 /* CPLEX LP */
+#define FMT_GLP 4 /* GLPK LP/MIP */
+#define FMT_MATHPROG 5 /* MathProg */
+#define FMT_MIN_COST 6 /* DIMACS min-cost flow */
+#define FMT_MAX_FLOW 7 /* DIMACS maximum flow */
+#if 1 /* 06/VIII-2011 */
+#define FMT_CNF 8 /* DIMACS CNF-SAT */
+#endif
+ const char *in_file;
+ /* name of input problem file */
+#define DATA_MAX 10
+ /* maximal number of input data files */
+ int ndf;
+ /* number of input data files specified */
+ const char *in_data[1+DATA_MAX];
+ /* name(s) of input data file(s) */
+ const char *out_dpy;
+ /* name of output file to send display output; NULL means the
+ display output is sent to the terminal */
+ int seed;
+ /* seed value to be passed to the MathProg translator; initially
+ set to 1; 0x80000000 means the value is omitted */
+ int solution;
+ /* solution type flag: */
+#define SOL_BASIC 1 /* basic */
+#define SOL_INTERIOR 2 /* interior-point */
+#define SOL_INTEGER 3 /* mixed integer */
+ const char *in_res;
+ /* name of input solution file in raw format */
+ int dir;
+ /* optimization direction flag:
+ 0 - not specified
+ GLP_MIN - minimization
+ GLP_MAX - maximization */
+ int scale;
+ /* automatic problem scaling flag */
+ const char *out_sol;
+ /* name of output solution file in printable format */
+ const char *out_res;
+ /* name of output solution file in raw format */
+ const char *out_ranges;
+ /* name of output file to write sensitivity analysis report */
+ int check;
+ /* input data checking flag; no solution is performed */
+ const char *new_name;
+ /* new name to be assigned to the problem */
+#if 1 /* 18/I-2018 */
+ int hide;
+ /* clear all symbolic names in the problem object */
+#endif
+ const char *out_mps;
+ /* name of output problem file in fixed MPS format */
+ const char *out_freemps;
+ /* name of output problem file in free MPS format */
+ const char *out_cpxlp;
+ /* name of output problem file in CPLEX LP format */
+ const char *out_glp;
+ /* name of output problem file in GLPK format */
+#if 0
+ const char *out_pb;
+ /* name of output problem file in OPB format */
+ const char *out_npb;
+ /* name of output problem file in normalized OPB format */
+#endif
+#if 1 /* 06/VIII-2011 */
+ const char *out_cnf;
+ /* name of output problem file in DIMACS CNF-SAT format */
+#endif
+ const char *log_file;
+ /* name of output file to hardcopy terminal output */
+ int crash;
+ /* initial basis option: */
+#define USE_STD_BASIS 1 /* use standard basis */
+#define USE_ADV_BASIS 2 /* use advanced basis */
+#define USE_CPX_BASIS 3 /* use Bixby's basis */
+#define USE_INI_BASIS 4 /* use initial basis from ini_file */
+ const char *ini_file;
+ /* name of input file containing initial basis */
+ int exact;
+ /* flag to use glp_exact rather than glp_simplex */
+ int xcheck;
+ /* flag to check final basis with glp_exact */
+ int nomip;
+ /* flag to consider MIP as pure LP */
+#if 1 /* 15/VIII-2011 */
+ int minisat;
+ /* option to solve feasibility problem with MiniSat solver */
+ int use_bnd;
+ /* option to bound objective function */
+ int obj_bnd;
+ /* upper (minization) or lower (maximization) objective bound */
+#endif
+#if 1 /* 11/VII-2013 */
+ const char *use_sol;
+ /* name of input mip solution file in GLPK format */
+#endif
+};
+
+static int str2int(const char *s, int *x)
+{ /* convert string to integer */
+ long t;
+ char *endptr;
+ t = strtol(s, &endptr, 10);
+ if (*endptr != '\0')
+ return 2;
+ if (!(INT_MIN <= t && t <= INT_MAX))
+ return 1;
+ *x = t;
+#if 0
+ xprintf("str2int: x = %d\n", *x);
+#endif
+ return 0;
+}
+
+static int str2num(const char *s, double *x)
+{ /* convert string to floating point */
+ double t;
+ char *endptr;
+ t = strtod(s, &endptr);
+ if (*endptr != '\0')
+ return 2;
+ if (!(-DBL_MAX <= t && t <= +DBL_MAX))
+ return 1;
+ *x = t;
+#if 0
+ xprintf("str2num: x = %g\n", *x);
+#endif
+ return 0;
+}
+
+static void print_help(const char *my_name)
+{ /* print help information */
+ xprintf("Usage: %s [options...] filename\n", my_name);
+ xprintf("\n");
+ xprintf("General options:\n");
+ xprintf(" --mps read LP/MIP problem in fixed MPS fo"
+ "rmat\n");
+ xprintf(" --freemps read LP/MIP problem in free MPS for"
+ "mat (default)\n");
+ xprintf(" --lp read LP/MIP problem in CPLEX LP for"
+ "mat\n");
+ xprintf(" --glp read LP/MIP problem in GLPK format "
+ "\n");
+ xprintf(" --math read LP/MIP model written in GNU Ma"
+ "thProg modeling\n");
+ xprintf(" language\n");
+ xprintf(" -m filename, --model filename\n");
+ xprintf(" read model section and optional dat"
+ "a section from\n");
+ xprintf(" filename (same as --math)\n");
+ xprintf(" -d filename, --data filename\n");
+ xprintf(" read data section from filename (fo"
+ "r --math only);\n");
+ xprintf(" if model file also has data section"
+ ", it is ignored\n");
+ xprintf(" -y filename, --display filename\n");
+ xprintf(" send display output to filename (fo"
+ "r --math only);\n");
+ xprintf(" by default the output is sent to te"
+ "rminal\n");
+ xprintf(" --seed value initialize pseudo-random number gen"
+ "erator used in\n");
+ xprintf(" MathProg model with specified seed "
+ "(any integer);\n");
+ xprintf(" if seed value is ?, some random see"
+ "d will be used\n");
+ xprintf(" --mincost read min-cost flow problem in DIMAC"
+ "S format\n");
+ xprintf(" --maxflow read maximum flow problem in DIMACS"
+ " format\n");
+#if 1 /* 06/VIII-2011 */
+ xprintf(" --cnf read CNF-SAT problem in DIMACS form"
+ "at\n");
+#endif
+ xprintf(" --simplex use simplex method (default)\n");
+ xprintf(" --interior use interior point method (LP only)"
+ "\n");
+ xprintf(" -r filename, --read filename\n");
+ xprintf(" read solution from filename rather "
+ "to find it with\n");
+ xprintf(" the solver\n");
+ xprintf(" --min minimization\n");
+ xprintf(" --max maximization\n");
+ xprintf(" --scale scale problem (default)\n");
+ xprintf(" --noscale do not scale problem\n");
+ xprintf(" -o filename, --output filename\n");
+ xprintf(" write solution to filename in print"
+ "able format\n");
+ xprintf(" -w filename, --write filename\n");
+ xprintf(" write solution to filename in plain"
+ " text format\n");
+ xprintf(" --ranges filename\n");
+ xprintf(" write sensitivity analysis report t"
+ "o filename in\n");
+ xprintf(" printable format (simplex only)\n");
+ xprintf(" --tmlim nnn limit solution time to nnn seconds "
+ "\n");
+ xprintf(" --memlim nnn limit available memory to nnn megab"
+ "ytes\n");
+ xprintf(" --check do not solve problem, check input d"
+ "ata only\n");
+ xprintf(" --name probname change problem name to probname\n");
+#if 1 /* 18/I-2018 */
+ xprintf(" --hide remove all symbolic names from prob"
+ "lem object\n");
+#endif
+ xprintf(" --wmps filename write problem to filename in fixed "
+ "MPS format\n");
+ xprintf(" --wfreemps filename\n");
+ xprintf(" write problem to filename in free M"
+ "PS format\n");
+ xprintf(" --wlp filename write problem to filename in CPLEX "
+ "LP format\n");
+ xprintf(" --wglp filename write problem to filename in GLPK f"
+ "ormat\n");
+#if 0
+ xprintf(" --wpb filename write problem to filename in OPB fo"
+ "rmat\n");
+ xprintf(" --wnpb filename write problem to filename in normal"
+ "ized OPB format\n");
+#endif
+#if 1 /* 06/VIII-2011 */
+ xprintf(" --wcnf filename write problem to filename in DIMACS"
+ " CNF-SAT format\n");
+#endif
+ xprintf(" --log filename write copy of terminal output to fi"
+ "lename\n");
+ xprintf(" -h, --help display this help information and e"
+ "xit\n");
+ xprintf(" -v, --version display program version and exit\n")
+ ;
+ xprintf("\n");
+ xprintf("LP basis factorization options:\n");
+#if 0 /* 08/III-2014 */
+ xprintf(" --luf LU + Forrest-Tomlin update\n");
+ xprintf(" (faster, less stable; default)\n");
+ xprintf(" --cbg LU + Schur complement + Bartels-Gol"
+ "ub update\n");
+ xprintf(" (slower, more stable)\n");
+ xprintf(" --cgr LU + Schur complement + Givens rota"
+ "tion update\n");
+ xprintf(" (slower, more stable)\n");
+#else
+ xprintf(" --luf plain LU-factorization (default)\n")
+ ;
+ xprintf(" --btf block triangular LU-factorization\n"
+ );
+ xprintf(" --ft Forrest-Tomlin update (requires --l"
+ "uf; default)\n");
+ xprintf(" --cbg Schur complement + Bartels-Golub up"
+ "date\n");
+ xprintf(" --cgr Schur complement + Givens rotation "
+ "update\n");
+#endif
+ xprintf("\n");
+ xprintf("Options specific to simplex solver:\n");
+ xprintf(" --primal use primal simplex (default)\n");
+ xprintf(" --dual use dual simplex\n");
+ xprintf(" --std use standard initial basis of all s"
+ "lacks\n");
+ xprintf(" --adv use advanced initial basis (default"
+ ")\n");
+ xprintf(" --bib use Bixby's initial basis\n");
+ xprintf(" --ini filename use as initial basis previously sav"
+ "ed with -w\n");
+ xprintf(" (disables LP presolver)\n");
+ xprintf(" --steep use steepest edge technique (defaul"
+ "t)\n");
+ xprintf(" --nosteep use standard \"textbook\" pricing\n"
+ );
+ xprintf(" --relax use Harris' two-pass ratio test (de"
+ "fault)\n");
+ xprintf(" --norelax use standard \"textbook\" ratio tes"
+ "t\n");
+#if 0 /* 23/VI-2017 */
+#if 1 /* 28/III-2016 */
+ xprintf(" --flip use flip-flop ratio test (assumes -"
+ "-dual)\n");
+#endif
+#else
+ /* now this option is implemented in both primal and dual */
+ xprintf(" --flip use long-step ratio test\n");
+#endif
+ xprintf(" --presol use presolver (default; assumes --s"
+ "cale and --adv)\n");
+ xprintf(" --nopresol do not use presolver\n");
+ xprintf(" --exact use simplex method based on exact a"
+ "rithmetic\n");
+ xprintf(" --xcheck check final basis using exact arith"
+ "metic\n");
+ xprintf("\n");
+ xprintf("Options specific to interior-point solver:\n");
+ xprintf(" --nord use natural (original) ordering\n");
+ xprintf(" --qmd use quotient minimum degree orderin"
+ "g\n");
+ xprintf(" --amd use approximate minimum degree orde"
+ "ring (default)\n");
+ xprintf(" --symamd use approximate minimum degree orde"
+ "ring\n");
+ xprintf("\n");
+ xprintf("Options specific to MIP solver:\n");
+ xprintf(" --nomip consider all integer variables as c"
+ "ontinuous\n");
+ xprintf(" (allows solving MIP as pure LP)\n");
+ xprintf(" --first branch on first integer variable\n")
+ ;
+ xprintf(" --last branch on last integer variable\n");
+ xprintf(" --mostf branch on most fractional variable "
+ "\n");
+ xprintf(" --drtom branch using heuristic by Driebeck "
+ "and Tomlin\n");
+ xprintf(" (default)\n");
+ xprintf(" --pcost branch using hybrid pseudocost heur"
+ "istic (may be\n");
+ xprintf(" useful for hard instances)\n");
+ xprintf(" --dfs backtrack using depth first search "
+ "\n");
+ xprintf(" --bfs backtrack using breadth first searc"
+ "h\n");
+ xprintf(" --bestp backtrack using the best projection"
+ " heuristic\n");
+ xprintf(" --bestb backtrack using node with best loca"
+ "l bound\n");
+ xprintf(" (default)\n");
+ xprintf(" --intopt use MIP presolver (default)\n");
+ xprintf(" --nointopt do not use MIP presolver\n");
+ xprintf(" --binarize replace general integer variables b"
+ "y binary ones\n");
+ xprintf(" (assumes --intopt)\n");
+ xprintf(" --fpump apply feasibility pump heuristic\n")
+ ;
+#if 1 /* 29/VI-2013 */
+ xprintf(" --proxy [nnn] apply proximity search heuristic (n"
+ "nn is time limit\n");
+ xprintf(" in seconds; default is 60)\n");
+#endif
+ xprintf(" --gomory generate Gomory's mixed integer cut"
+ "s\n");
+ xprintf(" --mir generate MIR (mixed integer roundin"
+ "g) cuts\n");
+ xprintf(" --cover generate mixed cover cuts\n");
+ xprintf(" --clique generate clique cuts\n");
+ xprintf(" --cuts generate all cuts above\n");
+ xprintf(" --mipgap tol set relative mip gap tolerance to t"
+ "ol\n");
+#if 1 /* 15/VIII-2011 */
+ xprintf(" --minisat translate integer feasibility probl"
+ "em to CNF-SAT\n");
+ xprintf(" and solve it with MiniSat solver\n")
+ ;
+ xprintf(" --objbnd bound add inequality obj <= bound (minimi"
+ "zation) or\n");
+ xprintf(" obj >= bound (maximization) to inte"
+ "ger feasibility\n");
+ xprintf(" problem (assumes --minisat)\n");
+#endif
+ xprintf("\n");
+ xprintf("For description of the MPS and CPLEX LP formats see Refe"
+ "rence Manual.\n");
+ xprintf("For description of the modeling language see \"GLPK: Mod"
+ "eling Language\n");
+ xprintf("GNU MathProg\". Both documents are included in the GLPK "
+ "distribution.\n");
+ xprintf("\n");
+ xprintf("See GLPK web page at <http://www.gnu.org/software/glpk/g"
+ "lpk.html>.\n");
+ xprintf("\n");
+ xprintf("Please report bugs to <bug-glpk@gnu.org>.\n");
+ return;
+}
+
+static void print_version(int briefly)
+{ /* print version information */
+ xprintf("GLPSOL: GLPK LP/MIP Solver, v%s\n", glp_version());
+ if (briefly) goto done;
+ xprintf("Copyright (C) 2000-2017 Andrew Makhorin, Department for "
+ "Applied\n");
+ xprintf("Informatics, Moscow Aviation Institute, Moscow, Russia. "
+ "All rights\n");
+ xprintf("reserved. E-mail: <mao@gnu.org>.\n");
+ xprintf("\n");
+ xprintf("This program has ABSOLUTELY NO WARRANTY.\n");
+ xprintf("\n");
+ xprintf("This program is free software; you may re-distribute it "
+ "under the terms\n");
+ xprintf("of the GNU General Public License version 3 or later.\n")
+ ;
+done: return;
+}
+
+static int parse_cmdline(struct csa *csa, int argc, char *argv[])
+{ /* parse command-line parameters */
+ int k;
+#define p(str) (strcmp(argv[k], str) == 0)
+ for (k = 1; k < argc; k++)
+ { if (p("--mps"))
+ csa->format = FMT_MPS_DECK;
+ else if (p("--freemps"))
+ csa->format = FMT_MPS_FILE;
+ else if (p("--lp") || p("--cpxlp"))
+ csa->format = FMT_LP;
+ else if (p("--glp"))
+ csa->format = FMT_GLP;
+ else if (p("--math") || p("-m") || p("--model"))
+ csa->format = FMT_MATHPROG;
+ else if (p("-d") || p("--data"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No input data file specified\n");
+ return 1;
+ }
+ if (csa->ndf == DATA_MAX)
+ { xprintf("Too many input data files\n");
+ return 1;
+ }
+ csa->in_data[++(csa->ndf)] = argv[k];
+ }
+ else if (p("-y") || p("--display"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No display output file specified\n");
+ return 1;
+ }
+ if (csa->out_dpy != NULL)
+ { xprintf("Only one display output file allowed\n");
+ return 1;
+ }
+ csa->out_dpy = argv[k];
+ }
+ else if (p("--seed"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' ||
+ argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1]))
+ { xprintf("No seed value specified\n");
+ return 1;
+ }
+ if (strcmp(argv[k], "?") == 0)
+ csa->seed = 0x80000000;
+ else if (str2int(argv[k], &csa->seed))
+ { xprintf("Invalid seed value '%s'\n", argv[k]);
+ return 1;
+ }
+ }
+ else if (p("--mincost"))
+ csa->format = FMT_MIN_COST;
+ else if (p("--maxflow"))
+ csa->format = FMT_MAX_FLOW;
+#if 1 /* 06/VIII-2011 */
+ else if (p("--cnf"))
+ csa->format = FMT_CNF;
+#endif
+ else if (p("--simplex"))
+ csa->solution = SOL_BASIC;
+ else if (p("--interior"))
+ csa->solution = SOL_INTERIOR;
+#if 1 /* 28/V-2010 */
+ else if (p("--alien"))
+ csa->iocp.alien = GLP_ON;
+#endif
+ else if (p("-r") || p("--read"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No input solution file specified\n");
+ return 1;
+ }
+ if (csa->in_res != NULL)
+ { xprintf("Only one input solution file allowed\n");
+ return 1;
+ }
+ csa->in_res = argv[k];
+ }
+ else if (p("--min"))
+ csa->dir = GLP_MIN;
+ else if (p("--max"))
+ csa->dir = GLP_MAX;
+ else if (p("--scale"))
+ csa->scale = 1;
+ else if (p("--noscale"))
+ csa->scale = 0;
+ else if (p("-o") || p("--output"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No output solution file specified\n");
+ return 1;
+ }
+ if (csa->out_sol != NULL)
+ { xprintf("Only one output solution file allowed\n");
+ return 1;
+ }
+ csa->out_sol = argv[k];
+ }
+ else if (p("-w") || p("--write"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No output solution file specified\n");
+ return 1;
+ }
+ if (csa->out_res != NULL)
+ { xprintf("Only one output solution file allowed\n");
+ return 1;
+ }
+ csa->out_res = argv[k];
+ }
+ else if (p("--ranges") || p("--bounds"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No output file specified to write sensitivity a"
+ "nalysis report\n");
+ return 1;
+ }
+ if (csa->out_ranges != NULL)
+ { xprintf("Only one output file allowed to write sensitivi"
+ "ty analysis report\n");
+ return 1;
+ }
+ csa->out_ranges = argv[k];
+ }
+ else if (p("--tmlim"))
+ { int tm_lim;
+ k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No time limit specified\n");
+ return 1;
+ }
+ if (str2int(argv[k], &tm_lim) || tm_lim < 0)
+ { xprintf("Invalid time limit '%s'\n", argv[k]);
+ return 1;
+ }
+ if (tm_lim <= INT_MAX / 1000)
+ csa->smcp.tm_lim = csa->iocp.tm_lim = 1000 * tm_lim;
+ else
+ csa->smcp.tm_lim = csa->iocp.tm_lim = INT_MAX;
+ }
+ else if (p("--memlim"))
+ { int mem_lim;
+ k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No memory limit specified\n");
+ return 1;
+ }
+ if (str2int(argv[k], &mem_lim) || mem_lim < 1)
+ { xprintf("Invalid memory limit '%s'\n", argv[k]);
+ return 1;
+ }
+ glp_mem_limit(mem_lim);
+ }
+ else if (p("--check"))
+ csa->check = 1;
+ else if (p("--name"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No problem name specified\n");
+ return 1;
+ }
+ if (csa->new_name != NULL)
+ { xprintf("Only one problem name allowed\n");
+ return 1;
+ }
+ csa->new_name = argv[k];
+ }
+#if 1 /* 18/I-2018 */
+ else if (p("--hide"))
+ csa->hide = 1;
+#endif
+ else if (p("--wmps"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No fixed MPS output file specified\n");
+ return 1;
+ }
+ if (csa->out_mps != NULL)
+ { xprintf("Only one fixed MPS output file allowed\n");
+ return 1;
+ }
+ csa->out_mps = argv[k];
+ }
+ else if (p("--wfreemps"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No free MPS output file specified\n");
+ return 1;
+ }
+ if (csa->out_freemps != NULL)
+ { xprintf("Only one free MPS output file allowed\n");
+ return 1;
+ }
+ csa->out_freemps = argv[k];
+ }
+ else if (p("--wlp") || p("--wcpxlp") || p("--wlpt"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No CPLEX LP output file specified\n");
+ return 1;
+ }
+ if (csa->out_cpxlp != NULL)
+ { xprintf("Only one CPLEX LP output file allowed\n");
+ return 1;
+ }
+ csa->out_cpxlp = argv[k];
+ }
+ else if (p("--wglp"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No GLPK LP/MIP output file specified\n");
+ return 1;
+ }
+ if (csa->out_glp != NULL)
+ { xprintf("Only one GLPK LP/MIP output file allowed\n");
+ return 1;
+ }
+ csa->out_glp = argv[k];
+ }
+#if 0
+ else if (p("--wpb"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No problem output file specified\n");
+ return 1;
+ }
+ if (csa->out_pb != NULL)
+ { xprintf("Only one OPB output file allowed\n");
+ return 1;
+ }
+ csa->out_pb = argv[k];
+ }
+ else if (p("--wnpb"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No problem output file specified\n");
+ return 1;
+ }
+ if (csa->out_npb != NULL)
+ { xprintf("Only one normalized OPB output file allowed\n");
+ return 1;
+ }
+ csa->out_npb = argv[k];
+ }
+#endif
+#if 1 /* 06/VIII-2011 */
+ else if (p("--wcnf"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No problem output file specified\n");
+ return 1;
+ }
+ if (csa->out_cnf != NULL)
+ { xprintf("Only one output DIMACS CNF-SAT file allowed\n");
+ return 1;
+ }
+ csa->out_cnf = argv[k];
+ }
+#endif
+ else if (p("--log"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No log file specified\n");
+ return 1;
+ }
+ if (csa->log_file != NULL)
+ { xprintf("Only one log file allowed\n");
+ return 1;
+ }
+ csa->log_file = argv[k];
+ }
+ else if (p("-h") || p("--help"))
+ { print_help(argv[0]);
+ return -1;
+ }
+ else if (p("-v") || p("--version"))
+ { print_version(0);
+ return -1;
+ }
+#if 0 /* 08/III-2014 */
+ else if (p("--luf"))
+ csa->bfcp.type = GLP_BF_FT;
+ else if (p("--cbg"))
+ csa->bfcp.type = GLP_BF_BG;
+ else if (p("--cgr"))
+ csa->bfcp.type = GLP_BF_GR;
+#else
+ else if (p("--luf"))
+ { csa->bfcp.type &= 0x0F;
+ csa->bfcp.type |= GLP_BF_LUF;
+ }
+ else if (p("--btf"))
+ { csa->bfcp.type &= 0x0F;
+ csa->bfcp.type |= GLP_BF_BTF;
+ }
+ else if (p("--ft"))
+ { csa->bfcp.type &= 0xF0;
+ csa->bfcp.type |= GLP_BF_FT;
+ }
+ else if (p("--cbg"))
+ { csa->bfcp.type &= 0xF0;
+ csa->bfcp.type |= GLP_BF_BG;
+ }
+ else if (p("--cgr"))
+ { csa->bfcp.type &= 0xF0;
+ csa->bfcp.type |= GLP_BF_GR;
+ }
+#endif
+ else if (p("--primal"))
+ csa->smcp.meth = GLP_PRIMAL;
+ else if (p("--dual"))
+ csa->smcp.meth = GLP_DUAL;
+ else if (p("--std"))
+ csa->crash = USE_STD_BASIS;
+ else if (p("--adv"))
+ csa->crash = USE_ADV_BASIS;
+ else if (p("--bib"))
+ csa->crash = USE_CPX_BASIS;
+ else if (p("--ini"))
+ { csa->crash = USE_INI_BASIS;
+ csa->smcp.presolve = GLP_OFF;
+ k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No initial basis file specified\n");
+ return 1;
+ }
+ if (csa->ini_file != NULL)
+ { xprintf("Only one initial basis file allowed\n");
+ return 1;
+ }
+ csa->ini_file = argv[k];
+ }
+ else if (p("--steep"))
+ csa->smcp.pricing = GLP_PT_PSE;
+ else if (p("--nosteep"))
+ csa->smcp.pricing = GLP_PT_STD;
+ else if (p("--relax"))
+ csa->smcp.r_test = GLP_RT_HAR;
+ else if (p("--norelax"))
+ csa->smcp.r_test = GLP_RT_STD;
+#if 1 /* 28/III-2016 */
+ else if (p("--flip"))
+#if 0 /* 23/VI-2017 */
+ { csa->smcp.meth = GLP_DUAL;
+#else
+ /* now this option is implemented in both primal and dual */
+ {
+#endif
+ csa->smcp.r_test = GLP_RT_FLIP;
+ csa->iocp.flip = GLP_ON;
+ }
+#endif
+ else if (p("--presol"))
+ csa->smcp.presolve = GLP_ON;
+ else if (p("--nopresol"))
+ csa->smcp.presolve = GLP_OFF;
+ else if (p("--exact"))
+ csa->exact = 1;
+ else if (p("--xcheck"))
+ csa->xcheck = 1;
+ else if (p("--nord"))
+ csa->iptcp.ord_alg = GLP_ORD_NONE;
+ else if (p("--qmd"))
+ csa->iptcp.ord_alg = GLP_ORD_QMD;
+ else if (p("--amd"))
+ csa->iptcp.ord_alg = GLP_ORD_AMD;
+ else if (p("--symamd"))
+ csa->iptcp.ord_alg = GLP_ORD_SYMAMD;
+ else if (p("--nomip"))
+ csa->nomip = 1;
+ else if (p("--first"))
+ csa->iocp.br_tech = GLP_BR_FFV;
+ else if (p("--last"))
+ csa->iocp.br_tech = GLP_BR_LFV;
+ else if (p("--drtom"))
+ csa->iocp.br_tech = GLP_BR_DTH;
+ else if (p("--mostf"))
+ csa->iocp.br_tech = GLP_BR_MFV;
+ else if (p("--pcost"))
+ csa->iocp.br_tech = GLP_BR_PCH;
+ else if (p("--dfs"))
+ csa->iocp.bt_tech = GLP_BT_DFS;
+ else if (p("--bfs"))
+ csa->iocp.bt_tech = GLP_BT_BFS;
+ else if (p("--bestp"))
+ csa->iocp.bt_tech = GLP_BT_BPH;
+ else if (p("--bestb"))
+ csa->iocp.bt_tech = GLP_BT_BLB;
+ else if (p("--intopt"))
+ csa->iocp.presolve = GLP_ON;
+ else if (p("--nointopt"))
+ csa->iocp.presolve = GLP_OFF;
+ else if (p("--binarize"))
+ csa->iocp.presolve = csa->iocp.binarize = GLP_ON;
+ else if (p("--fpump"))
+ csa->iocp.fp_heur = GLP_ON;
+#if 1 /* 29/VI-2013 */
+ else if (p("--proxy"))
+ { csa->iocp.ps_heur = GLP_ON;
+ if (argv[k+1] && isdigit((unsigned char)argv[k+1][0]))
+ { int nnn;
+ k++;
+ if (str2int(argv[k], &nnn) || nnn < 1)
+ { xprintf("Invalid proxy time limit '%s'\n", argv[k]);
+ return 1;
+ }
+ csa->iocp.ps_tm_lim = 1000 * nnn;
+ }
+ }
+#endif
+ else if (p("--gomory"))
+ csa->iocp.gmi_cuts = GLP_ON;
+ else if (p("--mir"))
+ csa->iocp.mir_cuts = GLP_ON;
+ else if (p("--cover"))
+ csa->iocp.cov_cuts = GLP_ON;
+ else if (p("--clique"))
+ csa->iocp.clq_cuts = GLP_ON;
+ else if (p("--cuts"))
+ csa->iocp.gmi_cuts = csa->iocp.mir_cuts =
+ csa->iocp.cov_cuts = csa->iocp.clq_cuts = GLP_ON;
+ else if (p("--mipgap"))
+ { double mip_gap;
+ k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No relative gap tolerance specified\n");
+ return 1;
+ }
+ if (str2num(argv[k], &mip_gap) || mip_gap < 0.0)
+ { xprintf("Invalid relative mip gap tolerance '%s'\n",
+ argv[k]);
+ return 1;
+ }
+ csa->iocp.mip_gap = mip_gap;
+ }
+#if 1 /* 15/VIII-2011 */
+ else if (p("--minisat"))
+ csa->minisat = 1;
+ else if (p("--objbnd"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' ||
+ argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1]))
+ { xprintf("No objective bound specified\n");
+ return 1;
+ }
+ csa->minisat = 1;
+ csa->use_bnd = 1;
+ if (str2int(argv[k], &csa->obj_bnd))
+ { xprintf("Invalid objective bound '%s' (should be integer"
+ " value)\n", argv[k]);
+ return 1;
+ }
+ }
+#endif
+#if 1 /* 11/VII-2013 */
+ else if (p("--use"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No input MIP solution file specified\n");
+ return 1;
+ }
+ if (csa->use_sol != NULL)
+ { xprintf("Only one input MIP solution file allowed\n");
+ return 1;
+ }
+ csa->use_sol = argv[k];
+ }
+ else if (p("--save"))
+ { k++;
+ if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+ { xprintf("No output MIP solution file specified\n");
+ return 1;
+ }
+ if (csa->iocp.save_sol != NULL)
+ { xprintf("Only one output MIP solution file allowed\n");
+ return 1;
+ }
+ csa->iocp.save_sol = argv[k];
+ }
+#endif
+ else if (argv[k][0] == '-' ||
+ (argv[k][0] == '-' && argv[k][1] == '-'))
+ { xprintf("Invalid option '%s'; try %s --help\n",
+ argv[k], argv[0]);
+ return 1;
+ }
+ else
+ { if (csa->in_file != NULL)
+ { xprintf("Only one input problem file allowed\n");
+ return 1;
+ }
+ csa->in_file = argv[k];
+ }
+ }
+#undef p
+ return 0;
+}
+
+typedef struct { double rhs, pi; } v_data;
+typedef struct { double low, cap, cost, x; } a_data;
+
+#ifndef __WOE__
+int main(int argc, char *argv[])
+#else
+int __cdecl main(int argc, char *argv[])
+#endif
+{ /* stand-alone LP/MIP solver */
+ struct csa _csa, *csa = &_csa;
+ int ret;
+#if 0 /* 10/VI-2013 */
+ glp_long start;
+#else
+ double start;
+#endif
+ /* perform initialization */
+ csa->prob = glp_create_prob();
+ glp_get_bfcp(csa->prob, &csa->bfcp);
+ glp_init_smcp(&csa->smcp);
+ csa->smcp.presolve = GLP_ON;
+ glp_init_iptcp(&csa->iptcp);
+ glp_init_iocp(&csa->iocp);
+ csa->iocp.presolve = GLP_ON;
+ csa->tran = NULL;
+ csa->graph = NULL;
+ csa->format = FMT_MPS_FILE;
+ csa->in_file = NULL;
+ csa->ndf = 0;
+ csa->out_dpy = NULL;
+ csa->seed = 1;
+ csa->solution = SOL_BASIC;
+ csa->in_res = NULL;
+ csa->dir = 0;
+ csa->scale = 1;
+ csa->out_sol = NULL;
+ csa->out_res = NULL;
+ csa->out_ranges = NULL;
+ csa->check = 0;
+ csa->new_name = NULL;
+#if 1 /* 18/I-2018 */
+ csa->hide = 0;
+#endif
+ csa->out_mps = NULL;
+ csa->out_freemps = NULL;
+ csa->out_cpxlp = NULL;
+ csa->out_glp = NULL;
+#if 0
+ csa->out_pb = NULL;
+ csa->out_npb = NULL;
+#endif
+#if 1 /* 06/VIII-2011 */
+ csa->out_cnf = NULL;
+#endif
+ csa->log_file = NULL;
+ csa->crash = USE_ADV_BASIS;
+ csa->ini_file = NULL;
+ csa->exact = 0;
+ csa->xcheck = 0;
+ csa->nomip = 0;
+#if 1 /* 15/VIII-2011 */
+ csa->minisat = 0;
+ csa->use_bnd = 0;
+ csa->obj_bnd = 0;
+#endif
+#if 1 /* 11/VII-2013 */
+ csa->use_sol = NULL;
+#endif
+ /* parse command-line parameters */
+ ret = parse_cmdline(csa, argc, argv);
+ if (ret < 0)
+ { ret = EXIT_SUCCESS;
+ goto done;
+ }
+ if (ret > 0)
+ { ret = EXIT_FAILURE;
+ goto done;
+ }
+ /*--------------------------------------------------------------*/
+ /* remove all output files specified in the command line */
+ if (csa->out_dpy != NULL) remove(csa->out_dpy);
+ if (csa->out_sol != NULL) remove(csa->out_sol);
+ if (csa->out_res != NULL) remove(csa->out_res);
+ if (csa->out_ranges != NULL) remove(csa->out_ranges);
+ if (csa->out_mps != NULL) remove(csa->out_mps);
+ if (csa->out_freemps != NULL) remove(csa->out_freemps);
+ if (csa->out_cpxlp != NULL) remove(csa->out_cpxlp);
+ if (csa->out_glp != NULL) remove(csa->out_glp);
+#if 0
+ if (csa->out_pb != NULL) remove(csa->out_pb);
+ if (csa->out_npb != NULL) remove(csa->out_npb);
+#endif
+#if 1 /* 06/VIII-2011 */
+ if (csa->out_cnf != NULL) remove(csa->out_cnf);
+#endif
+ if (csa->log_file != NULL) remove(csa->log_file);
+ /*--------------------------------------------------------------*/
+ /* open log file, if required */
+ if (csa->log_file != NULL)
+ { if (glp_open_tee(csa->log_file))
+ { xprintf("Unable to create log file\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ /*--------------------------------------------------------------*/
+ /* print version information */
+ print_version(1);
+ /*--------------------------------------------------------------*/
+ /* print parameters specified in the command line */
+ if (argc > 1)
+ { int k, len = INT_MAX;
+ xprintf("Parameter(s) specified in the command line:");
+ for (k = 1; k < argc; k++)
+ { if (len > 72)
+ xprintf("\n"), len = 0;
+ xprintf(" %s", argv[k]);
+ len += 1 + strlen(argv[k]);
+ }
+ xprintf("\n");
+ }
+ /*--------------------------------------------------------------*/
+ /* read problem data from the input file */
+ if (csa->in_file == NULL)
+ { xprintf("No input problem file specified; try %s --help\n",
+ argv[0]);
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ if (csa->format == FMT_MPS_DECK)
+ { ret = glp_read_mps(csa->prob, GLP_MPS_DECK, NULL,
+ csa->in_file);
+ if (ret != 0)
+err1: { xprintf("MPS file processing error\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ else if (csa->format == FMT_MPS_FILE)
+ { ret = glp_read_mps(csa->prob, GLP_MPS_FILE, NULL,
+ csa->in_file);
+ if (ret != 0) goto err1;
+ }
+ else if (csa->format == FMT_LP)
+ { ret = glp_read_lp(csa->prob, NULL, csa->in_file);
+ if (ret != 0)
+ { xprintf("CPLEX LP file processing error\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ else if (csa->format == FMT_GLP)
+ { ret = glp_read_prob(csa->prob, 0, csa->in_file);
+ if (ret != 0)
+ { xprintf("GLPK LP/MIP file processing error\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ else if (csa->format == FMT_MATHPROG)
+ { int k;
+ /* allocate the translator workspace */
+ csa->tran = glp_mpl_alloc_wksp();
+ /* set seed value */
+ if (csa->seed == 0x80000000)
+#if 0 /* 10/VI-2013 */
+ { csa->seed = glp_time().lo;
+#else
+ { csa->seed = (int)fmod(glp_time(), 1000000000.0);
+#endif
+ xprintf("Seed value %d will be used\n", csa->seed);
+ }
+ glp_mpl_init_rand(csa->tran, csa->seed);
+ /* read model section and optional data section */
+ if (glp_mpl_read_model(csa->tran, csa->in_file, csa->ndf > 0))
+err2: { xprintf("MathProg model processing error\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ /* read optional data section(s), if necessary */
+ for (k = 1; k <= csa->ndf; k++)
+ { if (glp_mpl_read_data(csa->tran, csa->in_data[k]))
+ goto err2;
+ }
+ /* generate the model */
+ if (glp_mpl_generate(csa->tran, csa->out_dpy)) goto err2;
+ /* build the problem instance from the model */
+ glp_mpl_build_prob(csa->tran, csa->prob);
+ }
+ else if (csa->format == FMT_MIN_COST)
+ { csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
+ ret = glp_read_mincost(csa->graph, offsetof(v_data, rhs),
+ offsetof(a_data, low), offsetof(a_data, cap),
+ offsetof(a_data, cost), csa->in_file);
+ if (ret != 0)
+ { xprintf("DIMACS file processing error\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ glp_mincost_lp(csa->prob, csa->graph, GLP_ON,
+ offsetof(v_data, rhs), offsetof(a_data, low),
+ offsetof(a_data, cap), offsetof(a_data, cost));
+ glp_set_prob_name(csa->prob, csa->in_file);
+ }
+ else if (csa->format == FMT_MAX_FLOW)
+ { int s, t;
+ csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
+ ret = glp_read_maxflow(csa->graph, &s, &t,
+ offsetof(a_data, cap), csa->in_file);
+ if (ret != 0)
+ { xprintf("DIMACS file processing error\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ glp_maxflow_lp(csa->prob, csa->graph, GLP_ON, s, t,
+ offsetof(a_data, cap));
+ glp_set_prob_name(csa->prob, csa->in_file);
+ }
+#if 1 /* 06/VIII-2011 */
+ else if (csa->format == FMT_CNF)
+ { ret = glp_read_cnfsat(csa->prob, csa->in_file);
+ if (ret != 0)
+ { xprintf("DIMACS file processing error\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ glp_set_prob_name(csa->prob, csa->in_file);
+ }
+#endif
+ else
+ xassert(csa != csa);
+ /*--------------------------------------------------------------*/
+ /* change problem name, if required */
+ if (csa->new_name != NULL)
+ glp_set_prob_name(csa->prob, csa->new_name);
+ /* change optimization direction, if required */
+ if (csa->dir != 0)
+ glp_set_obj_dir(csa->prob, csa->dir);
+ /* sort elements of the constraint matrix */
+ glp_sort_matrix(csa->prob);
+#if 1 /* 18/I-2018 */
+ /*--------------------------------------------------------------*/
+ /* remove all symbolic names from problem object, if required */
+ if (csa->hide)
+ { int i, j;
+ glp_set_obj_name(csa->prob, NULL);
+ glp_delete_index(csa->prob);
+ for (i = glp_get_num_rows(csa->prob); i >= 1; i--)
+ glp_set_row_name(csa->prob, i, NULL);
+ for (j = glp_get_num_cols(csa->prob); j >= 1; j--)
+ glp_set_col_name(csa->prob, j, NULL);
+ }
+#endif
+ /*--------------------------------------------------------------*/
+ /* write problem data in fixed MPS format, if required */
+ if (csa->out_mps != NULL)
+ { ret = glp_write_mps(csa->prob, GLP_MPS_DECK, NULL,
+ csa->out_mps);
+ if (ret != 0)
+ { xprintf("Unable to write problem in fixed MPS format\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ /* write problem data in free MPS format, if required */
+ if (csa->out_freemps != NULL)
+ { ret = glp_write_mps(csa->prob, GLP_MPS_FILE, NULL,
+ csa->out_freemps);
+ if (ret != 0)
+ { xprintf("Unable to write problem in free MPS format\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ /* write problem data in CPLEX LP format, if required */
+ if (csa->out_cpxlp != NULL)
+ { ret = glp_write_lp(csa->prob, NULL, csa->out_cpxlp);
+ if (ret != 0)
+ { xprintf("Unable to write problem in CPLEX LP format\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ /* write problem data in GLPK format, if required */
+ if (csa->out_glp != NULL)
+ { ret = glp_write_prob(csa->prob, 0, csa->out_glp);
+ if (ret != 0)
+ { xprintf("Unable to write problem in GLPK format\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+#if 0
+ /* write problem data in OPB format, if required */
+ if (csa->out_pb != NULL)
+ { ret = lpx_write_pb(csa->prob, csa->out_pb, 0, 0);
+ if (ret != 0)
+ { xprintf("Unable to write problem in OPB format\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ /* write problem data in normalized OPB format, if required */
+ if (csa->out_npb != NULL)
+ { ret = lpx_write_pb(csa->prob, csa->out_npb, 1, 1);
+ if (ret != 0)
+ { xprintf(
+ "Unable to write problem in normalized OPB format\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+#endif
+#if 1 /* 06/VIII-2011 */
+ /* write problem data in DIMACS CNF-SAT format, if required */
+ if (csa->out_cnf != NULL)
+ { ret = glp_write_cnfsat(csa->prob, csa->out_cnf);
+ if (ret != 0)
+ { xprintf(
+ "Unable to write problem in DIMACS CNF-SAT format\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+#endif
+ /*--------------------------------------------------------------*/
+ /* if only problem data check is required, skip computations */
+ if (csa->check)
+ {
+#if 1 /* 29/III-2016 */
+ /* report problem characteristics */
+ int j, cnt = 0;
+ xprintf("--- Problem Characteristics ---\n");
+ xprintf("Number of rows = %8d\n",
+ glp_get_num_rows(csa->prob));
+ xprintf("Number of columns = %8d\n",
+ glp_get_num_cols(csa->prob));
+ xprintf("Number of non-zeros (matrix) = %8d\n",
+ glp_get_num_nz(csa->prob));
+ for (j = glp_get_num_cols(csa->prob); j >= 1; j--)
+ { if (glp_get_obj_coef(csa->prob, j) != 0.0)
+ cnt++;
+ }
+ xprintf("Number of non-zeros (objrow) = %8d\n",
+ cnt);
+#endif
+ ret = EXIT_SUCCESS;
+ goto done;
+ }
+ /*--------------------------------------------------------------*/
+ /* determine the solution type */
+ if (!csa->nomip &&
+ glp_get_num_int(csa->prob) + glp_get_num_bin(csa->prob) > 0)
+ { if (csa->solution == SOL_INTERIOR)
+ { xprintf("Interior-point method is not able to solve MIP pro"
+ "blem; use --simplex\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ csa->solution = SOL_INTEGER;
+ }
+ /*--------------------------------------------------------------*/
+ /* if solution is provided, read it and skip computations */
+ if (csa->in_res != NULL)
+ { if (csa->solution == SOL_BASIC)
+ ret = glp_read_sol(csa->prob, csa->in_res);
+ else if (csa->solution == SOL_INTERIOR)
+ ret = glp_read_ipt(csa->prob, csa->in_res);
+ else if (csa->solution == SOL_INTEGER)
+ ret = glp_read_mip(csa->prob, csa->in_res);
+ else
+ xassert(csa != csa);
+ if (ret != 0)
+ { xprintf("Unable to read problem solution\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ goto skip;
+ }
+#if 1 /* 11/VII-2013 */
+ /*--------------------------------------------------------------*/
+ /* if initial MIP solution is provided, read it */
+ if (csa->solution == SOL_INTEGER && csa->use_sol != NULL)
+ { ret = glp_read_mip(csa->prob, csa->use_sol);
+ if (ret != 0)
+ { xprintf("Unable to read initial MIP solution\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ csa->iocp.use_sol = GLP_ON;
+ }
+#endif
+ /*--------------------------------------------------------------*/
+ /* scale the problem data, if required */
+ if (csa->scale)
+ { if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
+ csa->solution == SOL_INTERIOR ||
+ csa->solution == SOL_INTEGER && !csa->iocp.presolve)
+ glp_scale_prob(csa->prob, GLP_SF_AUTO);
+ }
+ /*--------------------------------------------------------------*/
+ /* construct starting LP basis */
+ if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
+ csa->solution == SOL_INTEGER && !csa->iocp.presolve)
+ { if (csa->crash == USE_STD_BASIS)
+ glp_std_basis(csa->prob);
+ else if (csa->crash == USE_ADV_BASIS)
+ glp_adv_basis(csa->prob, 0);
+ else if (csa->crash == USE_CPX_BASIS)
+ glp_cpx_basis(csa->prob);
+ else if (csa->crash == USE_INI_BASIS)
+ { ret = glp_read_sol(csa->prob, csa->ini_file);
+ if (ret != 0)
+ { xprintf("Unable to read initial basis\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ else
+ xassert(csa != csa);
+ }
+ /*--------------------------------------------------------------*/
+ /* solve the problem */
+ start = glp_time();
+ if (csa->solution == SOL_BASIC)
+ { if (!csa->exact)
+ { glp_set_bfcp(csa->prob, &csa->bfcp);
+ glp_simplex(csa->prob, &csa->smcp);
+ if (csa->xcheck)
+ { if (csa->smcp.presolve &&
+ glp_get_status(csa->prob) != GLP_OPT)
+ xprintf("If you need to check final basis for non-opt"
+ "imal solution, use --nopresol\n");
+ else
+ glp_exact(csa->prob, &csa->smcp);
+ }
+ if (csa->out_sol != NULL || csa->out_res != NULL)
+ { if (csa->smcp.presolve &&
+ glp_get_status(csa->prob) != GLP_OPT)
+ xprintf("If you need actual output for non-optimal solut"
+ "ion, use --nopresol\n");
+ }
+ }
+ else
+ glp_exact(csa->prob, &csa->smcp);
+ }
+ else if (csa->solution == SOL_INTERIOR)
+ glp_interior(csa->prob, &csa->iptcp);
+#if 1 /* 15/VIII-2011 */
+ else if (csa->solution == SOL_INTEGER && csa->minisat)
+ { if (glp_check_cnfsat(csa->prob) == 0)
+ glp_minisat1(csa->prob);
+ else
+ glp_intfeas1(csa->prob, csa->use_bnd, csa->obj_bnd);
+ }
+#endif
+ else if (csa->solution == SOL_INTEGER)
+ { glp_set_bfcp(csa->prob, &csa->bfcp);
+ if (!csa->iocp.presolve)
+ glp_simplex(csa->prob, &csa->smcp);
+#if 0
+ csa->iocp.msg_lev = GLP_MSG_DBG;
+ csa->iocp.pp_tech = GLP_PP_NONE;
+#endif
+#ifdef GLP_CB_FUNC /* 05/IV-2016 */
+ { extern void GLP_CB_FUNC(glp_tree *, void *);
+ csa->iocp.cb_func = GLP_CB_FUNC;
+ csa->iocp.cb_info = NULL;
+ }
+#endif
+ glp_intopt(csa->prob, &csa->iocp);
+ }
+ else
+ xassert(csa != csa);
+ /*--------------------------------------------------------------*/
+ /* display statistics */
+ xprintf("Time used: %.1f secs\n", glp_difftime(glp_time(),
+ start));
+#if 0 /* 16/II-2012 */
+ { glp_long tpeak;
+ char buf[50];
+ glp_mem_usage(NULL, NULL, NULL, &tpeak);
+ xprintf("Memory used: %.1f Mb (%s bytes)\n",
+ xltod(tpeak) / 1048576.0, xltoa(tpeak, buf));
+ }
+#else
+ { size_t tpeak;
+ glp_mem_usage(NULL, NULL, NULL, &tpeak);
+ xprintf("Memory used: %.1f Mb (%.0f bytes)\n",
+ (double)tpeak / 1048576.0, (double)tpeak);
+ }
+#endif
+ /*--------------------------------------------------------------*/
+skip: /* postsolve the model, if necessary */
+ if (csa->tran != NULL)
+ { if (csa->solution == SOL_BASIC)
+ { if (!(glp_get_status(csa->prob) == GLP_OPT ||
+ glp_get_status(csa->prob) == GLP_FEAS))
+ ret = -1;
+ else
+ ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_SOL);
+ }
+ else if (csa->solution == SOL_INTERIOR)
+ { if (!(glp_ipt_status(csa->prob) == GLP_OPT ||
+ glp_ipt_status(csa->prob) == GLP_FEAS))
+ ret = -1;
+ else
+ ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_IPT);
+ }
+ else if (csa->solution == SOL_INTEGER)
+ { if (!(glp_mip_status(csa->prob) == GLP_OPT ||
+ glp_mip_status(csa->prob) == GLP_FEAS))
+ ret = -1;
+ else
+ ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_MIP);
+ }
+ else
+ xassert(csa != csa);
+ if (ret > 0)
+ { xprintf("Model postsolving error\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ /*--------------------------------------------------------------*/
+ /* write problem solution in printable format, if required */
+ if (csa->out_sol != NULL)
+ { if (csa->solution == SOL_BASIC)
+ ret = glp_print_sol(csa->prob, csa->out_sol);
+ else if (csa->solution == SOL_INTERIOR)
+ ret = glp_print_ipt(csa->prob, csa->out_sol);
+ else if (csa->solution == SOL_INTEGER)
+ ret = glp_print_mip(csa->prob, csa->out_sol);
+ else
+ xassert(csa != csa);
+ if (ret != 0)
+ { xprintf("Unable to write problem solution\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ /* write problem solution in printable format, if required */
+ if (csa->out_res != NULL)
+ { if (csa->solution == SOL_BASIC)
+ ret = glp_write_sol(csa->prob, csa->out_res);
+ else if (csa->solution == SOL_INTERIOR)
+ ret = glp_write_ipt(csa->prob, csa->out_res);
+ else if (csa->solution == SOL_INTEGER)
+ ret = glp_write_mip(csa->prob, csa->out_res);
+ else
+ xassert(csa != csa);
+ if (ret != 0)
+ { xprintf("Unable to write problem solution\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ /* write sensitivity analysis report, if required */
+ if (csa->out_ranges != NULL)
+ { if (csa->solution == SOL_BASIC)
+ { if (glp_get_status(csa->prob) == GLP_OPT)
+ { if (glp_bf_exists(csa->prob))
+ranges: { ret = glp_print_ranges(csa->prob, 0, NULL, 0,
+ csa->out_ranges);
+ if (ret != 0)
+ { xprintf("Unable to write sensitivity analysis repo"
+ "rt\n");
+ ret = EXIT_FAILURE;
+ goto done;
+ }
+ }
+ else
+ { ret = glp_factorize(csa->prob);
+ if (ret == 0) goto ranges;
+ xprintf("Cannot produce sensitivity analysis report d"
+ "ue to error in basis factorization (glp_factorize"
+ " returned %d); try --nopresol\n", ret);
+ }
+ }
+ else
+ xprintf("Cannot produce sensitivity analysis report for "
+ "non-optimal basic solution\n");
+ }
+ else
+ xprintf("Cannot produce sensitivity analysis report for int"
+ "erior-point or MIP solution\n");
+ }
+ /*--------------------------------------------------------------*/
+ /* all seems to be ok */
+ ret = EXIT_SUCCESS;
+ /*--------------------------------------------------------------*/
+done: /* delete the LP/MIP problem object */
+ if (csa->prob != NULL)
+ glp_delete_prob(csa->prob);
+ /* free the translator workspace, if necessary */
+ if (csa->tran != NULL)
+ glp_mpl_free_wksp(csa->tran);
+ /* delete the network problem object, if necessary */
+ if (csa->graph != NULL)
+ glp_delete_graph(csa->graph);
+#if 0 /* 23/XI-2015 */
+ xassert(gmp_pool_count() == 0);
+ gmp_free_mem();
+#endif
+ /* close log file, if necessary */
+ if (csa->log_file != NULL) glp_close_tee();
+ /* check that no memory blocks are still allocated */
+#if 0 /* 16/II-2012 */
+ { int count;
+ glp_long total;
+ glp_mem_usage(&count, NULL, &total, NULL);
+ if (count != 0)
+ xerror("Error: %d memory block(s) were lost\n", count);
+ xassert(count == 0);
+ xassert(total.lo == 0 && total.hi == 0);
+ }
+#else
+ { int count;
+ size_t total;
+ glp_mem_usage(&count, NULL, &total, NULL);
+ if (count != 0)
+ xerror("Error: %d memory block(s) were lost\n", count);
+ xassert(total == 0);
+ }
+#endif
+ /* free the GLPK environment */
+ glp_free_env();
+ /* return to the control program */
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/amd/COPYING b/test/monniaux/glpk-4.65/src/amd/COPYING
new file mode 100644
index 00000000..84bba36d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/COPYING
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/test/monniaux/glpk-4.65/src/amd/README b/test/monniaux/glpk-4.65/src/amd/README
new file mode 100644
index 00000000..de950eb4
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/README
@@ -0,0 +1,58 @@
+NOTE: Files in this subdirectory are NOT part of the GLPK package, but
+ are used with GLPK.
+
+ The original code was modified according to GLPK requirements by
+ Andrew Makhorin <mao@gnu.org>.
+************************************************************************
+AMD Version 2.2, Copyright (C) 2007 by Timothy A. Davis,
+Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved.
+
+Description:
+
+ AMD is a set of routines for pre-ordering sparse matrices prior to
+ Cholesky or LU factorization, using the approximate minimum degree
+ ordering algorithm. Written in ANSI/ISO C with a MATLAB interface,
+ and in Fortran 77.
+
+Authors:
+
+ Timothy A. Davis (davis at cise.ufl.edu), University of Florida.
+ Patrick R. Amestoy, ENSEEIHT, Toulouse, France.
+ Iain S. Duff, Rutherford Appleton Laboratory, UK.
+
+AMD License:
+
+ Your use or distribution of AMD or any modified version of AMD
+ implies that you agree to this License.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ USA.
+
+ Permission is hereby granted to use or copy this program under the
+ terms of the GNU LGPL, provided that the Copyright, this License,
+ and the Availability of the original version is retained on all
+ copies. User documentation of any code that uses this code or any
+ modified version of this code must cite the Copyright, this License,
+ the Availability note, and "Used by permission." Permission to
+ modify the code and to distribute modified code is granted, provided
+ the Copyright, this License, and the Availability note are retained,
+ and a notice that the code was modified is included.
+
+ AMD is available under alternate licences; contact T. Davis for
+ details.
+
+Availability:
+
+ http://www.cise.ufl.edu/research/sparse/amd
diff --git a/test/monniaux/glpk-4.65/src/amd/amd.h b/test/monniaux/glpk-4.65/src/amd/amd.h
new file mode 100644
index 00000000..be662d95
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd.h
@@ -0,0 +1,67 @@
+/* amd.h */
+
+/* Written by Andrew Makhorin <mao@gnu.org>. */
+
+#ifndef GLPAMD_H
+#define GLPAMD_H
+
+#define AMD_DATE "May 31, 2007"
+#define AMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub))
+#define AMD_MAIN_VERSION 2
+#define AMD_SUB_VERSION 2
+#define AMD_SUBSUB_VERSION 0
+#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION, AMD_SUB_VERSION)
+
+#define AMD_CONTROL 5
+#define AMD_INFO 20
+
+#define AMD_DENSE 0
+#define AMD_AGGRESSIVE 1
+
+#define AMD_DEFAULT_DENSE 10.0
+#define AMD_DEFAULT_AGGRESSIVE 1
+
+#define AMD_STATUS 0
+#define AMD_N 1
+#define AMD_NZ 2
+#define AMD_SYMMETRY 3
+#define AMD_NZDIAG 4
+#define AMD_NZ_A_PLUS_AT 5
+#define AMD_NDENSE 6
+#define AMD_MEMORY 7
+#define AMD_NCMPA 8
+#define AMD_LNZ 9
+#define AMD_NDIV 10
+#define AMD_NMULTSUBS_LDL 11
+#define AMD_NMULTSUBS_LU 12
+#define AMD_DMAX 13
+
+#define AMD_OK 0
+#define AMD_OUT_OF_MEMORY (-1)
+#define AMD_INVALID (-2)
+#define AMD_OK_BUT_JUMBLED 1
+
+#define amd_order _glp_amd_order
+int amd_order(int n, const int Ap[], const int Ai[], int P[],
+ double Control[], double Info[]);
+
+#define amd_2 _glp_amd_2
+void amd_2(int n, int Pe[], int Iw[], int Len[], int iwlen, int pfree,
+ int Nv[], int Next[], int Last[], int Head[], int Elen[],
+ int Degree[], int W[], double Control[], double Info[]);
+
+#define amd_valid _glp_amd_valid
+int amd_valid(int n_row, int n_col, const int Ap[], const int Ai[]);
+
+#define amd_defaults _glp_amd_defaults
+void amd_defaults(double Control[]);
+
+#define amd_control _glp_amd_control
+void amd_control(double Control[]);
+
+#define amd_info _glp_amd_info
+void amd_info(double Info[]);
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_1.c b/test/monniaux/glpk-4.65/src/amd/amd_1.c
new file mode 100644
index 00000000..4f9b07d7
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_1.c
@@ -0,0 +1,181 @@
+/* ========================================================================= */
+/* === AMD_1 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
+ *
+ * The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style
+ * compressed-column form, with sorted row indices in each column, and no
+ * duplicate entries. Diagonal entries may be present, but they are ignored.
+ * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The
+ * size of the matrix, n, must be greater than or equal to zero.
+ *
+ * This routine must be preceded by a call to AMD_aat, which computes the
+ * number of entries in each row/column in A+A', excluding the diagonal.
+ * Len [j], on input, is the number of entries in row/column j of A+A'. This
+ * routine constructs the matrix A+A' and then calls AMD_2. No error checking
+ * is performed (this was done in AMD_valid).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_1
+(
+ Int n, /* n > 0 */
+ const Int Ap [ ], /* input of size n+1, not modified */
+ const Int Ai [ ], /* input of size nz = Ap [n], not modified */
+ Int P [ ], /* size n output permutation */
+ Int Pinv [ ], /* size n output inverse permutation */
+ Int Len [ ], /* size n input, undefined on output */
+ Int slen, /* slen >= sum (Len [0..n-1]) + 7n,
+ * ideally slen = 1.2 * sum (Len) + 8n */
+ Int S [ ], /* size slen workspace */
+ double Control [ ], /* input array of size AMD_CONTROL */
+ double Info [ ] /* output array of size AMD_INFO */
+)
+{
+ Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
+ *Elen, *Degree, *s, *W, *Sp, *Tp ;
+
+ /* --------------------------------------------------------------------- */
+ /* construct the matrix for AMD_2 */
+ /* --------------------------------------------------------------------- */
+
+ ASSERT (n > 0) ;
+
+ iwlen = slen - 6*n ;
+ s = S ;
+ Pe = s ; s += n ;
+ Nv = s ; s += n ;
+ Head = s ; s += n ;
+ Elen = s ; s += n ;
+ Degree = s ; s += n ;
+ W = s ; s += n ;
+ Iw = s ; s += iwlen ;
+
+ ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
+
+ /* construct the pointers for A+A' */
+ Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */
+ Tp = W ;
+ pfree = 0 ;
+ for (j = 0 ; j < n ; j++)
+ {
+ Pe [j] = pfree ;
+ Sp [j] = pfree ;
+ pfree += Len [j] ;
+ }
+
+ /* Note that this restriction on iwlen is slightly more restrictive than
+ * what is strictly required in AMD_2. AMD_2 can operate with no elbow
+ * room at all, but it will be very slow. For better performance, at
+ * least size-n elbow room is enforced. */
+ ASSERT (iwlen >= pfree + n) ;
+
+#ifndef NDEBUG
+ for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
+#endif
+
+ for (k = 0 ; k < n ; k++)
+ {
+ AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ;
+ p1 = Ap [k] ;
+ p2 = Ap [k+1] ;
+
+ /* construct A+A' */
+ for (p = p1 ; p < p2 ; )
+ {
+ /* scan the upper triangular part of A */
+ j = Ai [p] ;
+ ASSERT (j >= 0 && j < n) ;
+ if (j < k)
+ {
+ /* entry A (j,k) in the strictly upper triangular part */
+ ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+ ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
+ Iw [Sp [j]++] = k ;
+ Iw [Sp [k]++] = j ;
+ p++ ;
+ }
+ else if (j == k)
+ {
+ /* skip the diagonal */
+ p++ ;
+ break ;
+ }
+ else /* j > k */
+ {
+ /* first entry below the diagonal */
+ break ;
+ }
+ /* scan lower triangular part of A, in column j until reaching
+ * row k. Start where last scan left off. */
+ ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+ pj2 = Ap [j+1] ;
+ for (pj = Tp [j] ; pj < pj2 ; )
+ {
+ i = Ai [pj] ;
+ ASSERT (i >= 0 && i < n) ;
+ if (i < k)
+ {
+ /* A (i,j) is only in the lower part, not in upper */
+ ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+ ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+ Iw [Sp [i]++] = j ;
+ Iw [Sp [j]++] = i ;
+ pj++ ;
+ }
+ else if (i == k)
+ {
+ /* entry A (k,j) in lower part and A (j,k) in upper */
+ pj++ ;
+ break ;
+ }
+ else /* i > k */
+ {
+ /* consider this entry later, when k advances to i */
+ break ;
+ }
+ }
+ Tp [j] = pj ;
+ }
+ Tp [k] = p ;
+ }
+
+ /* clean up, for remaining mismatched entries */
+ for (j = 0 ; j < n ; j++)
+ {
+ for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+ {
+ i = Ai [pj] ;
+ ASSERT (i >= 0 && i < n) ;
+ /* A (i,j) is only in the lower part, not in upper */
+ ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+ ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+ Iw [Sp [i]++] = j ;
+ Iw [Sp [j]++] = i ;
+ }
+ }
+
+#ifndef NDEBUG
+ for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
+ ASSERT (Sp [n-1] == pfree) ;
+#endif
+
+ /* Tp and Sp no longer needed ] */
+
+ /* --------------------------------------------------------------------- */
+ /* order the matrix */
+ /* --------------------------------------------------------------------- */
+
+ AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
+ Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
+}
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_2.c b/test/monniaux/glpk-4.65/src/amd/amd_2.c
new file mode 100644
index 00000000..36ae828a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_2.c
@@ -0,0 +1,1842 @@
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_2: performs the AMD ordering on a symmetric sparse matrix A, followed
+ * by a postordering (via depth-first search) of the assembly tree using the
+ * AMD_postorder routine.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === clear_flag ========================================================== */
+/* ========================================================================= */
+
+static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n)
+{
+ Int x ;
+ if (wflg < 2 || wflg >= wbig)
+ {
+ for (x = 0 ; x < n ; x++)
+ {
+ if (W [x] != 0) W [x] = 1 ;
+ }
+ wflg = 2 ;
+ }
+ /* at this point, W [0..n-1] < wflg holds */
+ return (wflg) ;
+}
+
+
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+GLOBAL void AMD_2
+(
+ Int n, /* A is n-by-n, where n > 0 */
+ Int Pe [ ], /* Pe [0..n-1]: index in Iw of row i on input */
+ Int Iw [ ], /* workspace of size iwlen. Iw [0..pfree-1]
+ * holds the matrix on input */
+ Int Len [ ], /* Len [0..n-1]: length for row/column i on input */
+ Int iwlen, /* length of Iw. iwlen >= pfree + n */
+ Int pfree, /* Iw [pfree ... iwlen-1] is empty on input */
+
+ /* 7 size-n workspaces, not defined on input: */
+ Int Nv [ ], /* the size of each supernode on output */
+ Int Next [ ], /* the output inverse permutation */
+ Int Last [ ], /* the output permutation */
+ Int Head [ ],
+ Int Elen [ ], /* the size columns of L for each supernode */
+ Int Degree [ ],
+ Int W [ ],
+
+ /* control parameters and output statistics */
+ double Control [ ], /* array of size AMD_CONTROL */
+ double Info [ ] /* array of size AMD_INFO */
+)
+{
+
+/*
+ * Given a representation of the nonzero pattern of a symmetric matrix, A,
+ * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style)
+ * degree ordering to compute a pivot order such that the introduction of
+ * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low. At each
+ * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style
+ * upper-bound on the external degree. This routine can optionally perform
+ * aggresive absorption (as done by MC47B in the Harwell Subroutine
+ * Library).
+ *
+ * The approximate degree algorithm implemented here is the symmetric analog of
+ * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern
+ * MultiFrontal PACKage, both by Davis and Duff). The routine is based on the
+ * MA27 minimum degree ordering algorithm by Iain Duff and John Reid.
+ *
+ * This routine is a translation of the original AMDBAR and MC47B routines,
+ * in Fortran, with the following modifications:
+ *
+ * (1) dense rows/columns are removed prior to ordering the matrix, and placed
+ * last in the output order. The presence of a dense row/column can
+ * increase the ordering time by up to O(n^2), unless they are removed
+ * prior to ordering.
+ *
+ * (2) the minimum degree ordering is followed by a postordering (depth-first
+ * search) of the assembly tree. Note that mass elimination (discussed
+ * below) combined with the approximate degree update can lead to the mass
+ * elimination of nodes with lower exact degree than the current pivot
+ * element. No additional fill-in is caused in the representation of the
+ * Schur complement. The mass-eliminated nodes merge with the current
+ * pivot element. They are ordered prior to the current pivot element.
+ * Because they can have lower exact degree than the current element, the
+ * merger of two or more of these nodes in the current pivot element can
+ * lead to a single element that is not a "fundamental supernode". The
+ * diagonal block can have zeros in it. Thus, the assembly tree used here
+ * is not guaranteed to be the precise supernodal elemination tree (with
+ * "funadmental" supernodes), and the postordering performed by this
+ * routine is not guaranteed to be a precise postordering of the
+ * elimination tree.
+ *
+ * (3) input parameters are added, to control aggressive absorption and the
+ * detection of "dense" rows/columns of A.
+ *
+ * (4) additional statistical information is returned, such as the number of
+ * nonzeros in L, and the flop counts for subsequent LDL' and LU
+ * factorizations. These are slight upper bounds, because of the mass
+ * elimination issue discussed above.
+ *
+ * (5) additional routines are added to interface this routine to MATLAB
+ * to provide a simple C-callable user-interface, to check inputs for
+ * errors, compute the symmetry of the pattern of A and the number of
+ * nonzeros in each row/column of A+A', to compute the pattern of A+A',
+ * to perform the assembly tree postordering, and to provide debugging
+ * ouput. Many of these functions are also provided by the Fortran
+ * Harwell Subroutine Library routine MC47A.
+ *
+ * (6) both int and UF_long versions are provided. In the descriptions below
+ * and integer is and int or UF_long depending on which version is
+ * being used.
+
+ **********************************************************************
+ ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ******
+ **********************************************************************
+ ** If you want error checking, a more versatile input format, and a **
+ ** simpler user interface, use amd_order or amd_l_order instead. **
+ ** This routine is not meant to be user-callable. **
+ **********************************************************************
+
+ * ----------------------------------------------------------------------------
+ * References:
+ * ----------------------------------------------------------------------------
+ *
+ * [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal
+ * method for sparse LU factorization", SIAM J. Matrix Analysis and
+ * Applications, vol. 18, no. 1, pp. 140-158. Discusses UMFPACK / MA38,
+ * which first introduced the approximate minimum degree used by this
+ * routine.
+ *
+ * [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate
+ * minimum degree ordering algorithm," SIAM J. Matrix Analysis and
+ * Applications, vol. 17, no. 4, pp. 886-905, 1996. Discusses AMDBAR and
+ * MC47B, which are the Fortran versions of this routine.
+ *
+ * [3] Alan George and Joseph Liu, "The evolution of the minimum degree
+ * ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989.
+ * We list below the features mentioned in that paper that this code
+ * includes:
+ *
+ * mass elimination:
+ * Yes. MA27 relied on supervariable detection for mass elimination.
+ *
+ * indistinguishable nodes:
+ * Yes (we call these "supervariables"). This was also in the MA27
+ * code - although we modified the method of detecting them (the
+ * previous hash was the true degree, which we no longer keep track
+ * of). A supervariable is a set of rows with identical nonzero
+ * pattern. All variables in a supervariable are eliminated together.
+ * Each supervariable has as its numerical name that of one of its
+ * variables (its principal variable).
+ *
+ * quotient graph representation:
+ * Yes. We use the term "element" for the cliques formed during
+ * elimination. This was also in the MA27 code. The algorithm can
+ * operate in place, but it will work more efficiently if given some
+ * "elbow room."
+ *
+ * element absorption:
+ * Yes. This was also in the MA27 code.
+ *
+ * external degree:
+ * Yes. The MA27 code was based on the true degree.
+ *
+ * incomplete degree update and multiple elimination:
+ * No. This was not in MA27, either. Our method of degree update
+ * within MC47B is element-based, not variable-based. It is thus
+ * not well-suited for use with incomplete degree update or multiple
+ * elimination.
+ *
+ * Authors, and Copyright (C) 2004 by:
+ * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid.
+ *
+ * Acknowledgements: This work (and the UMFPACK package) was supported by the
+ * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270).
+ * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog
+ * which forms the basis of AMD, was developed while Tim Davis was supported by
+ * CERFACS (Toulouse, France) in a post-doctoral position. This C version, and
+ * the etree postorder, were written while Tim Davis was on sabbatical at
+ * Stanford University and Lawrence Berkeley National Laboratory.
+
+ * ----------------------------------------------------------------------------
+ * INPUT ARGUMENTS (unaltered):
+ * ----------------------------------------------------------------------------
+
+ * n: The matrix order. Restriction: n >= 1.
+ *
+ * iwlen: The size of the Iw array. On input, the matrix is stored in
+ * Iw [0..pfree-1]. However, Iw [0..iwlen-1] should be slightly larger
+ * than what is required to hold the matrix, at least iwlen >= pfree + n.
+ * Otherwise, excessive compressions will take place. The recommended
+ * value of iwlen is 1.2 * pfree + n, which is the value used in the
+ * user-callable interface to this routine (amd_order.c). The algorithm
+ * will not run at all if iwlen < pfree. Restriction: iwlen >= pfree + n.
+ * Note that this is slightly more restrictive than the actual minimum
+ * (iwlen >= pfree), but AMD_2 will be very slow with no elbow room.
+ * Thus, this routine enforces a bare minimum elbow room of size n.
+ *
+ * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty,
+ * and the matrix is stored in Iw [0..pfree-1]. During execution,
+ * additional data is placed in Iw, and pfree is modified so that
+ * Iw [pfree..iwlen-1] is always the unused part of Iw.
+ *
+ * Control: A double array of size AMD_CONTROL containing input parameters
+ * that affect how the ordering is computed. If NULL, then default
+ * settings are used.
+ *
+ * Control [AMD_DENSE] is used to determine whether or not a given input
+ * row is "dense". A row is "dense" if the number of entries in the row
+ * exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or
+ * fewer entries are never considered "dense". To turn off the detection
+ * of dense rows, set Control [AMD_DENSE] to a negative number, or to a
+ * number larger than sqrt (n). The default value of Control [AMD_DENSE]
+ * is AMD_DEFAULT_DENSE, which is defined in amd.h as 10.
+ *
+ * Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive
+ * absorption is to be performed. If nonzero, then aggressive absorption
+ * is performed (this is the default).
+
+ * ----------------------------------------------------------------------------
+ * INPUT/OUPUT ARGUMENTS:
+ * ----------------------------------------------------------------------------
+ *
+ * Pe: An integer array of size n. On input, Pe [i] is the index in Iw of
+ * the start of row i. Pe [i] is ignored if row i has no off-diagonal
+ * entries. Thus Pe [i] must be in the range 0 to pfree-1 for non-empty
+ * rows.
+ *
+ * During execution, it is used for both supervariables and elements:
+ *
+ * Principal supervariable i: index into Iw of the description of
+ * supervariable i. A supervariable represents one or more rows of
+ * the matrix with identical nonzero pattern. In this case,
+ * Pe [i] >= 0.
+ *
+ * Non-principal supervariable i: if i has been absorbed into another
+ * supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined
+ * as (-(j)-2). Row j has the same pattern as row i. Note that j
+ * might later be absorbed into another supervariable j2, in which
+ * case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is
+ * < EMPTY, where EMPTY is defined as (-1) in amd_internal.h.
+ *
+ * Unabsorbed element e: the index into Iw of the description of element
+ * e, if e has not yet been absorbed by a subsequent element. Element
+ * e is created when the supervariable of the same name is selected as
+ * the pivot. In this case, Pe [i] >= 0.
+ *
+ * Absorbed element e: if element e is absorbed into element e2, then
+ * Pe [e] = FLIP (e2). This occurs when the pattern of e (which we
+ * refer to as Le) is found to be a subset of the pattern of e2 (that
+ * is, Le2). In this case, Pe [i] < EMPTY. If element e is "null"
+ * (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY,
+ * and e is the root of an assembly subtree (or the whole tree if
+ * there is just one such root).
+ *
+ * Dense variable i: if i is "dense", then Pe [i] = EMPTY.
+ *
+ * On output, Pe holds the assembly tree/forest, which implicitly
+ * represents a pivot order with identical fill-in as the actual order
+ * (via a depth-first search of the tree), as follows. If Nv [i] > 0,
+ * then i represents a node in the assembly tree, and the parent of i is
+ * Pe [i], or EMPTY if i is a root. If Nv [i] = 0, then (i, Pe [i])
+ * represents an edge in a subtree, the root of which is a node in the
+ * assembly tree. Note that i refers to a row/column in the original
+ * matrix, not the permuted matrix.
+ *
+ * Info: A double array of size AMD_INFO. If present, (that is, not NULL),
+ * then statistics about the ordering are returned in the Info array.
+ * See amd.h for a description.
+
+ * ----------------------------------------------------------------------------
+ * INPUT/MODIFIED (undefined on output):
+ * ----------------------------------------------------------------------------
+ *
+ * Len: An integer array of size n. On input, Len [i] holds the number of
+ * entries in row i of the matrix, excluding the diagonal. The contents
+ * of Len are undefined on output.
+ *
+ * Iw: An integer array of size iwlen. On input, Iw [0..pfree-1] holds the
+ * description of each row i in the matrix. The matrix must be symmetric,
+ * and both upper and lower triangular parts must be present. The
+ * diagonal must not be present. Row i is held as follows:
+ *
+ * Len [i]: the length of the row i data structure in the Iw array.
+ * Iw [Pe [i] ... Pe [i] + Len [i] - 1]:
+ * the list of column indices for nonzeros in row i (simple
+ * supervariables), excluding the diagonal. All supervariables
+ * start with one row/column each (supervariable i is just row i).
+ * If Len [i] is zero on input, then Pe [i] is ignored on input.
+ *
+ * Note that the rows need not be in any particular order, and there
+ * may be empty space between the rows.
+ *
+ * During execution, the supervariable i experiences fill-in. This is
+ * represented by placing in i a list of the elements that cause fill-in
+ * in supervariable i:
+ *
+ * Len [i]: the length of supervariable i in the Iw array.
+ * Iw [Pe [i] ... Pe [i] + Elen [i] - 1]:
+ * the list of elements that contain i. This list is kept short
+ * by removing absorbed elements.
+ * Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]:
+ * the list of supervariables in i. This list is kept short by
+ * removing nonprincipal variables, and any entry j that is also
+ * contained in at least one of the elements (j in Le) in the list
+ * for i (e in row i).
+ *
+ * When supervariable i is selected as pivot, we create an element e of
+ * the same name (e=i):
+ *
+ * Len [e]: the length of element e in the Iw array.
+ * Iw [Pe [e] ... Pe [e] + Len [e] - 1]:
+ * the list of supervariables in element e.
+ *
+ * An element represents the fill-in that occurs when supervariable i is
+ * selected as pivot (which represents the selection of row i and all
+ * non-principal variables whose principal variable is i). We use the
+ * term Le to denote the set of all supervariables in element e. Absorbed
+ * supervariables and elements are pruned from these lists when
+ * computationally convenient.
+ *
+ * CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+ * The contents of Iw are undefined on output.
+
+ * ----------------------------------------------------------------------------
+ * OUTPUT (need not be set on input):
+ * ----------------------------------------------------------------------------
+ *
+ * Nv: An integer array of size n. During execution, ABS (Nv [i]) is equal to
+ * the number of rows that are represented by the principal supervariable
+ * i. If i is a nonprincipal or dense variable, then Nv [i] = 0.
+ * Initially, Nv [i] = 1 for all i. Nv [i] < 0 signifies that i is a
+ * principal variable in the pattern Lme of the current pivot element me.
+ * After element me is constructed, Nv [i] is set back to a positive
+ * value.
+ *
+ * On output, Nv [i] holds the number of pivots represented by super
+ * row/column i of the original matrix, or Nv [i] = 0 for non-principal
+ * rows/columns. Note that i refers to a row/column in the original
+ * matrix, not the permuted matrix.
+ *
+ * Elen: An integer array of size n. See the description of Iw above. At the
+ * start of execution, Elen [i] is set to zero for all rows i. During
+ * execution, Elen [i] is the number of elements in the list for
+ * supervariable i. When e becomes an element, Elen [e] = FLIP (esize) is
+ * set, where esize is the size of the element (the number of pivots, plus
+ * the number of nonpivotal entries). Thus Elen [e] < EMPTY.
+ * Elen (i) = EMPTY set when variable i becomes nonprincipal.
+ *
+ * For variables, Elen (i) >= EMPTY holds until just before the
+ * postordering and permutation vectors are computed. For elements,
+ * Elen [e] < EMPTY holds.
+ *
+ * On output, Elen [i] is the degree of the row/column in the Cholesky
+ * factorization of the permuted matrix, corresponding to the original row
+ * i, if i is a super row/column. It is equal to EMPTY if i is
+ * non-principal. Note that i refers to a row/column in the original
+ * matrix, not the permuted matrix.
+ *
+ * Note that the contents of Elen on output differ from the Fortran
+ * version (Elen holds the inverse permutation in the Fortran version,
+ * which is instead returned in the Next array in this C version,
+ * described below).
+ *
+ * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY
+ * if i is the head of the list. In a hash bucket, Last [i] is the hash
+ * key for i.
+ *
+ * Last [Head [hash]] is also used as the head of a hash bucket if
+ * Head [hash] contains a degree list (see the description of Head,
+ * below).
+ *
+ * On output, Last [0..n-1] holds the permutation. That is, if
+ * i = Last [k], then row i is the kth pivot row (where k ranges from 0 to
+ * n-1). Row Last [k] of A is the kth row in the permuted matrix, PAP'.
+ *
+ * Next: Next [i] is the supervariable following i in a link list, or EMPTY if
+ * i is the last in the list. Used for two kinds of lists: degree lists
+ * and hash buckets (a supervariable can be in only one kind of list at a
+ * time).
+ *
+ * On output Next [0..n-1] holds the inverse permutation. That is, if
+ * k = Next [i], then row i is the kth pivot row. Row i of A appears as
+ * the (Next[i])-th row in the permuted matrix, PAP'.
+ *
+ * Note that the contents of Next on output differ from the Fortran
+ * version (Next is undefined on output in the Fortran version).
+
+ * ----------------------------------------------------------------------------
+ * LOCAL WORKSPACE (not input or output - used only during execution):
+ * ----------------------------------------------------------------------------
+ *
+ * Degree: An integer array of size n. If i is a supervariable, then
+ * Degree [i] holds the current approximation of the external degree of
+ * row i (an upper bound). The external degree is the number of nonzeros
+ * in row i, minus ABS (Nv [i]), the diagonal part. The bound is equal to
+ * the exact external degree if Elen [i] is less than or equal to two.
+ *
+ * We also use the term "external degree" for elements e to refer to
+ * |Le \ Lme|. If e is an element, then Degree [e] is |Le|, which is the
+ * degree of the off-diagonal part of the element e (not including the
+ * diagonal part).
+ *
+ * Head: An integer array of size n. Head is used for degree lists.
+ * Head [deg] is the first supervariable in a degree list. All
+ * supervariables i in a degree list Head [deg] have the same approximate
+ * degree, namely, deg = Degree [i]. If the list Head [deg] is empty then
+ * Head [deg] = EMPTY.
+ *
+ * During supervariable detection Head [hash] also serves as a pointer to
+ * a hash bucket. If Head [hash] >= 0, there is a degree list of degree
+ * hash. The hash bucket head pointer is Last [Head [hash]]. If
+ * Head [hash] = EMPTY, then the degree list and hash bucket are both
+ * empty. If Head [hash] < EMPTY, then the degree list is empty, and
+ * FLIP (Head [hash]) is the head of the hash bucket. After supervariable
+ * detection is complete, all hash buckets are empty, and the
+ * (Last [Head [hash]] = EMPTY) condition is restored for the non-empty
+ * degree lists.
+ *
+ * W: An integer array of size n. The flag array W determines the status of
+ * elements and variables, and the external degree of elements.
+ *
+ * for elements:
+ * if W [e] = 0, then the element e is absorbed.
+ * if W [e] >= wflg, then W [e] - wflg is the size of the set
+ * |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for
+ * each principal variable i that is both in the pattern of
+ * element e and NOT in the pattern of the current pivot element,
+ * me).
+ * if wflg > W [e] > 0, then e is not absorbed and has not yet been
+ * seen in the scan of the element lists in the computation of
+ * |Le\Lme| in Scan 1 below.
+ *
+ * for variables:
+ * during supervariable detection, if W [j] != wflg then j is
+ * not in the pattern of variable i.
+ *
+ * The W array is initialized by setting W [i] = 1 for all i, and by
+ * setting wflg = 2. It is reinitialized if wflg becomes too large (to
+ * ensure that wflg+n does not cause integer overflow).
+
+ * ----------------------------------------------------------------------------
+ * LOCAL INTEGERS:
+ * ----------------------------------------------------------------------------
+ */
+
+ Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j,
+ jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft,
+ nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa,
+ dense, aggressive ;
+
+ unsigned Int hash ; /* unsigned, so that hash % n is well defined.*/
+
+/*
+ * deg: the degree of a variable or element
+ * degme: size, |Lme|, of the current element, me (= Degree [me])
+ * dext: external degree, |Le \ Lme|, of some element e
+ * lemax: largest |Le| seen so far (called dmax in Fortran version)
+ * e: an element
+ * elenme: the length, Elen [me], of element list of pivotal variable
+ * eln: the length, Elen [...], of an element list
+ * hash: the computed value of the hash function
+ * i: a supervariable
+ * ilast: the entry in a link list preceding i
+ * inext: the entry in a link list following i
+ * j: a supervariable
+ * jlast: the entry in a link list preceding j
+ * jnext: the entry in a link list, or path, following j
+ * k: the pivot order of an element or variable
+ * knt1: loop counter used during element construction
+ * knt2: loop counter used during element construction
+ * knt3: loop counter used during compression
+ * lenj: Len [j]
+ * ln: length of a supervariable list
+ * me: current supervariable being eliminated, and the current
+ * element created by eliminating that supervariable
+ * mindeg: current minimum degree
+ * nel: number of pivots selected so far
+ * nleft: n - nel, the number of nonpivotal rows/columns remaining
+ * nvi: the number of variables in a supervariable i (= Nv [i])
+ * nvj: the number of variables in a supervariable j (= Nv [j])
+ * nvpiv: number of pivots in current element
+ * slenme: number of variables in variable list of pivotal variable
+ * wbig: = INT_MAX - n for the int version, UF_long_max - n for the
+ * UF_long version. wflg is not allowed to be >= wbig.
+ * we: W [e]
+ * wflg: used for flagging the W array. See description of Iw.
+ * wnvi: wflg - Nv [i]
+ * x: either a supervariable or an element
+ *
+ * ok: true if supervariable j can be absorbed into i
+ * ndense: number of "dense" rows/columns
+ * dense: rows/columns with initial degree > dense are considered "dense"
+ * aggressive: true if aggressive absorption is being performed
+ * ncmpa: number of garbage collections
+
+ * ----------------------------------------------------------------------------
+ * LOCAL DOUBLES, used for statistical output only (except for alpha):
+ * ----------------------------------------------------------------------------
+ */
+
+ double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ;
+
+/*
+ * f: nvpiv
+ * r: degme + nvpiv
+ * ndiv: number of divisions for LU or LDL' factorizations
+ * s: number of multiply-subtract pairs for LU factorization, for the
+ * current element me
+ * nms_lu number of multiply-subtract pairs for LU factorization
+ * nms_ldl number of multiply-subtract pairs for LDL' factorization
+ * dmax: the largest number of entries in any column of L, including the
+ * diagonal
+ * alpha: "dense" degree ratio
+ * lnz: the number of nonzeros in L (excluding the diagonal)
+ * lnzme: the number of nonzeros in L (excl. the diagonal) for the
+ * current element me
+
+ * ----------------------------------------------------------------------------
+ * LOCAL "POINTERS" (indices into the Iw array)
+ * ----------------------------------------------------------------------------
+*/
+
+ Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ;
+
+/*
+ * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for
+ * Pointer) is an index into Iw, and all indices into Iw use variables starting
+ * with "p." The only exception to this rule is the iwlen input argument.
+ *
+ * p: pointer into lots of things
+ * p1: Pe [i] for some variable i (start of element list)
+ * p2: Pe [i] + Elen [i] - 1 for some variable i
+ * p3: index of first supervariable in clean list
+ * p4:
+ * pdst: destination pointer, for compression
+ * pend: end of memory to compress
+ * pj: pointer into an element or variable
+ * pme: pointer into the current element (pme1...pme2)
+ * pme1: the current element, me, is stored in Iw [pme1...pme2]
+ * pme2: the end of the current element
+ * pn: pointer into a "clean" variable, also used to compress
+ * psrc: source pointer, for compression
+*/
+
+/* ========================================================================= */
+/* INITIALIZATIONS */
+/* ========================================================================= */
+
+ /* Note that this restriction on iwlen is slightly more restrictive than
+ * what is actually required in AMD_2. AMD_2 can operate with no elbow
+ * room at all, but it will be slow. For better performance, at least
+ * size-n elbow room is enforced. */
+ ASSERT (iwlen >= pfree + n) ;
+ ASSERT (n > 0) ;
+
+ /* initialize output statistics */
+ lnz = 0 ;
+ ndiv = 0 ;
+ nms_lu = 0 ;
+ nms_ldl = 0 ;
+ dmax = 1 ;
+ me = EMPTY ;
+
+ mindeg = 0 ;
+ ncmpa = 0 ;
+ nel = 0 ;
+ lemax = 0 ;
+
+ /* get control parameters */
+ if (Control != (double *) NULL)
+ {
+ alpha = Control [AMD_DENSE] ;
+ aggressive = (Control [AMD_AGGRESSIVE] != 0) ;
+ }
+ else
+ {
+ alpha = AMD_DEFAULT_DENSE ;
+ aggressive = AMD_DEFAULT_AGGRESSIVE ;
+ }
+ /* Note: if alpha is NaN, this is undefined: */
+ if (alpha < 0)
+ {
+ /* only remove completely dense rows/columns */
+ dense = n-2 ;
+ }
+ else
+ {
+ dense = alpha * sqrt ((double) n) ;
+ }
+ dense = MAX (16, dense) ;
+ dense = MIN (n, dense) ;
+ AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n",
+ alpha, aggressive)) ;
+
+ for (i = 0 ; i < n ; i++)
+ {
+ Last [i] = EMPTY ;
+ Head [i] = EMPTY ;
+ Next [i] = EMPTY ;
+ /* if separate Hhead array is used for hash buckets: *
+ Hhead [i] = EMPTY ;
+ */
+ Nv [i] = 1 ;
+ W [i] = 1 ;
+ Elen [i] = 0 ;
+ Degree [i] = Len [i] ;
+ }
+
+#ifndef NDEBUG
+ AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ;
+ AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last,
+ Head, Elen, Degree, W, -1) ;
+#endif
+
+ /* initialize wflg */
+ wbig = Int_MAX - n ;
+ wflg = clear_flag (0, wbig, W, n) ;
+
+ /* --------------------------------------------------------------------- */
+ /* initialize degree lists and eliminate dense and empty rows */
+ /* --------------------------------------------------------------------- */
+
+ ndense = 0 ;
+
+ for (i = 0 ; i < n ; i++)
+ {
+ deg = Degree [i] ;
+ ASSERT (deg >= 0 && deg < n) ;
+ if (deg == 0)
+ {
+
+ /* -------------------------------------------------------------
+ * we have a variable that can be eliminated at once because
+ * there is no off-diagonal non-zero in its row. Note that
+ * Nv [i] = 1 for an empty variable i. It is treated just
+ * the same as an eliminated element i.
+ * ------------------------------------------------------------- */
+
+ Elen [i] = FLIP (1) ;
+ nel++ ;
+ Pe [i] = EMPTY ;
+ W [i] = 0 ;
+
+ }
+ else if (deg > dense)
+ {
+
+ /* -------------------------------------------------------------
+ * Dense variables are not treated as elements, but as unordered,
+ * non-principal variables that have no parent. They do not take
+ * part in the postorder, since Nv [i] = 0. Note that the Fortran
+ * version does not have this option.
+ * ------------------------------------------------------------- */
+
+ AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ;
+ ndense++ ;
+ Nv [i] = 0 ; /* do not postorder this node */
+ Elen [i] = EMPTY ;
+ nel++ ;
+ Pe [i] = EMPTY ;
+
+ }
+ else
+ {
+
+ /* -------------------------------------------------------------
+ * place i in the degree list corresponding to its degree
+ * ------------------------------------------------------------- */
+
+ inext = Head [deg] ;
+ ASSERT (inext >= EMPTY && inext < n) ;
+ if (inext != EMPTY) Last [inext] = i ;
+ Next [i] = inext ;
+ Head [deg] = i ;
+
+ }
+ }
+
+/* ========================================================================= */
+/* WHILE (selecting pivots) DO */
+/* ========================================================================= */
+
+ while (nel < n)
+ {
+
+#ifndef NDEBUG
+ AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
+ if (AMD_debug >= 2)
+ {
+ AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next,
+ Last, Head, Elen, Degree, W, nel) ;
+ }
+#endif
+
+/* ========================================================================= */
+/* GET PIVOT OF MINIMUM DEGREE */
+/* ========================================================================= */
+
+ /* ----------------------------------------------------------------- */
+ /* find next supervariable for elimination */
+ /* ----------------------------------------------------------------- */
+
+ ASSERT (mindeg >= 0 && mindeg < n) ;
+ for (deg = mindeg ; deg < n ; deg++)
+ {
+ me = Head [deg] ;
+ if (me != EMPTY) break ;
+ }
+ mindeg = deg ;
+ ASSERT (me >= 0 && me < n) ;
+ AMD_DEBUG1 (("=================me: "ID"\n", me)) ;
+
+ /* ----------------------------------------------------------------- */
+ /* remove chosen variable from link list */
+ /* ----------------------------------------------------------------- */
+
+ inext = Next [me] ;
+ ASSERT (inext >= EMPTY && inext < n) ;
+ if (inext != EMPTY) Last [inext] = EMPTY ;
+ Head [deg] = inext ;
+
+ /* ----------------------------------------------------------------- */
+ /* me represents the elimination of pivots nel to nel+Nv[me]-1. */
+ /* place me itself as the first in this set. */
+ /* ----------------------------------------------------------------- */
+
+ elenme = Elen [me] ;
+ nvpiv = Nv [me] ;
+ ASSERT (nvpiv > 0) ;
+ nel += nvpiv ;
+
+/* ========================================================================= */
+/* CONSTRUCT NEW ELEMENT */
+/* ========================================================================= */
+
+ /* -----------------------------------------------------------------
+ * At this point, me is the pivotal supervariable. It will be
+ * converted into the current element. Scan list of the pivotal
+ * supervariable, me, setting tree pointers and constructing new list
+ * of supervariables for the new element, me. p is a pointer to the
+ * current position in the old list.
+ * ----------------------------------------------------------------- */
+
+ /* flag the variable "me" as being in Lme by negating Nv [me] */
+ Nv [me] = -nvpiv ;
+ degme = 0 ;
+ ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+ if (elenme == 0)
+ {
+
+ /* ------------------------------------------------------------- */
+ /* construct the new element in place */
+ /* ------------------------------------------------------------- */
+
+ pme1 = Pe [me] ;
+ pme2 = pme1 - 1 ;
+
+ for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++)
+ {
+ i = Iw [p] ;
+ ASSERT (i >= 0 && i < n && Nv [i] >= 0) ;
+ nvi = Nv [i] ;
+ if (nvi > 0)
+ {
+
+ /* ----------------------------------------------------- */
+ /* i is a principal variable not yet placed in Lme. */
+ /* store i in new list */
+ /* ----------------------------------------------------- */
+
+ /* flag i as being in Lme by negating Nv [i] */
+ degme += nvi ;
+ Nv [i] = -nvi ;
+ Iw [++pme2] = i ;
+
+ /* ----------------------------------------------------- */
+ /* remove variable i from degree list. */
+ /* ----------------------------------------------------- */
+
+ ilast = Last [i] ;
+ inext = Next [i] ;
+ ASSERT (ilast >= EMPTY && ilast < n) ;
+ ASSERT (inext >= EMPTY && inext < n) ;
+ if (inext != EMPTY) Last [inext] = ilast ;
+ if (ilast != EMPTY)
+ {
+ Next [ilast] = inext ;
+ }
+ else
+ {
+ /* i is at the head of the degree list */
+ ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+ Head [Degree [i]] = inext ;
+ }
+ }
+ }
+ }
+ else
+ {
+
+ /* ------------------------------------------------------------- */
+ /* construct the new element in empty space, Iw [pfree ...] */
+ /* ------------------------------------------------------------- */
+
+ p = Pe [me] ;
+ pme1 = pfree ;
+ slenme = Len [me] - elenme ;
+
+ for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++)
+ {
+
+ if (knt1 > elenme)
+ {
+ /* search the supervariables in me. */
+ e = me ;
+ pj = p ;
+ ln = slenme ;
+ AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ;
+ }
+ else
+ {
+ /* search the elements in me. */
+ e = Iw [p++] ;
+ ASSERT (e >= 0 && e < n) ;
+ pj = Pe [e] ;
+ ln = Len [e] ;
+ AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ;
+ ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ;
+ }
+ ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ;
+
+ /* ---------------------------------------------------------
+ * search for different supervariables and add them to the
+ * new list, compressing when necessary. this loop is
+ * executed once for each element in the list and once for
+ * all the supervariables in the list.
+ * --------------------------------------------------------- */
+
+ for (knt2 = 1 ; knt2 <= ln ; knt2++)
+ {
+ i = Iw [pj++] ;
+ ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY));
+ nvi = Nv [i] ;
+ AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n",
+ i, Elen [i], Nv [i], wflg)) ;
+
+ if (nvi > 0)
+ {
+
+ /* ------------------------------------------------- */
+ /* compress Iw, if necessary */
+ /* ------------------------------------------------- */
+
+ if (pfree >= iwlen)
+ {
+
+ AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ;
+
+ /* prepare for compressing Iw by adjusting pointers
+ * and lengths so that the lists being searched in
+ * the inner and outer loops contain only the
+ * remaining entries. */
+
+ Pe [me] = p ;
+ Len [me] -= knt1 ;
+ /* check if nothing left of supervariable me */
+ if (Len [me] == 0) Pe [me] = EMPTY ;
+ Pe [e] = pj ;
+ Len [e] = ln - knt2 ;
+ /* nothing left of element e */
+ if (Len [e] == 0) Pe [e] = EMPTY ;
+
+ ncmpa++ ; /* one more garbage collection */
+
+ /* store first entry of each object in Pe */
+ /* FLIP the first entry in each object */
+ for (j = 0 ; j < n ; j++)
+ {
+ pn = Pe [j] ;
+ if (pn >= 0)
+ {
+ ASSERT (pn >= 0 && pn < iwlen) ;
+ Pe [j] = Iw [pn] ;
+ Iw [pn] = FLIP (j) ;
+ }
+ }
+
+ /* psrc/pdst point to source/destination */
+ psrc = 0 ;
+ pdst = 0 ;
+ pend = pme1 - 1 ;
+
+ while (psrc <= pend)
+ {
+ /* search for next FLIP'd entry */
+ j = FLIP (Iw [psrc++]) ;
+ if (j >= 0)
+ {
+ AMD_DEBUG2 (("Got object j: "ID"\n", j)) ;
+ Iw [pdst] = Pe [j] ;
+ Pe [j] = pdst++ ;
+ lenj = Len [j] ;
+ /* copy from source to destination */
+ for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++)
+ {
+ Iw [pdst++] = Iw [psrc++] ;
+ }
+ }
+ }
+
+ /* move the new partially-constructed element */
+ p1 = pdst ;
+ for (psrc = pme1 ; psrc <= pfree-1 ; psrc++)
+ {
+ Iw [pdst++] = Iw [psrc] ;
+ }
+ pme1 = p1 ;
+ pfree = pdst ;
+ pj = Pe [e] ;
+ p = Pe [me] ;
+
+ }
+
+ /* ------------------------------------------------- */
+ /* i is a principal variable not yet placed in Lme */
+ /* store i in new list */
+ /* ------------------------------------------------- */
+
+ /* flag i as being in Lme by negating Nv [i] */
+ degme += nvi ;
+ Nv [i] = -nvi ;
+ Iw [pfree++] = i ;
+ AMD_DEBUG2 ((" s: "ID" nv "ID"\n", i, Nv [i]));
+
+ /* ------------------------------------------------- */
+ /* remove variable i from degree link list */
+ /* ------------------------------------------------- */
+
+ ilast = Last [i] ;
+ inext = Next [i] ;
+ ASSERT (ilast >= EMPTY && ilast < n) ;
+ ASSERT (inext >= EMPTY && inext < n) ;
+ if (inext != EMPTY) Last [inext] = ilast ;
+ if (ilast != EMPTY)
+ {
+ Next [ilast] = inext ;
+ }
+ else
+ {
+ /* i is at the head of the degree list */
+ ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+ Head [Degree [i]] = inext ;
+ }
+ }
+ }
+
+ if (e != me)
+ {
+ /* set tree pointer and flag to indicate element e is
+ * absorbed into new element me (the parent of e is me) */
+ AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ;
+ Pe [e] = FLIP (me) ;
+ W [e] = 0 ;
+ }
+ }
+
+ pme2 = pfree - 1 ;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* me has now been converted into an element in Iw [pme1..pme2] */
+ /* ----------------------------------------------------------------- */
+
+ /* degme holds the external degree of new element */
+ Degree [me] = degme ;
+ Pe [me] = pme1 ;
+ Len [me] = pme2 - pme1 + 1 ;
+ ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+ Elen [me] = FLIP (nvpiv + degme) ;
+ /* FLIP (Elen (me)) is now the degree of pivot (including
+ * diagonal part). */
+
+#ifndef NDEBUG
+ AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ;
+ for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme]));
+ AMD_DEBUG3 (("\n")) ;
+#endif
+
+ /* ----------------------------------------------------------------- */
+ /* make sure that wflg is not too large. */
+ /* ----------------------------------------------------------------- */
+
+ /* With the current value of wflg, wflg+n must not cause integer
+ * overflow */
+
+ wflg = clear_flag (wflg, wbig, W, n) ;
+
+/* ========================================================================= */
+/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */
+/* ========================================================================= */
+
+ /* -----------------------------------------------------------------
+ * Scan 1: compute the external degrees of previous elements with
+ * respect to the current element. That is:
+ * (W [e] - wflg) = |Le \ Lme|
+ * for each element e that appears in any supervariable in Lme. The
+ * notation Le refers to the pattern (list of supervariables) of a
+ * previous element e, where e is not yet absorbed, stored in
+ * Iw [Pe [e] + 1 ... Pe [e] + Len [e]]. The notation Lme
+ * refers to the pattern of the current element (stored in
+ * Iw [pme1..pme2]). If aggressive absorption is enabled, and
+ * (W [e] - wflg) becomes zero, then the element e will be absorbed
+ * in Scan 2.
+ * ----------------------------------------------------------------- */
+
+ AMD_DEBUG2 (("me: ")) ;
+ for (pme = pme1 ; pme <= pme2 ; pme++)
+ {
+ i = Iw [pme] ;
+ ASSERT (i >= 0 && i < n) ;
+ eln = Elen [i] ;
+ AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ;
+ if (eln > 0)
+ {
+ /* note that Nv [i] has been negated to denote i in Lme: */
+ nvi = -Nv [i] ;
+ ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ;
+ wnvi = wflg - nvi ;
+ for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++)
+ {
+ e = Iw [p] ;
+ ASSERT (e >= 0 && e < n) ;
+ we = W [e] ;
+ AMD_DEBUG4 ((" e "ID" we "ID" ", e, we)) ;
+ if (we >= wflg)
+ {
+ /* unabsorbed element e has been seen in this loop */
+ AMD_DEBUG4 ((" unabsorbed, first time seen")) ;
+ we -= nvi ;
+ }
+ else if (we != 0)
+ {
+ /* e is an unabsorbed element */
+ /* this is the first we have seen e in all of Scan 1 */
+ AMD_DEBUG4 ((" unabsorbed")) ;
+ we = Degree [e] + wnvi ;
+ }
+ AMD_DEBUG4 (("\n")) ;
+ W [e] = we ;
+ }
+ }
+ }
+ AMD_DEBUG2 (("\n")) ;
+
+/* ========================================================================= */
+/* DEGREE UPDATE AND ELEMENT ABSORPTION */
+/* ========================================================================= */
+
+ /* -----------------------------------------------------------------
+ * Scan 2: for each i in Lme, sum up the degree of Lme (which is
+ * degme), plus the sum of the external degrees of each Le for the
+ * elements e appearing within i, plus the supervariables in i.
+ * Place i in hash list.
+ * ----------------------------------------------------------------- */
+
+ for (pme = pme1 ; pme <= pme2 ; pme++)
+ {
+ i = Iw [pme] ;
+ ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ;
+ AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i]));
+ p1 = Pe [i] ;
+ p2 = p1 + Elen [i] - 1 ;
+ pn = p1 ;
+ hash = 0 ;
+ deg = 0 ;
+ ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ;
+
+ /* ------------------------------------------------------------- */
+ /* scan the element list associated with supervariable i */
+ /* ------------------------------------------------------------- */
+
+ /* UMFPACK/MA38-style approximate degree: */
+ if (aggressive)
+ {
+ for (p = p1 ; p <= p2 ; p++)
+ {
+ e = Iw [p] ;
+ ASSERT (e >= 0 && e < n) ;
+ we = W [e] ;
+ if (we != 0)
+ {
+ /* e is an unabsorbed element */
+ /* dext = | Le \ Lme | */
+ dext = we - wflg ;
+ if (dext > 0)
+ {
+ deg += dext ;
+ Iw [pn++] = e ;
+ hash += e ;
+ AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
+ }
+ else
+ {
+ /* external degree of e is zero, absorb e into me*/
+ AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n",
+ e, me)) ;
+ ASSERT (dext == 0) ;
+ Pe [e] = FLIP (me) ;
+ W [e] = 0 ;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (p = p1 ; p <= p2 ; p++)
+ {
+ e = Iw [p] ;
+ ASSERT (e >= 0 && e < n) ;
+ we = W [e] ;
+ if (we != 0)
+ {
+ /* e is an unabsorbed element */
+ dext = we - wflg ;
+ ASSERT (dext >= 0) ;
+ deg += dext ;
+ Iw [pn++] = e ;
+ hash += e ;
+ AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
+ }
+ }
+ }
+
+ /* count the number of elements in i (including me): */
+ Elen [i] = pn - p1 + 1 ;
+
+ /* ------------------------------------------------------------- */
+ /* scan the supervariables in the list associated with i */
+ /* ------------------------------------------------------------- */
+
+ /* The bulk of the AMD run time is typically spent in this loop,
+ * particularly if the matrix has many dense rows that are not
+ * removed prior to ordering. */
+ p3 = pn ;
+ p4 = p1 + Len [i] ;
+ for (p = p2 + 1 ; p < p4 ; p++)
+ {
+ j = Iw [p] ;
+ ASSERT (j >= 0 && j < n) ;
+ nvj = Nv [j] ;
+ if (nvj > 0)
+ {
+ /* j is unabsorbed, and not in Lme. */
+ /* add to degree and add to new list */
+ deg += nvj ;
+ Iw [pn++] = j ;
+ hash += j ;
+ AMD_DEBUG4 ((" s: "ID" hash "ID" Nv[j]= "ID"\n",
+ j, hash, nvj)) ;
+ }
+ }
+
+ /* ------------------------------------------------------------- */
+ /* update the degree and check for mass elimination */
+ /* ------------------------------------------------------------- */
+
+ /* with aggressive absorption, deg==0 is identical to the
+ * Elen [i] == 1 && p3 == pn test, below. */
+ ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ;
+
+ if (Elen [i] == 1 && p3 == pn)
+ {
+
+ /* --------------------------------------------------------- */
+ /* mass elimination */
+ /* --------------------------------------------------------- */
+
+ /* There is nothing left of this node except for an edge to
+ * the current pivot element. Elen [i] is 1, and there are
+ * no variables adjacent to node i. Absorb i into the
+ * current pivot element, me. Note that if there are two or
+ * more mass eliminations, fillin due to mass elimination is
+ * possible within the nvpiv-by-nvpiv pivot block. It is this
+ * step that causes AMD's analysis to be an upper bound.
+ *
+ * The reason is that the selected pivot has a lower
+ * approximate degree than the true degree of the two mass
+ * eliminated nodes. There is no edge between the two mass
+ * eliminated nodes. They are merged with the current pivot
+ * anyway.
+ *
+ * No fillin occurs in the Schur complement, in any case,
+ * and this effect does not decrease the quality of the
+ * ordering itself, just the quality of the nonzero and
+ * flop count analysis. It also means that the post-ordering
+ * is not an exact elimination tree post-ordering. */
+
+ AMD_DEBUG1 ((" MASS i "ID" => parent e "ID"\n", i, me)) ;
+ Pe [i] = FLIP (me) ;
+ nvi = -Nv [i] ;
+ degme -= nvi ;
+ nvpiv += nvi ;
+ nel += nvi ;
+ Nv [i] = 0 ;
+ Elen [i] = EMPTY ;
+
+ }
+ else
+ {
+
+ /* --------------------------------------------------------- */
+ /* update the upper-bound degree of i */
+ /* --------------------------------------------------------- */
+
+ /* the following degree does not yet include the size
+ * of the current element, which is added later: */
+
+ Degree [i] = MIN (Degree [i], deg) ;
+
+ /* --------------------------------------------------------- */
+ /* add me to the list for i */
+ /* --------------------------------------------------------- */
+
+ /* move first supervariable to end of list */
+ Iw [pn] = Iw [p3] ;
+ /* move first element to end of element part of list */
+ Iw [p3] = Iw [p1] ;
+ /* add new element, me, to front of list. */
+ Iw [p1] = me ;
+ /* store the new length of the list in Len [i] */
+ Len [i] = pn - p1 + 1 ;
+
+ /* --------------------------------------------------------- */
+ /* place in hash bucket. Save hash key of i in Last [i]. */
+ /* --------------------------------------------------------- */
+
+ /* NOTE: this can fail if hash is negative, because the ANSI C
+ * standard does not define a % b when a and/or b are negative.
+ * That's why hash is defined as an unsigned Int, to avoid this
+ * problem. */
+ hash = hash % n ;
+ ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ;
+
+ /* if the Hhead array is not used: */
+ j = Head [hash] ;
+ if (j <= EMPTY)
+ {
+ /* degree list is empty, hash head is FLIP (j) */
+ Next [i] = FLIP (j) ;
+ Head [hash] = FLIP (i) ;
+ }
+ else
+ {
+ /* degree list is not empty, use Last [Head [hash]] as
+ * hash head. */
+ Next [i] = Last [j] ;
+ Last [j] = i ;
+ }
+
+ /* if a separate Hhead array is used: *
+ Next [i] = Hhead [hash] ;
+ Hhead [hash] = i ;
+ */
+
+ Last [i] = hash ;
+ }
+ }
+
+ Degree [me] = degme ;
+
+ /* ----------------------------------------------------------------- */
+ /* Clear the counter array, W [...], by incrementing wflg. */
+ /* ----------------------------------------------------------------- */
+
+ /* make sure that wflg+n does not cause integer overflow */
+ lemax = MAX (lemax, degme) ;
+ wflg += lemax ;
+ wflg = clear_flag (wflg, wbig, W, n) ;
+ /* at this point, W [0..n-1] < wflg holds */
+
+/* ========================================================================= */
+/* SUPERVARIABLE DETECTION */
+/* ========================================================================= */
+
+ AMD_DEBUG1 (("Detecting supervariables:\n")) ;
+ for (pme = pme1 ; pme <= pme2 ; pme++)
+ {
+ i = Iw [pme] ;
+ ASSERT (i >= 0 && i < n) ;
+ AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ;
+ if (Nv [i] < 0)
+ {
+ /* i is a principal variable in Lme */
+
+ /* ---------------------------------------------------------
+ * examine all hash buckets with 2 or more variables. We do
+ * this by examing all unique hash keys for supervariables in
+ * the pattern Lme of the current element, me
+ * --------------------------------------------------------- */
+
+ /* let i = head of hash bucket, and empty the hash bucket */
+ ASSERT (Last [i] >= 0 && Last [i] < n) ;
+ hash = Last [i] ;
+
+ /* if Hhead array is not used: */
+ j = Head [hash] ;
+ if (j == EMPTY)
+ {
+ /* hash bucket and degree list are both empty */
+ i = EMPTY ;
+ }
+ else if (j < EMPTY)
+ {
+ /* degree list is empty */
+ i = FLIP (j) ;
+ Head [hash] = EMPTY ;
+ }
+ else
+ {
+ /* degree list is not empty, restore Last [j] of head j */
+ i = Last [j] ;
+ Last [j] = EMPTY ;
+ }
+
+ /* if separate Hhead array is used: *
+ i = Hhead [hash] ;
+ Hhead [hash] = EMPTY ;
+ */
+
+ ASSERT (i >= EMPTY && i < n) ;
+ AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ;
+
+ while (i != EMPTY && Next [i] != EMPTY)
+ {
+
+ /* -----------------------------------------------------
+ * this bucket has one or more variables following i.
+ * scan all of them to see if i can absorb any entries
+ * that follow i in hash bucket. Scatter i into w.
+ * ----------------------------------------------------- */
+
+ ln = Len [i] ;
+ eln = Elen [i] ;
+ ASSERT (ln >= 0 && eln >= 0) ;
+ ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ;
+ /* do not flag the first element in the list (me) */
+ for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++)
+ {
+ ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+ W [Iw [p]] = wflg ;
+ }
+
+ /* ----------------------------------------------------- */
+ /* scan every other entry j following i in bucket */
+ /* ----------------------------------------------------- */
+
+ jlast = i ;
+ j = Next [i] ;
+ ASSERT (j >= EMPTY && j < n) ;
+
+ while (j != EMPTY)
+ {
+ /* ------------------------------------------------- */
+ /* check if j and i have identical nonzero pattern */
+ /* ------------------------------------------------- */
+
+ AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ;
+
+ /* check if i and j have the same Len and Elen */
+ ASSERT (Len [j] >= 0 && Elen [j] >= 0) ;
+ ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ;
+ ok = (Len [j] == ln) && (Elen [j] == eln) ;
+ /* skip the first element in the list (me) */
+ for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++)
+ {
+ ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+ if (W [Iw [p]] != wflg) ok = 0 ;
+ }
+ if (ok)
+ {
+ /* --------------------------------------------- */
+ /* found it! j can be absorbed into i */
+ /* --------------------------------------------- */
+
+ AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i));
+ Pe [j] = FLIP (i) ;
+ /* both Nv [i] and Nv [j] are negated since they */
+ /* are in Lme, and the absolute values of each */
+ /* are the number of variables in i and j: */
+ Nv [i] += Nv [j] ;
+ Nv [j] = 0 ;
+ Elen [j] = EMPTY ;
+ /* delete j from hash bucket */
+ ASSERT (j != Next [j]) ;
+ j = Next [j] ;
+ Next [jlast] = j ;
+
+ }
+ else
+ {
+ /* j cannot be absorbed into i */
+ jlast = j ;
+ ASSERT (j != Next [j]) ;
+ j = Next [j] ;
+ }
+ ASSERT (j >= EMPTY && j < n) ;
+ }
+
+ /* -----------------------------------------------------
+ * no more variables can be absorbed into i
+ * go to next i in bucket and clear flag array
+ * ----------------------------------------------------- */
+
+ wflg++ ;
+ i = Next [i] ;
+ ASSERT (i >= EMPTY && i < n) ;
+
+ }
+ }
+ }
+ AMD_DEBUG2 (("detect done\n")) ;
+
+/* ========================================================================= */
+/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */
+/* ========================================================================= */
+
+ p = pme1 ;
+ nleft = n - nel ;
+ for (pme = pme1 ; pme <= pme2 ; pme++)
+ {
+ i = Iw [pme] ;
+ ASSERT (i >= 0 && i < n) ;
+ nvi = -Nv [i] ;
+ AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ;
+ if (nvi > 0)
+ {
+ /* i is a principal variable in Lme */
+ /* restore Nv [i] to signify that i is principal */
+ Nv [i] = nvi ;
+
+ /* --------------------------------------------------------- */
+ /* compute the external degree (add size of current element) */
+ /* --------------------------------------------------------- */
+
+ deg = Degree [i] + degme - nvi ;
+ deg = MIN (deg, nleft - nvi) ;
+ ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ;
+
+ /* --------------------------------------------------------- */
+ /* place the supervariable at the head of the degree list */
+ /* --------------------------------------------------------- */
+
+ inext = Head [deg] ;
+ ASSERT (inext >= EMPTY && inext < n) ;
+ if (inext != EMPTY) Last [inext] = i ;
+ Next [i] = inext ;
+ Last [i] = EMPTY ;
+ Head [deg] = i ;
+
+ /* --------------------------------------------------------- */
+ /* save the new degree, and find the minimum degree */
+ /* --------------------------------------------------------- */
+
+ mindeg = MIN (mindeg, deg) ;
+ Degree [i] = deg ;
+
+ /* --------------------------------------------------------- */
+ /* place the supervariable in the element pattern */
+ /* --------------------------------------------------------- */
+
+ Iw [p++] = i ;
+
+ }
+ }
+ AMD_DEBUG2 (("restore done\n")) ;
+
+/* ========================================================================= */
+/* FINALIZE THE NEW ELEMENT */
+/* ========================================================================= */
+
+ AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ;
+ Nv [me] = nvpiv ;
+ /* save the length of the list for the new element me */
+ Len [me] = p - pme1 ;
+ if (Len [me] == 0)
+ {
+ /* there is nothing left of the current pivot element */
+ /* it is a root of the assembly tree */
+ Pe [me] = EMPTY ;
+ W [me] = 0 ;
+ }
+ if (elenme != 0)
+ {
+ /* element was not constructed in place: deallocate part of */
+ /* it since newly nonprincipal variables may have been removed */
+ pfree = p ;
+ }
+
+ /* The new element has nvpiv pivots and the size of the contribution
+ * block for a multifrontal method is degme-by-degme, not including
+ * the "dense" rows/columns. If the "dense" rows/columns are included,
+ * the frontal matrix is no larger than
+ * (degme+ndense)-by-(degme+ndense).
+ */
+
+ if (Info != (double *) NULL)
+ {
+ f = nvpiv ;
+ r = degme + ndense ;
+ dmax = MAX (dmax, f + r) ;
+
+ /* number of nonzeros in L (excluding the diagonal) */
+ lnzme = f*r + (f-1)*f/2 ;
+ lnz += lnzme ;
+
+ /* number of divide operations for LDL' and for LU */
+ ndiv += lnzme ;
+
+ /* number of multiply-subtract pairs for LU */
+ s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ;
+ nms_lu += s ;
+
+ /* number of multiply-subtract pairs for LDL' */
+ nms_ldl += (s + lnzme)/2 ;
+ }
+
+#ifndef NDEBUG
+ AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n ::::\n", nel, n)) ;
+ for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++)
+ {
+ AMD_DEBUG3 ((" "ID"", Iw [pme])) ;
+ }
+ AMD_DEBUG3 (("\n")) ;
+#endif
+
+ }
+
+/* ========================================================================= */
+/* DONE SELECTING PIVOTS */
+/* ========================================================================= */
+
+ if (Info != (double *) NULL)
+ {
+
+ /* count the work to factorize the ndense-by-ndense submatrix */
+ f = ndense ;
+ dmax = MAX (dmax, (double) ndense) ;
+
+ /* number of nonzeros in L (excluding the diagonal) */
+ lnzme = (f-1)*f/2 ;
+ lnz += lnzme ;
+
+ /* number of divide operations for LDL' and for LU */
+ ndiv += lnzme ;
+
+ /* number of multiply-subtract pairs for LU */
+ s = (f-1)*f*(2*f-1)/6 ;
+ nms_lu += s ;
+
+ /* number of multiply-subtract pairs for LDL' */
+ nms_ldl += (s + lnzme)/2 ;
+
+ /* number of nz's in L (excl. diagonal) */
+ Info [AMD_LNZ] = lnz ;
+
+ /* number of divide ops for LU and LDL' */
+ Info [AMD_NDIV] = ndiv ;
+
+ /* number of multiply-subtract pairs for LDL' */
+ Info [AMD_NMULTSUBS_LDL] = nms_ldl ;
+
+ /* number of multiply-subtract pairs for LU */
+ Info [AMD_NMULTSUBS_LU] = nms_lu ;
+
+ /* number of "dense" rows/columns */
+ Info [AMD_NDENSE] = ndense ;
+
+ /* largest front is dmax-by-dmax */
+ Info [AMD_DMAX] = dmax ;
+
+ /* number of garbage collections in AMD */
+ Info [AMD_NCMPA] = ncmpa ;
+
+ /* successful ordering */
+ Info [AMD_STATUS] = AMD_OK ;
+ }
+
+/* ========================================================================= */
+/* POST-ORDERING */
+/* ========================================================================= */
+
+/* -------------------------------------------------------------------------
+ * Variables at this point:
+ *
+ * Pe: holds the elimination tree. The parent of j is FLIP (Pe [j]),
+ * or EMPTY if j is a root. The tree holds both elements and
+ * non-principal (unordered) variables absorbed into them.
+ * Dense variables are non-principal and unordered.
+ *
+ * Elen: holds the size of each element, including the diagonal part.
+ * FLIP (Elen [e]) > 0 if e is an element. For unordered
+ * variables i, Elen [i] is EMPTY.
+ *
+ * Nv: Nv [e] > 0 is the number of pivots represented by the element e.
+ * For unordered variables i, Nv [i] is zero.
+ *
+ * Contents no longer needed:
+ * W, Iw, Len, Degree, Head, Next, Last.
+ *
+ * The matrix itself has been destroyed.
+ *
+ * n: the size of the matrix.
+ * No other scalars needed (pfree, iwlen, etc.)
+ * ------------------------------------------------------------------------- */
+
+ /* restore Pe */
+ for (i = 0 ; i < n ; i++)
+ {
+ Pe [i] = FLIP (Pe [i]) ;
+ }
+
+ /* restore Elen, for output information, and for postordering */
+ for (i = 0 ; i < n ; i++)
+ {
+ Elen [i] = FLIP (Elen [i]) ;
+ }
+
+/* Now the parent of j is Pe [j], or EMPTY if j is a root. Elen [e] > 0
+ * is the size of element e. Elen [i] is EMPTY for unordered variable i. */
+
+#ifndef NDEBUG
+ AMD_DEBUG2 (("\nTree:\n")) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ AMD_DEBUG2 ((" "ID" parent: "ID" ", i, Pe [i])) ;
+ ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ;
+ if (Nv [i] > 0)
+ {
+ /* this is an element */
+ e = i ;
+ AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ;
+ ASSERT (Elen [e] > 0) ;
+ }
+ AMD_DEBUG2 (("\n")) ;
+ }
+ AMD_DEBUG2 (("\nelements:\n")) ;
+ for (e = 0 ; e < n ; e++)
+ {
+ if (Nv [e] > 0)
+ {
+ AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e,
+ Elen [e], Nv [e])) ;
+ }
+ }
+ AMD_DEBUG2 (("\nvariables:\n")) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ Int cnt ;
+ if (Nv [i] == 0)
+ {
+ AMD_DEBUG3 (("i unordered: "ID"\n", i)) ;
+ j = Pe [i] ;
+ cnt = 0 ;
+ AMD_DEBUG3 ((" j: "ID"\n", j)) ;
+ if (j == EMPTY)
+ {
+ AMD_DEBUG3 ((" i is a dense variable\n")) ;
+ }
+ else
+ {
+ ASSERT (j >= 0 && j < n) ;
+ while (Nv [j] == 0)
+ {
+ AMD_DEBUG3 ((" j : "ID"\n", j)) ;
+ j = Pe [j] ;
+ AMD_DEBUG3 ((" j:: "ID"\n", j)) ;
+ cnt++ ;
+ if (cnt > n) break ;
+ }
+ e = j ;
+ AMD_DEBUG3 ((" got to e: "ID"\n", e)) ;
+ }
+ }
+ }
+#endif
+
+/* ========================================================================= */
+/* compress the paths of the variables */
+/* ========================================================================= */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ if (Nv [i] == 0)
+ {
+
+ /* -------------------------------------------------------------
+ * i is an un-ordered row. Traverse the tree from i until
+ * reaching an element, e. The element, e, was the principal
+ * supervariable of i and all nodes in the path from i to when e
+ * was selected as pivot.
+ * ------------------------------------------------------------- */
+
+ AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ;
+ j = Pe [i] ;
+ ASSERT (j >= EMPTY && j < n) ;
+ AMD_DEBUG3 ((" j: "ID"\n", j)) ;
+ if (j == EMPTY)
+ {
+ /* Skip a dense variable. It has no parent. */
+ AMD_DEBUG3 ((" i is a dense variable\n")) ;
+ continue ;
+ }
+
+ /* while (j is a variable) */
+ while (Nv [j] == 0)
+ {
+ AMD_DEBUG3 ((" j : "ID"\n", j)) ;
+ j = Pe [j] ;
+ AMD_DEBUG3 ((" j:: "ID"\n", j)) ;
+ ASSERT (j >= 0 && j < n) ;
+ }
+ /* got to an element e */
+ e = j ;
+ AMD_DEBUG3 (("got to e: "ID"\n", e)) ;
+
+ /* -------------------------------------------------------------
+ * traverse the path again from i to e, and compress the path
+ * (all nodes point to e). Path compression allows this code to
+ * compute in O(n) time.
+ * ------------------------------------------------------------- */
+
+ j = i ;
+ /* while (j is a variable) */
+ while (Nv [j] == 0)
+ {
+ jnext = Pe [j] ;
+ AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ;
+ Pe [j] = e ;
+ j = jnext ;
+ ASSERT (j >= 0 && j < n) ;
+ }
+ }
+ }
+
+/* ========================================================================= */
+/* postorder the assembly tree */
+/* ========================================================================= */
+
+ AMD_postorder (n, Pe, Nv, Elen,
+ W, /* output order */
+ Head, Next, Last) ; /* workspace */
+
+/* ========================================================================= */
+/* compute output permutation and inverse permutation */
+/* ========================================================================= */
+
+ /* W [e] = k means that element e is the kth element in the new
+ * order. e is in the range 0 to n-1, and k is in the range 0 to
+ * the number of elements. Use Head for inverse order. */
+
+ for (k = 0 ; k < n ; k++)
+ {
+ Head [k] = EMPTY ;
+ Next [k] = EMPTY ;
+ }
+ for (e = 0 ; e < n ; e++)
+ {
+ k = W [e] ;
+ ASSERT ((k == EMPTY) == (Nv [e] == 0)) ;
+ if (k != EMPTY)
+ {
+ ASSERT (k >= 0 && k < n) ;
+ Head [k] = e ;
+ }
+ }
+
+ /* construct output inverse permutation in Next,
+ * and permutation in Last */
+ nel = 0 ;
+ for (k = 0 ; k < n ; k++)
+ {
+ e = Head [k] ;
+ if (e == EMPTY) break ;
+ ASSERT (e >= 0 && e < n && Nv [e] > 0) ;
+ Next [e] = nel ;
+ nel += Nv [e] ;
+ }
+ ASSERT (nel == n - ndense) ;
+
+ /* order non-principal variables (dense, & those merged into supervar's) */
+ for (i = 0 ; i < n ; i++)
+ {
+ if (Nv [i] == 0)
+ {
+ e = Pe [i] ;
+ ASSERT (e >= EMPTY && e < n) ;
+ if (e != EMPTY)
+ {
+ /* This is an unordered variable that was merged
+ * into element e via supernode detection or mass
+ * elimination of i when e became the pivot element.
+ * Place i in order just before e. */
+ ASSERT (Next [i] == EMPTY && Nv [e] > 0) ;
+ Next [i] = Next [e] ;
+ Next [e]++ ;
+ }
+ else
+ {
+ /* This is a dense unordered variable, with no parent.
+ * Place it last in the output order. */
+ Next [i] = nel++ ;
+ }
+ }
+ }
+ ASSERT (nel == n) ;
+
+ AMD_DEBUG2 (("\n\nPerm:\n")) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ k = Next [i] ;
+ ASSERT (k >= 0 && k < n) ;
+ Last [k] = i ;
+ AMD_DEBUG2 ((" perm ["ID"] = "ID"\n", k, i)) ;
+ }
+}
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_aat.c b/test/monniaux/glpk-4.65/src/amd/amd_aat.c
new file mode 100644
index 00000000..63bf55f5
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_aat.c
@@ -0,0 +1,185 @@
+/* ========================================================================= */
+/* === AMD_aat ============================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_aat: compute the symmetry of the pattern of A, and count the number of
+ * nonzeros each column of A+A' (excluding the diagonal). Assumes the input
+ * matrix has no errors, with sorted columns and no duplicates
+ * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not
+ * checked).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL size_t AMD_aat /* returns nz in A+A' */
+(
+ Int n,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ Int Len [ ], /* Len [j]: length of column j of A+A', excl diagonal*/
+ Int Tp [ ], /* workspace of size n */
+ double Info [ ]
+)
+{
+ Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ;
+ double sym ;
+ size_t nzaat ;
+
+#ifndef NDEBUG
+ AMD_debug_init ("AMD AAT") ;
+ for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
+ ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
+#endif
+
+ if (Info != (double *) NULL)
+ {
+ /* clear the Info array, if it exists */
+ for (i = 0 ; i < AMD_INFO ; i++)
+ {
+ Info [i] = EMPTY ;
+ }
+ Info [AMD_STATUS] = AMD_OK ;
+ }
+
+ for (k = 0 ; k < n ; k++)
+ {
+ Len [k] = 0 ;
+ }
+
+ nzdiag = 0 ;
+ nzboth = 0 ;
+ nz = Ap [n] ;
+
+ for (k = 0 ; k < n ; k++)
+ {
+ p1 = Ap [k] ;
+ p2 = Ap [k+1] ;
+ AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
+
+ /* construct A+A' */
+ for (p = p1 ; p < p2 ; )
+ {
+ /* scan the upper triangular part of A */
+ j = Ai [p] ;
+ if (j < k)
+ {
+ /* entry A (j,k) is in the strictly upper triangular part,
+ * add both A (j,k) and A (k,j) to the matrix A+A' */
+ Len [j]++ ;
+ Len [k]++ ;
+ AMD_DEBUG3 ((" upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
+ p++ ;
+ }
+ else if (j == k)
+ {
+ /* skip the diagonal */
+ p++ ;
+ nzdiag++ ;
+ break ;
+ }
+ else /* j > k */
+ {
+ /* first entry below the diagonal */
+ break ;
+ }
+ /* scan lower triangular part of A, in column j until reaching
+ * row k. Start where last scan left off. */
+ ASSERT (Tp [j] != EMPTY) ;
+ ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+ pj2 = Ap [j+1] ;
+ for (pj = Tp [j] ; pj < pj2 ; )
+ {
+ i = Ai [pj] ;
+ if (i < k)
+ {
+ /* A (i,j) is only in the lower part, not in upper.
+ * add both A (i,j) and A (j,i) to the matrix A+A' */
+ Len [i]++ ;
+ Len [j]++ ;
+ AMD_DEBUG3 ((" lower ("ID","ID") ("ID","ID")\n",
+ i,j, j,i)) ;
+ pj++ ;
+ }
+ else if (i == k)
+ {
+ /* entry A (k,j) in lower part and A (j,k) in upper */
+ pj++ ;
+ nzboth++ ;
+ break ;
+ }
+ else /* i > k */
+ {
+ /* consider this entry later, when k advances to i */
+ break ;
+ }
+ }
+ Tp [j] = pj ;
+ }
+ /* Tp [k] points to the entry just below the diagonal in column k */
+ Tp [k] = p ;
+ }
+
+ /* clean up, for remaining mismatched entries */
+ for (j = 0 ; j < n ; j++)
+ {
+ for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+ {
+ i = Ai [pj] ;
+ /* A (i,j) is only in the lower part, not in upper.
+ * add both A (i,j) and A (j,i) to the matrix A+A' */
+ Len [i]++ ;
+ Len [j]++ ;
+ AMD_DEBUG3 ((" lower cleanup ("ID","ID") ("ID","ID")\n",
+ i,j, j,i)) ;
+ }
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* compute the symmetry of the nonzero pattern of A */
+ /* --------------------------------------------------------------------- */
+
+ /* Given a matrix A, the symmetry of A is:
+ * B = tril (spones (A), -1) + triu (spones (A), 1) ;
+ * sym = nnz (B & B') / nnz (B) ;
+ * or 1 if nnz (B) is zero.
+ */
+
+ if (nz == nzdiag)
+ {
+ sym = 1 ;
+ }
+ else
+ {
+ sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ;
+ }
+
+ nzaat = 0 ;
+ for (k = 0 ; k < n ; k++)
+ {
+ nzaat += Len [k] ;
+ }
+
+ AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n",
+ (double) nzaat)) ;
+ AMD_DEBUG1 ((" nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
+ nzboth, nz, nzdiag, sym)) ;
+
+ if (Info != (double *) NULL)
+ {
+ Info [AMD_STATUS] = AMD_OK ;
+ Info [AMD_N] = n ;
+ Info [AMD_NZ] = nz ;
+ Info [AMD_SYMMETRY] = sym ; /* symmetry of pattern of A */
+ Info [AMD_NZDIAG] = nzdiag ; /* nonzeros on diagonal of A */
+ Info [AMD_NZ_A_PLUS_AT] = nzaat ; /* nonzeros in A+A' */
+ }
+
+ return (nzaat) ;
+}
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_control.c b/test/monniaux/glpk-4.65/src/amd/amd_control.c
new file mode 100644
index 00000000..f4d4f0df
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_control.c
@@ -0,0 +1,64 @@
+/* ========================================================================= */
+/* === AMD_control ========================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable. Prints the control parameters for AMD. See amd.h
+ * for details. If the Control array is not present, the defaults are
+ * printed instead.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_control
+(
+ double Control [ ]
+)
+{
+ double alpha ;
+ Int aggressive ;
+
+ if (Control != (double *) NULL)
+ {
+ alpha = Control [AMD_DENSE] ;
+ aggressive = Control [AMD_AGGRESSIVE] != 0 ;
+ }
+ else
+ {
+ alpha = AMD_DEFAULT_DENSE ;
+ aggressive = AMD_DEFAULT_AGGRESSIVE ;
+ }
+
+ PRINTF (("\nAMD version %d.%d.%d, %s: approximate minimum degree ordering\n"
+ " dense row parameter: %g\n", AMD_MAIN_VERSION, AMD_SUB_VERSION,
+ AMD_SUBSUB_VERSION, AMD_DATE, alpha)) ;
+
+ if (alpha < 0)
+ {
+ PRINTF ((" no rows treated as dense\n")) ;
+ }
+ else
+ {
+ PRINTF ((
+ " (rows with more than max (%g * sqrt (n), 16) entries are\n"
+ " considered \"dense\", and placed last in output permutation)\n",
+ alpha)) ;
+ }
+
+ if (aggressive)
+ {
+ PRINTF ((" aggressive absorption: yes\n")) ;
+ }
+ else
+ {
+ PRINTF ((" aggressive absorption: no\n")) ;
+ }
+
+ PRINTF ((" size of AMD integer: %d\n\n", sizeof (Int))) ;
+}
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_defaults.c b/test/monniaux/glpk-4.65/src/amd/amd_defaults.c
new file mode 100644
index 00000000..820e8942
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_defaults.c
@@ -0,0 +1,38 @@
+/* ========================================================================= */
+/* === AMD_defaults ======================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable. Sets default control parameters for AMD. See amd.h
+ * for details.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD defaults ======================================================== */
+/* ========================================================================= */
+
+GLOBAL void AMD_defaults
+(
+ double Control [ ]
+)
+{
+ Int i ;
+
+ if (Control != (double *) NULL)
+ {
+ for (i = 0 ; i < AMD_CONTROL ; i++)
+ {
+ Control [i] = 0 ;
+ }
+ Control [AMD_DENSE] = AMD_DEFAULT_DENSE ;
+ Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ;
+ }
+}
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_dump.c b/test/monniaux/glpk-4.65/src/amd/amd_dump.c
new file mode 100644
index 00000000..39bbe1d8
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_dump.c
@@ -0,0 +1,180 @@
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Debugging routines for AMD. Not used if NDEBUG is not defined at compile-
+ * time (the default). See comments in amd_internal.h on how to enable
+ * debugging. Not user-callable.
+ */
+
+#include "amd_internal.h"
+
+#ifndef NDEBUG
+
+/* This global variable is present only when debugging */
+GLOBAL Int AMD_debug = -999 ; /* default is no debug printing */
+
+/* ========================================================================= */
+/* === AMD_debug_init ====================================================== */
+/* ========================================================================= */
+
+/* Sets the debug print level, by reading the file debug.amd (if it exists) */
+
+GLOBAL void AMD_debug_init ( char *s )
+{
+ FILE *f ;
+ f = fopen ("debug.amd", "r") ;
+ if (f == (FILE *) NULL)
+ {
+ AMD_debug = -999 ;
+ }
+ else
+ {
+ fscanf (f, ID, &AMD_debug) ;
+ fclose (f) ;
+ }
+ if (AMD_debug >= 0)
+ {
+ printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug) ;
+ }
+}
+
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* Dump AMD's data structure, except for the hash buckets. This routine
+ * cannot be called when the hash buckets are non-empty.
+ */
+
+GLOBAL void AMD_dump (
+ Int n, /* A is n-by-n */
+ Int Pe [ ], /* pe [0..n-1]: index in iw of start of row i */
+ Int Iw [ ], /* workspace of size iwlen, iwlen [0..pfree-1]
+ * holds the matrix on input */
+ Int Len [ ], /* len [0..n-1]: length for row i */
+ Int iwlen, /* length of iw */
+ Int pfree, /* iw [pfree ... iwlen-1] is empty on input */
+ Int Nv [ ], /* nv [0..n-1] */
+ Int Next [ ], /* next [0..n-1] */
+ Int Last [ ], /* last [0..n-1] */
+ Int Head [ ], /* head [0..n-1] */
+ Int Elen [ ], /* size n */
+ Int Degree [ ], /* size n */
+ Int W [ ], /* size n */
+ Int nel
+)
+{
+ Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ;
+
+ if (AMD_debug < 0) return ;
+ ASSERT (pfree <= iwlen) ;
+ AMD_DEBUG3 (("\nAMD dump, pfree: "ID"\n", pfree)) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ pe = Pe [i] ;
+ elen = Elen [i] ;
+ nv = Nv [i] ;
+ len = Len [i] ;
+ w = W [i] ;
+
+ if (elen >= EMPTY)
+ {
+ if (nv == 0)
+ {
+ AMD_DEBUG3 (("\nI "ID": nonprincipal: ", i)) ;
+ ASSERT (elen == EMPTY) ;
+ if (pe == EMPTY)
+ {
+ AMD_DEBUG3 ((" dense node\n")) ;
+ ASSERT (w == 1) ;
+ }
+ else
+ {
+ ASSERT (pe < EMPTY) ;
+ AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i])));
+ }
+ }
+ else
+ {
+ AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i));
+ AMD_DEBUG3 ((" nv(i): "ID" Flag: %d\n", nv, (nv < 0))) ;
+ ASSERT (elen >= 0) ;
+ ASSERT (nv > 0 && pe >= 0) ;
+ p = pe ;
+ AMD_DEBUG3 ((" e/s: ")) ;
+ if (elen == 0) AMD_DEBUG3 ((" : ")) ;
+ ASSERT (pe + len <= pfree) ;
+ for (k = 0 ; k < len ; k++)
+ {
+ j = Iw [p] ;
+ AMD_DEBUG3 ((" "ID"", j)) ;
+ ASSERT (j >= 0 && j < n) ;
+ if (k == elen-1) AMD_DEBUG3 ((" : ")) ;
+ p++ ;
+ }
+ AMD_DEBUG3 (("\n")) ;
+ }
+ }
+ else
+ {
+ e = i ;
+ if (w == 0)
+ {
+ AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ;
+ ASSERT (nv > 0 && pe < 0) ;
+ AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ;
+ }
+ else
+ {
+ AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ;
+ ASSERT (nv > 0 && pe >= 0) ;
+ p = pe ;
+ AMD_DEBUG3 ((" : ")) ;
+ ASSERT (pe + len <= pfree) ;
+ for (k = 0 ; k < len ; k++)
+ {
+ j = Iw [p] ;
+ AMD_DEBUG3 ((" "ID"", j)) ;
+ ASSERT (j >= 0 && j < n) ;
+ p++ ;
+ }
+ AMD_DEBUG3 (("\n")) ;
+ }
+ }
+ }
+
+ /* this routine cannot be called when the hash buckets are non-empty */
+ AMD_DEBUG3 (("\nDegree lists:\n")) ;
+ if (nel >= 0)
+ {
+ cnt = 0 ;
+ for (deg = 0 ; deg < n ; deg++)
+ {
+ if (Head [deg] == EMPTY) continue ;
+ ilast = EMPTY ;
+ AMD_DEBUG3 ((ID": \n", deg)) ;
+ for (i = Head [deg] ; i != EMPTY ; i = Next [i])
+ {
+ AMD_DEBUG3 ((" "ID" : next "ID" last "ID" deg "ID"\n",
+ i, Next [i], Last [i], Degree [i])) ;
+ ASSERT (i >= 0 && i < n && ilast == Last [i] &&
+ deg == Degree [i]) ;
+ cnt += Nv [i] ;
+ ilast = i ;
+ }
+ AMD_DEBUG3 (("\n")) ;
+ }
+ ASSERT (cnt == n - nel) ;
+ }
+
+}
+
+#endif
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_info.c b/test/monniaux/glpk-4.65/src/amd/amd_info.c
new file mode 100644
index 00000000..e7b806a9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_info.c
@@ -0,0 +1,120 @@
+/* ========================================================================= */
+/* === AMD_info ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable. Prints the output statistics for AMD. See amd.h
+ * for details. If the Info array is not present, nothing is printed.
+ */
+
+#include "amd_internal.h"
+
+#define PRI(format,x) { if (x >= 0) { PRINTF ((format, x)) ; }}
+
+GLOBAL void AMD_info
+(
+ double Info [ ]
+)
+{
+ double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ;
+
+ PRINTF (("\nAMD version %d.%d.%d, %s, results:\n",
+ AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE)) ;
+
+ if (!Info)
+ {
+ return ;
+ }
+
+ n = Info [AMD_N] ;
+ ndiv = Info [AMD_NDIV] ;
+ nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ;
+ nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ;
+ lnz = Info [AMD_LNZ] ;
+ lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ;
+
+ /* AMD return status */
+ PRINTF ((" status: ")) ;
+ if (Info [AMD_STATUS] == AMD_OK)
+ {
+ PRINTF (("OK\n")) ;
+ }
+ else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY)
+ {
+ PRINTF (("out of memory\n")) ;
+ }
+ else if (Info [AMD_STATUS] == AMD_INVALID)
+ {
+ PRINTF (("invalid matrix\n")) ;
+ }
+ else if (Info [AMD_STATUS] == AMD_OK_BUT_JUMBLED)
+ {
+ PRINTF (("OK, but jumbled\n")) ;
+ }
+ else
+ {
+ PRINTF (("unknown\n")) ;
+ }
+
+ /* statistics about the input matrix */
+ PRI (" n, dimension of A: %.20g\n", n);
+ PRI (" nz, number of nonzeros in A: %.20g\n",
+ Info [AMD_NZ]) ;
+ PRI (" symmetry of A: %.4f\n",
+ Info [AMD_SYMMETRY]) ;
+ PRI (" number of nonzeros on diagonal: %.20g\n",
+ Info [AMD_NZDIAG]) ;
+ PRI (" nonzeros in pattern of A+A' (excl. diagonal): %.20g\n",
+ Info [AMD_NZ_A_PLUS_AT]) ;
+ PRI (" # dense rows/columns of A+A': %.20g\n",
+ Info [AMD_NDENSE]) ;
+
+ /* statistics about AMD's behavior */
+ PRI (" memory used, in bytes: %.20g\n",
+ Info [AMD_MEMORY]) ;
+ PRI (" # of memory compactions: %.20g\n",
+ Info [AMD_NCMPA]) ;
+
+ /* statistics about the ordering quality */
+ PRINTF (("\n"
+ " The following approximate statistics are for a subsequent\n"
+ " factorization of A(P,P) + A(P,P)'. They are slight upper\n"
+ " bounds if there are no dense rows/columns in A+A', and become\n"
+ " looser if dense rows/columns exist.\n\n")) ;
+
+ PRI (" nonzeros in L (excluding diagonal): %.20g\n",
+ lnz) ;
+ PRI (" nonzeros in L (including diagonal): %.20g\n",
+ lnzd) ;
+ PRI (" # divide operations for LDL' or LU: %.20g\n",
+ ndiv) ;
+ PRI (" # multiply-subtract operations for LDL': %.20g\n",
+ nmultsubs_ldl) ;
+ PRI (" # multiply-subtract operations for LU: %.20g\n",
+ nmultsubs_lu) ;
+ PRI (" max nz. in any column of L (incl. diagonal): %.20g\n",
+ Info [AMD_DMAX]) ;
+
+ /* total flop counts for various factorizations */
+
+ if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0)
+ {
+ PRINTF (("\n"
+ " chol flop count for real A, sqrt counted as 1 flop: %.20g\n"
+ " LDL' flop count for real A: %.20g\n"
+ " LDL' flop count for complex A: %.20g\n"
+ " LU flop count for real A (with no pivoting): %.20g\n"
+ " LU flop count for complex A (with no pivoting): %.20g\n\n",
+ n + ndiv + 2*nmultsubs_ldl,
+ ndiv + 2*nmultsubs_ldl,
+ 9*ndiv + 8*nmultsubs_ldl,
+ ndiv + 2*nmultsubs_lu,
+ 9*ndiv + 8*nmultsubs_lu)) ;
+ }
+}
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_internal.h b/test/monniaux/glpk-4.65/src/amd/amd_internal.h
new file mode 100644
index 00000000..b08f8436
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_internal.h
@@ -0,0 +1,117 @@
+/* amd_internal.h */
+
+/* Written by Andrew Makhorin <mao@gnu.org>. */
+
+#ifndef AMD_INTERNAL_H
+#define AMD_INTERNAL_H
+
+/* AMD will be exceedingly slow when running in debug mode. */
+#if 1
+#define NDEBUG
+#endif
+
+#include "amd.h"
+#define _GLPSTD_STDIO
+#include "env.h"
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+
+#if 0 /* 15/II-2012 */
+/* now this macro is defined in glpenv.h; besides, the definiton below
+ depends on implementation, because size_t is an unsigned type */
+#define SIZE_T_MAX ((size_t)(-1))
+#endif
+
+#define EMPTY (-1)
+#define FLIP(i) (-(i)-2)
+#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i))
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define IMPLIES(p, q) (!(p) || (q))
+
+#define GLOBAL
+
+#define AMD_order amd_order
+#define AMD_defaults amd_defaults
+#define AMD_control amd_control
+#define AMD_info amd_info
+#define AMD_1 amd_1
+#define AMD_2 amd_2
+#define AMD_valid amd_valid
+#define AMD_aat amd_aat
+#define AMD_postorder amd_postorder
+#define AMD_post_tree amd_post_tree
+#define AMD_dump amd_dump
+#define AMD_debug amd_debug
+#define AMD_debug_init amd_debug_init
+#define AMD_preprocess amd_preprocess
+
+#define amd_malloc xmalloc
+#if 0 /* 24/V-2009 */
+#define amd_free xfree
+#else
+#define amd_free(ptr) { if ((ptr) != NULL) xfree(ptr); }
+#endif
+#define amd_printf xprintf
+
+#define PRINTF(params) { amd_printf params; }
+
+#ifndef NDEBUG
+#define ASSERT(expr) xassert(expr)
+#define AMD_DEBUG0(params) { PRINTF(params); }
+#define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF(params); }
+#define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF(params); }
+#define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF(params); }
+#define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF(params); }
+#else
+#define ASSERT(expression)
+#define AMD_DEBUG0(params)
+#define AMD_DEBUG1(params)
+#define AMD_DEBUG2(params)
+#define AMD_DEBUG3(params)
+#define AMD_DEBUG4(params)
+#endif
+
+#define amd_aat _glp_amd_aat
+size_t AMD_aat(Int n, const Int Ap[], const Int Ai[], Int Len[],
+ Int Tp[], double Info[]);
+
+#define amd_1 _glp_amd_1
+void AMD_1(Int n, const Int Ap[], const Int Ai[], Int P[], Int Pinv[],
+ Int Len[], Int slen, Int S[], double Control[], double Info[]);
+
+#define amd_postorder _glp_amd_postorder
+void AMD_postorder(Int nn, Int Parent[], Int Npiv[], Int Fsize[],
+ Int Order[], Int Child[], Int Sibling[], Int Stack[]);
+
+#define amd_post_tree _glp_amd_post_tree
+#ifndef NDEBUG
+Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[],
+ Int Order[], Int Stack[], Int nn);
+#else
+Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[],
+ Int Order[], Int Stack[]);
+#endif
+
+#define amd_preprocess _glp_amd_preprocess
+void AMD_preprocess(Int n, const Int Ap[], const Int Ai[], Int Rp[],
+ Int Ri[], Int W[], Int Flag[]);
+
+#define amd_debug _glp_amd_debug
+extern Int AMD_debug;
+
+#define amd_debug_init _glp_amd_debug_init
+void AMD_debug_init(char *s);
+
+#define amd_dump _glp_amd_dump
+void AMD_dump(Int n, Int Pe[], Int Iw[], Int Len[], Int iwlen,
+ Int pfree, Int Nv[], Int Next[], Int Last[], Int Head[],
+ Int Elen[], Int Degree[], Int W[], Int nel);
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_order.c b/test/monniaux/glpk-4.65/src/amd/amd_order.c
new file mode 100644
index 00000000..332d5663
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_order.c
@@ -0,0 +1,200 @@
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable AMD minimum degree ordering routine. See amd.h for
+ * documentation.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+GLOBAL Int AMD_order
+(
+ Int n,
+ const Int Ap [ ],
+ const Int Ai [ ],
+ Int P [ ],
+ double Control [ ],
+ double Info [ ]
+)
+{
+ Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ;
+ size_t nzaat, slen ;
+ double mem = 0 ;
+
+#ifndef NDEBUG
+ AMD_debug_init ("amd") ;
+#endif
+
+ /* clear the Info array, if it exists */
+ info = Info != (double *) NULL ;
+ if (info)
+ {
+ for (i = 0 ; i < AMD_INFO ; i++)
+ {
+ Info [i] = EMPTY ;
+ }
+ Info [AMD_N] = n ;
+ Info [AMD_STATUS] = AMD_OK ;
+ }
+
+ /* make sure inputs exist and n is >= 0 */
+ if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0)
+ {
+ if (info) Info [AMD_STATUS] = AMD_INVALID ;
+ return (AMD_INVALID) ; /* arguments are invalid */
+ }
+
+ if (n == 0)
+ {
+ return (AMD_OK) ; /* n is 0 so there's nothing to do */
+ }
+
+ nz = Ap [n] ;
+ if (info)
+ {
+ Info [AMD_NZ] = nz ;
+ }
+ if (nz < 0)
+ {
+ if (info) Info [AMD_STATUS] = AMD_INVALID ;
+ return (AMD_INVALID) ;
+ }
+
+ /* check if n or nz will cause size_t overflow */
+ if (((size_t) n) >= SIZE_T_MAX / sizeof (Int)
+ || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int))
+ {
+ if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+ return (AMD_OUT_OF_MEMORY) ; /* problem too large */
+ }
+
+ /* check the input matrix: AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */
+ status = AMD_valid (n, n, Ap, Ai) ;
+
+ if (status == AMD_INVALID)
+ {
+ if (info) Info [AMD_STATUS] = AMD_INVALID ;
+ return (AMD_INVALID) ; /* matrix is invalid */
+ }
+
+ /* allocate two size-n integer workspaces */
+ Len = amd_malloc (n * sizeof (Int)) ;
+ Pinv = amd_malloc (n * sizeof (Int)) ;
+ mem += n ;
+ mem += n ;
+ if (!Len || !Pinv)
+ {
+ /* :: out of memory :: */
+ amd_free (Len) ;
+ amd_free (Pinv) ;
+ if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+ return (AMD_OUT_OF_MEMORY) ;
+ }
+
+ if (status == AMD_OK_BUT_JUMBLED)
+ {
+ /* sort the input matrix and remove duplicate entries */
+ AMD_DEBUG1 (("Matrix is jumbled\n")) ;
+ Rp = amd_malloc ((n+1) * sizeof (Int)) ;
+ Ri = amd_malloc (MAX (nz,1) * sizeof (Int)) ;
+ mem += (n+1) ;
+ mem += MAX (nz,1) ;
+ if (!Rp || !Ri)
+ {
+ /* :: out of memory :: */
+ amd_free (Rp) ;
+ amd_free (Ri) ;
+ amd_free (Len) ;
+ amd_free (Pinv) ;
+ if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+ return (AMD_OUT_OF_MEMORY) ;
+ }
+ /* use Len and Pinv as workspace to create R = A' */
+ AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ;
+ Cp = Rp ;
+ Ci = Ri ;
+ }
+ else
+ {
+ /* order the input matrix as-is. No need to compute R = A' first */
+ Rp = NULL ;
+ Ri = NULL ;
+ Cp = (Int *) Ap ;
+ Ci = (Int *) Ai ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* determine the symmetry and count off-diagonal nonzeros in A+A' */
+ /* --------------------------------------------------------------------- */
+
+ nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ;
+ AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ;
+ ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ;
+
+ /* --------------------------------------------------------------------- */
+ /* allocate workspace for matrix, elbow room, and 6 size-n vectors */
+ /* --------------------------------------------------------------------- */
+
+ S = NULL ;
+ slen = nzaat ; /* space for matrix */
+ ok = ((slen + nzaat/5) >= slen) ; /* check for size_t overflow */
+ slen += nzaat/5 ; /* add elbow room */
+ for (i = 0 ; ok && i < 7 ; i++)
+ {
+ ok = ((slen + n) > slen) ; /* check for size_t overflow */
+ slen += n ; /* size-n elbow room, 6 size-n work */
+ }
+ mem += slen ;
+ ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */
+ ok = ok && (slen < Int_MAX) ; /* S[i] for Int i must be OK */
+ if (ok)
+ {
+ S = amd_malloc (slen * sizeof (Int)) ;
+ }
+ AMD_DEBUG1 (("slen %g\n", (double) slen)) ;
+ if (!S)
+ {
+ /* :: out of memory :: (or problem too large) */
+ amd_free (Rp) ;
+ amd_free (Ri) ;
+ amd_free (Len) ;
+ amd_free (Pinv) ;
+ if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+ return (AMD_OUT_OF_MEMORY) ;
+ }
+ if (info)
+ {
+ /* memory usage, in bytes. */
+ Info [AMD_MEMORY] = mem * sizeof (Int) ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* order the matrix */
+ /* --------------------------------------------------------------------- */
+
+ AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ;
+
+ /* --------------------------------------------------------------------- */
+ /* free the workspace */
+ /* --------------------------------------------------------------------- */
+
+ amd_free (Rp) ;
+ amd_free (Ri) ;
+ amd_free (Len) ;
+ amd_free (Pinv) ;
+ amd_free (S) ;
+ if (info) Info [AMD_STATUS] = status ;
+ return (status) ; /* successful ordering */
+}
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_post_tree.c b/test/monniaux/glpk-4.65/src/amd/amd_post_tree.c
new file mode 100644
index 00000000..bff0e263
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_post_tree.c
@@ -0,0 +1,121 @@
+/* ========================================================================= */
+/* === AMD_post_tree ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Post-ordering of a supernodal elimination tree. */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_post_tree
+(
+ Int root, /* root of the tree */
+ Int k, /* start numbering at k */
+ Int Child [ ], /* input argument of size nn, undefined on
+ * output. Child [i] is the head of a link
+ * list of all nodes that are children of node
+ * i in the tree. */
+ const Int Sibling [ ], /* input argument of size nn, not modified.
+ * If f is a node in the link list of the
+ * children of node i, then Sibling [f] is the
+ * next child of node i.
+ */
+ Int Order [ ], /* output order, of size nn. Order [i] = k
+ * if node i is the kth node of the reordered
+ * tree. */
+ Int Stack [ ] /* workspace of size nn */
+#ifndef NDEBUG
+ , Int nn /* nodes are in the range 0..nn-1. */
+#endif
+)
+{
+ Int f, head, h, i ;
+
+#if 0
+ /* --------------------------------------------------------------------- */
+ /* recursive version (Stack [ ] is not used): */
+ /* --------------------------------------------------------------------- */
+
+ /* this is simple, but can caouse stack overflow if nn is large */
+ i = root ;
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ;
+ }
+ Order [i] = k++ ;
+ return (k) ;
+#endif
+
+ /* --------------------------------------------------------------------- */
+ /* non-recursive version, using an explicit stack */
+ /* --------------------------------------------------------------------- */
+
+ /* push root on the stack */
+ head = 0 ;
+ Stack [0] = root ;
+
+ while (head >= 0)
+ {
+ /* get head of stack */
+ ASSERT (head < nn) ;
+ i = Stack [head] ;
+ AMD_DEBUG1 (("head of stack "ID" \n", i)) ;
+ ASSERT (i >= 0 && i < nn) ;
+
+ if (Child [i] != EMPTY)
+ {
+ /* the children of i are not yet ordered */
+ /* push each child onto the stack in reverse order */
+ /* so that small ones at the head of the list get popped first */
+ /* and the biggest one at the end of the list gets popped last */
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ head++ ;
+ ASSERT (head < nn) ;
+ ASSERT (f >= 0 && f < nn) ;
+ }
+ h = head ;
+ ASSERT (head < nn) ;
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ ASSERT (h > 0) ;
+ Stack [h--] = f ;
+ AMD_DEBUG1 (("push "ID" on stack\n", f)) ;
+ ASSERT (f >= 0 && f < nn) ;
+ }
+ ASSERT (Stack [h] == i) ;
+
+ /* delete child list so that i gets ordered next time we see it */
+ Child [i] = EMPTY ;
+ }
+ else
+ {
+ /* the children of i (if there were any) are already ordered */
+ /* remove i from the stack and order it. Front i is kth front */
+ head-- ;
+ AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ;
+ Order [i] = k++ ;
+ ASSERT (k <= nn) ;
+ }
+
+#ifndef NDEBUG
+ AMD_DEBUG1 (("\nStack:")) ;
+ for (h = head ; h >= 0 ; h--)
+ {
+ Int j = Stack [h] ;
+ AMD_DEBUG1 ((" "ID, j)) ;
+ ASSERT (j >= 0 && j < nn) ;
+ }
+ AMD_DEBUG1 (("\n\n")) ;
+ ASSERT (head < nn) ;
+#endif
+
+ }
+ return (k) ;
+}
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_postorder.c b/test/monniaux/glpk-4.65/src/amd/amd_postorder.c
new file mode 100644
index 00000000..a3ece915
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_postorder.c
@@ -0,0 +1,207 @@
+/* ========================================================================= */
+/* === AMD_postorder ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Perform a postordering (via depth-first search) of an assembly tree. */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_postorder
+(
+ /* inputs, not modified on output: */
+ Int nn, /* nodes are in the range 0..nn-1 */
+ Int Parent [ ], /* Parent [j] is the parent of j, or EMPTY if root */
+ Int Nv [ ], /* Nv [j] > 0 number of pivots represented by node j,
+ * or zero if j is not a node. */
+ Int Fsize [ ], /* Fsize [j]: size of node j */
+
+ /* output, not defined on input: */
+ Int Order [ ], /* output post-order */
+
+ /* workspaces of size nn: */
+ Int Child [ ],
+ Int Sibling [ ],
+ Int Stack [ ]
+)
+{
+ Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ;
+
+ for (j = 0 ; j < nn ; j++)
+ {
+ Child [j] = EMPTY ;
+ Sibling [j] = EMPTY ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* place the children in link lists - bigger elements tend to be last */
+ /* --------------------------------------------------------------------- */
+
+ for (j = nn-1 ; j >= 0 ; j--)
+ {
+ if (Nv [j] > 0)
+ {
+ /* this is an element */
+ parent = Parent [j] ;
+ if (parent != EMPTY)
+ {
+ /* place the element in link list of the children its parent */
+ /* bigger elements will tend to be at the end of the list */
+ Sibling [j] = Child [parent] ;
+ Child [parent] = j ;
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ {
+ Int nels, ff, nchild ;
+ AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n"));
+ nels = 0 ;
+ for (j = 0 ; j < nn ; j++)
+ {
+ if (Nv [j] > 0)
+ {
+ AMD_DEBUG1 (( ""ID" : nels "ID" npiv "ID" size "ID
+ " parent "ID" maxfr "ID"\n", j, nels,
+ Nv [j], Fsize [j], Parent [j], Fsize [j])) ;
+ /* this is an element */
+ /* dump the link list of children */
+ nchild = 0 ;
+ AMD_DEBUG1 ((" Children: ")) ;
+ for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff])
+ {
+ AMD_DEBUG1 ((ID" ", ff)) ;
+ ASSERT (Parent [ff] == j) ;
+ nchild++ ;
+ ASSERT (nchild < nn) ;
+ }
+ AMD_DEBUG1 (("\n")) ;
+ parent = Parent [j] ;
+ if (parent != EMPTY)
+ {
+ ASSERT (Nv [parent] > 0) ;
+ }
+ nels++ ;
+ }
+ }
+ }
+ AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n"
+ "the biggest child last in each list:\n")) ;
+#endif
+
+ /* --------------------------------------------------------------------- */
+ /* place the largest child last in the list of children for each node */
+ /* --------------------------------------------------------------------- */
+
+ for (i = 0 ; i < nn ; i++)
+ {
+ if (Nv [i] > 0 && Child [i] != EMPTY)
+ {
+
+#ifndef NDEBUG
+ Int nchild ;
+ AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ;
+ nchild = 0 ;
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ ASSERT (f >= 0 && f < nn) ;
+ AMD_DEBUG1 ((" f: "ID" size: "ID"\n", f, Fsize [f])) ;
+ nchild++ ;
+ ASSERT (nchild <= nn) ;
+ }
+#endif
+
+ /* find the biggest element in the child list */
+ fprev = EMPTY ;
+ maxfrsize = EMPTY ;
+ bigfprev = EMPTY ;
+ bigf = EMPTY ;
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ ASSERT (f >= 0 && f < nn) ;
+ frsize = Fsize [f] ;
+ if (frsize >= maxfrsize)
+ {
+ /* this is the biggest seen so far */
+ maxfrsize = frsize ;
+ bigfprev = fprev ;
+ bigf = f ;
+ }
+ fprev = f ;
+ }
+ ASSERT (bigf != EMPTY) ;
+
+ fnext = Sibling [bigf] ;
+
+ AMD_DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID
+ " fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ;
+
+ if (fnext != EMPTY)
+ {
+ /* if fnext is EMPTY then bigf is already at the end of list */
+
+ if (bigfprev == EMPTY)
+ {
+ /* delete bigf from the element of the list */
+ Child [i] = fnext ;
+ }
+ else
+ {
+ /* delete bigf from the middle of the list */
+ Sibling [bigfprev] = fnext ;
+ }
+
+ /* put bigf at the end of the list */
+ Sibling [bigf] = EMPTY ;
+ ASSERT (Child [i] != EMPTY) ;
+ ASSERT (fprev != bigf) ;
+ ASSERT (fprev != EMPTY) ;
+ Sibling [fprev] = bigf ;
+ }
+
+#ifndef NDEBUG
+ AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ;
+ for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+ {
+ ASSERT (f >= 0 && f < nn) ;
+ AMD_DEBUG1 ((" "ID" "ID"\n", f, Fsize [f])) ;
+ ASSERT (Nv [f] > 0) ;
+ nchild-- ;
+ }
+ ASSERT (nchild == 0) ;
+#endif
+
+ }
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* postorder the assembly tree */
+ /* --------------------------------------------------------------------- */
+
+ for (i = 0 ; i < nn ; i++)
+ {
+ Order [i] = EMPTY ;
+ }
+
+ k = 0 ;
+
+ for (i = 0 ; i < nn ; i++)
+ {
+ if (Parent [i] == EMPTY && Nv [i] > 0)
+ {
+ AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ;
+ k = AMD_post_tree (i, k, Child, Sibling, Order, Stack
+#ifndef NDEBUG
+ , nn
+#endif
+ ) ;
+ }
+ }
+}
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_preprocess.c b/test/monniaux/glpk-4.65/src/amd/amd_preprocess.c
new file mode 100644
index 00000000..fc223fb5
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_preprocess.c
@@ -0,0 +1,119 @@
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of
+ * a column-form matrix A, to obtain the matrix R. The input matrix can have
+ * duplicate entries and/or unsorted columns (AMD_valid (n,Ap,Ai) must not be
+ * AMD_INVALID).
+ *
+ * This input condition is NOT checked. This routine is not user-callable.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* AMD_preprocess does not check its input for errors or allocate workspace.
+ * On input, the condition (AMD_valid (n,n,Ap,Ai) != AMD_INVALID) must hold.
+ */
+
+GLOBAL void AMD_preprocess
+(
+ Int n, /* input matrix: A is n-by-n */
+ const Int Ap [ ], /* size n+1 */
+ const Int Ai [ ], /* size nz = Ap [n] */
+
+ /* output matrix R: */
+ Int Rp [ ], /* size n+1 */
+ Int Ri [ ], /* size nz (or less, if duplicates present) */
+
+ Int W [ ], /* workspace of size n */
+ Int Flag [ ] /* workspace of size n */
+)
+{
+
+ /* --------------------------------------------------------------------- */
+ /* local variables */
+ /* --------------------------------------------------------------------- */
+
+ Int i, j, p, p2 ;
+
+ ASSERT (AMD_valid (n, n, Ap, Ai) != AMD_INVALID) ;
+
+ /* --------------------------------------------------------------------- */
+ /* count the entries in each row of A (excluding duplicates) */
+ /* --------------------------------------------------------------------- */
+
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = 0 ; /* # of nonzeros in row i (excl duplicates) */
+ Flag [i] = EMPTY ; /* Flag [i] = j if i appears in column j */
+ }
+ for (j = 0 ; j < n ; j++)
+ {
+ p2 = Ap [j+1] ;
+ for (p = Ap [j] ; p < p2 ; p++)
+ {
+ i = Ai [p] ;
+ if (Flag [i] != j)
+ {
+ /* row index i has not yet appeared in column j */
+ W [i]++ ; /* one more entry in row i */
+ Flag [i] = j ; /* flag row index i as appearing in col j*/
+ }
+ }
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* compute the row pointers for R */
+ /* --------------------------------------------------------------------- */
+
+ Rp [0] = 0 ;
+ for (i = 0 ; i < n ; i++)
+ {
+ Rp [i+1] = Rp [i] + W [i] ;
+ }
+ for (i = 0 ; i < n ; i++)
+ {
+ W [i] = Rp [i] ;
+ Flag [i] = EMPTY ;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* construct the row form matrix R */
+ /* --------------------------------------------------------------------- */
+
+ /* R = row form of pattern of A */
+ for (j = 0 ; j < n ; j++)
+ {
+ p2 = Ap [j+1] ;
+ for (p = Ap [j] ; p < p2 ; p++)
+ {
+ i = Ai [p] ;
+ if (Flag [i] != j)
+ {
+ /* row index i has not yet appeared in column j */
+ Ri [W [i]++] = j ; /* put col j in row i */
+ Flag [i] = j ; /* flag row index i as appearing in col j*/
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ ASSERT (AMD_valid (n, n, Rp, Ri) == AMD_OK) ;
+ for (j = 0 ; j < n ; j++)
+ {
+ ASSERT (W [j] == Rp [j+1]) ;
+ }
+#endif
+}
diff --git a/test/monniaux/glpk-4.65/src/amd/amd_valid.c b/test/monniaux/glpk-4.65/src/amd/amd_valid.c
new file mode 100644
index 00000000..e9e2e5ab
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/amd/amd_valid.c
@@ -0,0 +1,93 @@
+/* ========================================================================= */
+/* === AMD_valid =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis, */
+/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
+/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
+/* web: http://www.cise.ufl.edu/research/sparse/amd */
+/* ------------------------------------------------------------------------- */
+
+/* Check if a column-form matrix is valid or not. The matrix A is
+ * n_row-by-n_col. The row indices of entries in column j are in
+ * Ai [Ap [j] ... Ap [j+1]-1]. Required conditions are:
+ *
+ * n_row >= 0
+ * n_col >= 0
+ * nz = Ap [n_col] >= 0 number of entries in the matrix
+ * Ap [0] == 0
+ * Ap [j] <= Ap [j+1] for all j in the range 0 to n_col.
+ * Ai [0 ... nz-1] must be in the range 0 to n_row-1.
+ *
+ * If any of the above conditions hold, AMD_INVALID is returned. If the
+ * following condition holds, AMD_OK_BUT_JUMBLED is returned (a warning,
+ * not an error):
+ *
+ * row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending
+ * order, and/or duplicate entries exist.
+ *
+ * Otherwise, AMD_OK is returned.
+ *
+ * In v1.2 and earlier, this function returned TRUE if the matrix was valid
+ * (now returns AMD_OK), or FALSE otherwise (now returns AMD_INVALID or
+ * AMD_OK_BUT_JUMBLED).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_valid
+(
+ /* inputs, not modified on output: */
+ Int n_row, /* A is n_row-by-n_col */
+ Int n_col,
+ const Int Ap [ ], /* column pointers of A, of size n_col+1 */
+ const Int Ai [ ] /* row indices of A, of size nz = Ap [n_col] */
+)
+{
+ Int nz, j, p1, p2, ilast, i, p, result = AMD_OK ;
+
+ if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL)
+ {
+ return (AMD_INVALID) ;
+ }
+ nz = Ap [n_col] ;
+ if (Ap [0] != 0 || nz < 0)
+ {
+ /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
+ AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
+ return (AMD_INVALID) ;
+ }
+ for (j = 0 ; j < n_col ; j++)
+ {
+ p1 = Ap [j] ;
+ p2 = Ap [j+1] ;
+ AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ;
+ if (p1 > p2)
+ {
+ /* column pointers must be ascending */
+ AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
+ return (AMD_INVALID) ;
+ }
+ ilast = EMPTY ;
+ for (p = p1 ; p < p2 ; p++)
+ {
+ i = Ai [p] ;
+ AMD_DEBUG3 (("row: "ID"\n", i)) ;
+ if (i < 0 || i >= n_row)
+ {
+ /* row index out of range */
+ AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i));
+ return (AMD_INVALID) ;
+ }
+ if (i <= ilast)
+ {
+ /* row index unsorted, or duplicate entry present */
+ AMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i));
+ result = AMD_OK_BUT_JUMBLED ;
+ }
+ ilast = i ;
+ }
+ }
+ return (result) ;
+}
diff --git a/test/monniaux/glpk-4.65/src/api/advbas.c b/test/monniaux/glpk-4.65/src/api/advbas.c
new file mode 100644
index 00000000..23067624
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/advbas.c
@@ -0,0 +1,155 @@
+/* advbas.c (construct advanced initial LP basis) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2008-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+#include "triang.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_adv_basis - construct advanced initial LP basis
+*
+* SYNOPSIS
+*
+* void glp_adv_basis(glp_prob *P, int flags);
+*
+* DESCRIPTION
+*
+* The routine glp_adv_basis constructs an advanced initial LP basis
+* for the specified problem object.
+*
+* The parameter flag is reserved for use in the future and should be
+* specified as zero.
+*
+* NOTE
+*
+* The routine glp_adv_basis should be called after the constraint
+* matrix has been scaled (if scaling is used). */
+
+static int mat(void *info, int k, int ind[], double val[])
+{ glp_prob *P = info;
+ int m = P->m;
+ int n = P->n;
+ GLPROW **row = P->row;
+ GLPCOL **col = P->col;
+ GLPAIJ *aij;
+ int i, j, len;
+ if (k > 0)
+ { /* retrieve scaled row of constraint matrix */
+ i = +k;
+ xassert(1 <= i && i <= m);
+ len = 0;
+ if (row[i]->type == GLP_FX)
+ { for (aij = row[i]->ptr; aij != NULL; aij = aij->r_next)
+ { j = aij->col->j;
+ if (col[j]->type != GLP_FX)
+ { len++;
+ ind[len] = j;
+ val[len] = aij->row->rii * aij->val * aij->col->sjj;
+ }
+ }
+ }
+ }
+ else
+ { /* retrieve scaled column of constraint matrix */
+ j = -k;
+ xassert(1 <= j && j <= n);
+ len = 0;
+ if (col[j]->type != GLP_FX)
+ { for (aij = col[j]->ptr; aij != NULL; aij = aij->c_next)
+ { i = aij->row->i;
+ if (row[i]->type == GLP_FX)
+ { len++;
+ ind[len] = i;
+ val[len] = aij->row->rii * aij->val * aij->col->sjj;
+ }
+ }
+ }
+ }
+ return len;
+}
+
+void glp_adv_basis(glp_prob *P, int flags)
+{ int i, j, k, m, n, min_mn, size, *rn, *cn;
+ char *flag;
+ if (flags != 0)
+ xerror("glp_adv_basis: flags = %d; invalid flags\n", flags);
+ m = P->m; /* number of rows */
+ n = P->n; /* number of columns */
+ if (m == 0 || n == 0)
+ { /* trivial case */
+ glp_std_basis(P);
+ goto done;
+ }
+ xprintf("Constructing initial basis...\n");
+ /* allocate working arrays */
+ min_mn = (m < n ? m : n);
+ rn = talloc(1+min_mn, int);
+ cn = talloc(1+min_mn, int);
+ flag = talloc(1+m, char);
+ /* make the basis empty */
+ for (i = 1; i <= m; i++)
+ { flag[i] = 0;
+ glp_set_row_stat(P, i, GLP_NS);
+ }
+ for (j = 1; j <= n; j++)
+ glp_set_col_stat(P, j, GLP_NS);
+ /* find maximal triangular part of the constraint matrix;
+ to prevent including non-fixed rows and fixed columns in the
+ triangular part, such rows and columns are temporarily made
+ empty by the routine mat */
+#if 1 /* FIXME: tolerance */
+ size = triang(m, n, mat, P, 0.001, rn, cn);
+#endif
+ xassert(0 <= size && size <= min_mn);
+ /* include in the basis non-fixed structural variables, whose
+ columns constitute the triangular part */
+ for (k = 1; k <= size; k++)
+ { i = rn[k];
+ xassert(1 <= i && i <= m);
+ flag[i] = 1;
+ j = cn[k];
+ xassert(1 <= j && j <= n);
+ glp_set_col_stat(P, j, GLP_BS);
+ }
+ /* include in the basis appropriate auxiliary variables, whose
+ unity columns preserve triangular form of the basis matrix */
+ for (i = 1; i <= m; i++)
+ { if (flag[i] == 0)
+ { glp_set_row_stat(P, i, GLP_BS);
+ if (P->row[i]->type != GLP_FX)
+ size++;
+ }
+ }
+ /* size of triangular part = (number of rows) - (number of basic
+ fixed auxiliary variables) */
+ xprintf("Size of triangular part is %d\n", size);
+ /* deallocate working arrays */
+ tfree(rn);
+ tfree(cn);
+ tfree(flag);
+done: return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/asnhall.c b/test/monniaux/glpk-4.65/src/api/asnhall.c
new file mode 100644
index 00000000..d7112a10
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/asnhall.c
@@ -0,0 +1,163 @@
+/* asnhall.c (find bipartite matching of maximum cardinality) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+#include "mc21a.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_asnprob_hall - find bipartite matching of maximum cardinality
+*
+* SYNOPSIS
+*
+* int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
+*
+* DESCRIPTION
+*
+* The routine glp_asnprob_hall finds a matching of maximal cardinality
+* in the specified bipartite graph G. It uses a version of the Fortran
+* routine MC21A developed by I.S.Duff [1], which implements Hall's
+* algorithm [2].
+*
+* RETURNS
+*
+* The routine glp_asnprob_hall returns the cardinality of the matching
+* found. However, if the specified graph is incorrect (as detected by
+* the routine glp_check_asnprob), the routine returns negative value.
+*
+* REFERENCES
+*
+* 1. I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
+* Trans. on Math. Softw. 7 (1981), 387-390.
+*
+* 2. M.Hall, "An Algorithm for distinct representatives," Amer. Math.
+* Monthly 63 (1956), 716-717. */
+
+int glp_asnprob_hall(glp_graph *G, int v_set, int a_x)
+{ glp_vertex *v;
+ glp_arc *a;
+ int card, i, k, loc, n, n1, n2, xij;
+ int *num, *icn, *ip, *lenr, *iperm, *pr, *arp, *cv, *out;
+ if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+ xerror("glp_asnprob_hall: v_set = %d; invalid offset\n",
+ v_set);
+ if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
+ xerror("glp_asnprob_hall: a_x = %d; invalid offset\n", a_x);
+ if (glp_check_asnprob(G, v_set))
+ return -1;
+ /* determine the number of vertices in sets R and S and renumber
+ vertices in S which correspond to columns of the matrix; skip
+ all isolated vertices */
+ num = xcalloc(1+G->nv, sizeof(int));
+ n1 = n2 = 0;
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ if (v->in == NULL && v->out != NULL)
+ n1++, num[i] = 0; /* vertex in R */
+ else if (v->in != NULL && v->out == NULL)
+ n2++, num[i] = n2; /* vertex in S */
+ else
+ { xassert(v->in == NULL && v->out == NULL);
+ num[i] = -1; /* isolated vertex */
+ }
+ }
+ /* the matrix must be square, thus, if it has more columns than
+ rows, extra rows will be just empty, and vice versa */
+ n = (n1 >= n2 ? n1 : n2);
+ /* allocate working arrays */
+ icn = xcalloc(1+G->na, sizeof(int));
+ ip = xcalloc(1+n, sizeof(int));
+ lenr = xcalloc(1+n, sizeof(int));
+ iperm = xcalloc(1+n, sizeof(int));
+ pr = xcalloc(1+n, sizeof(int));
+ arp = xcalloc(1+n, sizeof(int));
+ cv = xcalloc(1+n, sizeof(int));
+ out = xcalloc(1+n, sizeof(int));
+ /* build the adjacency matrix of the bipartite graph in row-wise
+ format (rows are vertices in R, columns are vertices in S) */
+ k = 0, loc = 1;
+ for (i = 1; i <= G->nv; i++)
+ { if (num[i] != 0) continue;
+ /* vertex i in R */
+ ip[++k] = loc;
+ v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { xassert(num[a->head->i] != 0);
+ icn[loc++] = num[a->head->i];
+ }
+ lenr[k] = loc - ip[k];
+ }
+ xassert(loc-1 == G->na);
+ /* make all extra rows empty (all extra columns are empty due to
+ the row-wise format used) */
+ for (k++; k <= n; k++)
+ ip[k] = loc, lenr[k] = 0;
+ /* find a row permutation that maximizes the number of non-zeros
+ on the main diagonal */
+ card = mc21a(n, icn, ip, lenr, iperm, pr, arp, cv, out);
+#if 1 /* 18/II-2010 */
+ /* FIXED: if card = n, arp remains clobbered on exit */
+ for (i = 1; i <= n; i++)
+ arp[i] = 0;
+ for (i = 1; i <= card; i++)
+ { k = iperm[i];
+ xassert(1 <= k && k <= n);
+ xassert(arp[k] == 0);
+ arp[k] = i;
+ }
+#endif
+ /* store solution, if necessary */
+ if (a_x < 0) goto skip;
+ k = 0;
+ for (i = 1; i <= G->nv; i++)
+ { if (num[i] != 0) continue;
+ /* vertex i in R */
+ k++;
+ v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { /* arp[k] is the number of matched column or zero */
+ if (arp[k] == num[a->head->i])
+ { xassert(arp[k] != 0);
+ xij = 1;
+ }
+ else
+ xij = 0;
+ memcpy((char *)a->data + a_x, &xij, sizeof(int));
+ }
+ }
+skip: /* free working arrays */
+ xfree(num);
+ xfree(icn);
+ xfree(ip);
+ xfree(lenr);
+ xfree(iperm);
+ xfree(pr);
+ xfree(arp);
+ xfree(cv);
+ xfree(out);
+ return card;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/asnlp.c b/test/monniaux/glpk-4.65/src/api/asnlp.c
new file mode 100644
index 00000000..cfa925d0
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/asnlp.c
@@ -0,0 +1,104 @@
+/* asnlp.c (convert assignment problem to LP) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_asnprob_lp - convert assignment problem to LP
+*
+* SYNOPSIS
+*
+* int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
+* int v_set, int a_cost);
+*
+* DESCRIPTION
+*
+* The routine glp_asnprob_lp builds an LP problem, which corresponds
+* to the assignment problem on the specified graph G.
+*
+* RETURNS
+*
+* If the LP problem has been successfully built, the routine returns
+* zero, otherwise, non-zero. */
+
+int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
+ int v_set, int a_cost)
+{ glp_vertex *v;
+ glp_arc *a;
+ int i, j, ret, ind[1+2];
+ double cost, val[1+2];
+ if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
+ form == GLP_ASN_MMP))
+ xerror("glp_asnprob_lp: form = %d; invalid parameter\n",
+ form);
+ if (!(names == GLP_ON || names == GLP_OFF))
+ xerror("glp_asnprob_lp: names = %d; invalid parameter\n",
+ names);
+ if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+ xerror("glp_asnprob_lp: v_set = %d; invalid offset\n",
+ v_set);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_asnprob_lp: a_cost = %d; invalid offset\n",
+ a_cost);
+ ret = glp_check_asnprob(G, v_set);
+ if (ret != 0) goto done;
+ glp_erase_prob(P);
+ if (names) glp_set_prob_name(P, G->name);
+ glp_set_obj_dir(P, form == GLP_ASN_MIN ? GLP_MIN : GLP_MAX);
+ if (G->nv > 0) glp_add_rows(P, G->nv);
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ if (names) glp_set_row_name(P, i, v->name);
+ glp_set_row_bnds(P, i, form == GLP_ASN_MMP ? GLP_UP : GLP_FX,
+ 1.0, 1.0);
+ }
+ if (G->na > 0) glp_add_cols(P, G->na);
+ for (i = 1, j = 0; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { j++;
+ if (names)
+ { char name[50+1];
+ sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
+ xassert(strlen(name) < sizeof(name));
+ glp_set_col_name(P, j, name);
+ }
+ ind[1] = a->tail->i, val[1] = +1.0;
+ ind[2] = a->head->i, val[2] = +1.0;
+ glp_set_mat_col(P, j, 2, ind, val);
+ glp_set_col_bnds(P, j, GLP_DB, 0.0, 1.0);
+ if (a_cost >= 0)
+ memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+ else
+ cost = 1.0;
+ glp_set_obj_coef(P, j, cost);
+ }
+ }
+ xassert(j == G->na);
+done: return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/asnokalg.c b/test/monniaux/glpk-4.65/src/api/asnokalg.c
new file mode 100644
index 00000000..d55dbac7
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/asnokalg.c
@@ -0,0 +1,154 @@
+/* asnokalg.c (solve assignment problem with out-of-kilter alg.) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+#include "okalg.h"
+
+int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
+ double *sol, int a_x)
+{ /* solve assignment problem with out-of-kilter algorithm */
+ glp_vertex *v;
+ glp_arc *a;
+ int nv, na, i, k, *tail, *head, *low, *cap, *cost, *x, *pi, ret;
+ double temp;
+ if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
+ form == GLP_ASN_MMP))
+ xerror("glp_asnprob_okalg: form = %d; invalid parameter\n",
+ form);
+ if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+ xerror("glp_asnprob_okalg: v_set = %d; invalid offset\n",
+ v_set);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_asnprob_okalg: a_cost = %d; invalid offset\n",
+ a_cost);
+ if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
+ xerror("glp_asnprob_okalg: a_x = %d; invalid offset\n", a_x);
+ if (glp_check_asnprob(G, v_set))
+ return GLP_EDATA;
+ /* nv is the total number of nodes in the resulting network */
+ nv = G->nv + 1;
+ /* na is the total number of arcs in the resulting network */
+ na = G->na + G->nv;
+ /* allocate working arrays */
+ tail = xcalloc(1+na, sizeof(int));
+ head = xcalloc(1+na, sizeof(int));
+ low = xcalloc(1+na, sizeof(int));
+ cap = xcalloc(1+na, sizeof(int));
+ cost = xcalloc(1+na, sizeof(int));
+ x = xcalloc(1+na, sizeof(int));
+ pi = xcalloc(1+nv, sizeof(int));
+ /* construct the resulting network */
+ k = 0;
+ /* (original arcs) */
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { k++;
+ tail[k] = a->tail->i;
+ head[k] = a->head->i;
+ low[k] = 0;
+ cap[k] = 1;
+ if (a_cost >= 0)
+ memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
+ else
+ temp = 1.0;
+ if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ cost[k] = (int)temp;
+ if (form != GLP_ASN_MIN) cost[k] = - cost[k];
+ }
+ }
+ /* (artificial arcs) */
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ k++;
+ if (v->out == NULL)
+ tail[k] = i, head[k] = nv;
+ else if (v->in == NULL)
+ tail[k] = nv, head[k] = i;
+ else
+ xassert(v != v);
+ low[k] = (form == GLP_ASN_MMP ? 0 : 1);
+ cap[k] = 1;
+ cost[k] = 0;
+ }
+ xassert(k == na);
+ /* find minimal-cost circulation in the resulting network */
+ ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
+ switch (ret)
+ { case 0:
+ /* optimal circulation found */
+ ret = 0;
+ break;
+ case 1:
+ /* no feasible circulation exists */
+ ret = GLP_ENOPFS;
+ break;
+ case 2:
+ /* integer overflow occured */
+ ret = GLP_ERANGE;
+ goto done;
+ case 3:
+ /* optimality test failed (logic error) */
+ ret = GLP_EFAIL;
+ goto done;
+ default:
+ xassert(ret != ret);
+ }
+ /* store solution components */
+ /* (objective function = the total cost) */
+ if (sol != NULL)
+ { temp = 0.0;
+ for (k = 1; k <= na; k++)
+ temp += (double)cost[k] * (double)x[k];
+ if (form != GLP_ASN_MIN) temp = - temp;
+ *sol = temp;
+ }
+ /* (arc flows) */
+ if (a_x >= 0)
+ { k = 0;
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { k++;
+ if (ret == 0)
+ xassert(x[k] == 0 || x[k] == 1);
+ memcpy((char *)a->data + a_x, &x[k], sizeof(int));
+ }
+ }
+ }
+done: /* free working arrays */
+ xfree(tail);
+ xfree(head);
+ xfree(low);
+ xfree(cap);
+ xfree(cost);
+ xfree(x);
+ xfree(pi);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/ckasn.c b/test/monniaux/glpk-4.65/src/api/ckasn.c
new file mode 100644
index 00000000..56221a8a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/ckasn.c
@@ -0,0 +1,78 @@
+/* ckasn.c (check correctness of assignment problem data) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_check_asnprob - check correctness of assignment problem data
+*
+* SYNOPSIS
+*
+* int glp_check_asnprob(glp_graph *G, int v_set);
+*
+* RETURNS
+*
+* If the specified assignment problem data are correct, the routine
+* glp_check_asnprob returns zero, otherwise, non-zero. */
+
+int glp_check_asnprob(glp_graph *G, int v_set)
+{ glp_vertex *v;
+ int i, k, ret = 0;
+ if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+ xerror("glp_check_asnprob: v_set = %d; invalid offset\n",
+ v_set);
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ if (v_set >= 0)
+ { memcpy(&k, (char *)v->data + v_set, sizeof(int));
+ if (k == 0)
+ { if (v->in != NULL)
+ { ret = 1;
+ break;
+ }
+ }
+ else if (k == 1)
+ { if (v->out != NULL)
+ { ret = 2;
+ break;
+ }
+ }
+ else
+ { ret = 3;
+ break;
+ }
+ }
+ else
+ { if (v->in != NULL && v->out != NULL)
+ { ret = 4;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/ckcnf.c b/test/monniaux/glpk-4.65/src/api/ckcnf.c
new file mode 100644
index 00000000..0ee47ed9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/ckcnf.c
@@ -0,0 +1,82 @@
+/* ckcnf.c (check for CNF-SAT problem instance) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+int glp_check_cnfsat(glp_prob *P)
+{ /* check for CNF-SAT problem instance */
+ int m = P->m;
+ int n = P->n;
+ GLPROW *row;
+ GLPCOL *col;
+ GLPAIJ *aij;
+ int i, j, neg;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_check_cnfsat: P = %p; invalid problem object\n",
+ P);
+#endif
+ /* check columns */
+ for (j = 1; j <= n; j++)
+ { col = P->col[j];
+ /* the variable should be binary */
+ if (!(col->kind == GLP_IV && col->type == GLP_DB &&
+ col->lb == 0.0 && col->ub == 1.0))
+ return 1;
+ }
+ /* objective function should be zero */
+ if (P->c0 != 0.0)
+ return 2;
+ for (j = 1; j <= n; j++)
+ { col = P->col[j];
+ if (col->coef != 0.0)
+ return 3;
+ }
+ /* check rows */
+ for (i = 1; i <= m; i++)
+ { row = P->row[i];
+ /* the row should be of ">=" type */
+ if (row->type != GLP_LO)
+ return 4;
+ /* check constraint coefficients */
+ neg = 0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { /* the constraint coefficient should be +1 or -1 */
+ if (aij->val == +1.0)
+ ;
+ else if (aij->val == -1.0)
+ neg++;
+ else
+ return 5;
+ }
+ /* the right-hand side should be (1 - neg), where neg is the
+ number of negative constraint coefficients in the row */
+ if (row->lb != (double)(1 - neg))
+ return 6;
+ }
+ /* congratulations; this is CNF-SAT */
+ return 0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/cplex.c b/test/monniaux/glpk-4.65/src/api/cplex.c
new file mode 100644
index 00000000..8403a646
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/cplex.c
@@ -0,0 +1,1283 @@
+/* cplex.c (CPLEX LP format routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "misc.h"
+#include "prob.h"
+
+#define xfprintf glp_format
+
+/***********************************************************************
+* NAME
+*
+* glp_init_cpxcp - initialize CPLEX LP format control parameters
+*
+* SYNOPSIS
+*
+* void glp_init_cpxcp(glp_cpxcp *parm):
+*
+* The routine glp_init_cpxcp initializes control parameters used by
+* the CPLEX LP input/output routines glp_read_lp and glp_write_lp with
+* default values.
+*
+* Default values of the control parameters are stored in the glp_cpxcp
+* structure, which the parameter parm points to. */
+
+void glp_init_cpxcp(glp_cpxcp *parm)
+{ xassert(parm != NULL);
+ return;
+}
+
+static void check_parm(const char *func, const glp_cpxcp *parm)
+{ /* check control parameters */
+ xassert(func != NULL);
+ xassert(parm != NULL);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_read_lp - read problem data in CPLEX LP format
+*
+* SYNOPSIS
+*
+* int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char
+* *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_read_lp reads problem data in CPLEX LP format from
+* a text file.
+*
+* The parameter parm is a pointer to the structure glp_cpxcp, which
+* specifies control parameters used by the routine. If parm is NULL,
+* the routine uses default settings.
+*
+* The character string fname specifies a name of the text file to be
+* read.
+*
+* Note that before reading data the current content of the problem
+* object is completely erased with the routine glp_erase_prob.
+*
+* RETURNS
+*
+* If the operation was successful, the routine glp_read_lp returns
+* zero. Otherwise, it prints an error message and returns non-zero. */
+
+struct csa
+{ /* common storage area */
+ glp_prob *P;
+ /* LP/MIP problem object */
+ const glp_cpxcp *parm;
+ /* pointer to control parameters */
+ const char *fname;
+ /* name of input CPLEX LP file */
+ glp_file *fp;
+ /* stream assigned to input CPLEX LP file */
+ jmp_buf jump;
+ /* label for go to in case of error */
+ int count;
+ /* line count */
+ int c;
+ /* current character or EOF */
+ int token;
+ /* current token: */
+#define T_EOF 0x00 /* end of file */
+#define T_MINIMIZE 0x01 /* keyword 'minimize' */
+#define T_MAXIMIZE 0x02 /* keyword 'maximize' */
+#define T_SUBJECT_TO 0x03 /* keyword 'subject to' */
+#define T_BOUNDS 0x04 /* keyword 'bounds' */
+#define T_GENERAL 0x05 /* keyword 'general' */
+#define T_INTEGER 0x06 /* keyword 'integer' */
+#define T_BINARY 0x07 /* keyword 'binary' */
+#define T_END 0x08 /* keyword 'end' */
+#define T_NAME 0x09 /* symbolic name */
+#define T_NUMBER 0x0A /* numeric constant */
+#define T_PLUS 0x0B /* delimiter '+' */
+#define T_MINUS 0x0C /* delimiter '-' */
+#define T_COLON 0x0D /* delimiter ':' */
+#define T_LE 0x0E /* delimiter '<=' */
+#define T_GE 0x0F /* delimiter '>=' */
+#define T_EQ 0x10 /* delimiter '=' */
+ char image[255+1];
+ /* image of current token */
+ int imlen;
+ /* length of token image */
+ double value;
+ /* value of numeric constant */
+ int n_max;
+ /* length of the following five arrays (enlarged automatically,
+ if necessary) */
+ int *ind; /* int ind[1+n_max]; */
+ double *val; /* double val[1+n_max]; */
+ char *flag; /* char flag[1+n_max]; */
+ /* working arrays used to construct linear forms */
+ double *lb; /* double lb[1+n_max]; */
+ double *ub; /* double ub[1+n_max]; */
+ /* lower and upper bounds of variables (columns) */
+#if 1 /* 27/VII-2013 */
+ int lb_warn, ub_warn;
+ /* warning 'lower/upper bound redefined' already issued */
+#endif
+};
+
+#define CHAR_SET "!\"#$%&()/,.;?@_`'{}|~"
+/* characters that may appear in symbolic names */
+
+static void error(struct csa *csa, const char *fmt, ...)
+{ /* print error message and terminate processing */
+ va_list arg;
+ xprintf("%s:%d: ", csa->fname, csa->count);
+ va_start(arg, fmt);
+ xvprintf(fmt, arg);
+ va_end(arg);
+ longjmp(csa->jump, 1);
+ /* no return */
+}
+
+static void warning(struct csa *csa, const char *fmt, ...)
+{ /* print warning message and continue processing */
+ va_list arg;
+ xprintf("%s:%d: warning: ", csa->fname, csa->count);
+ va_start(arg, fmt);
+ xvprintf(fmt, arg);
+ va_end(arg);
+ return;
+}
+
+static void read_char(struct csa *csa)
+{ /* read next character from input file */
+ int c;
+ xassert(csa->c != EOF);
+ if (csa->c == '\n') csa->count++;
+ c = glp_getc(csa->fp);
+ if (c < 0)
+ { if (glp_ioerr(csa->fp))
+ error(csa, "read error - %s\n", get_err_msg());
+ else if (csa->c == '\n')
+ { csa->count--;
+ c = EOF;
+ }
+ else
+ { warning(csa, "missing final end of line\n");
+ c = '\n';
+ }
+ }
+ else if (c == '\n')
+ ;
+ else if (isspace(c))
+ c = ' ';
+ else if (iscntrl(c))
+ error(csa, "invalid control character 0x%02X\n", c);
+ csa->c = c;
+ return;
+}
+
+static void add_char(struct csa *csa)
+{ /* append current character to current token */
+ if (csa->imlen == sizeof(csa->image)-1)
+ error(csa, "token '%.15s...' too long\n", csa->image);
+ csa->image[csa->imlen++] = (char)csa->c;
+ csa->image[csa->imlen] = '\0';
+ read_char(csa);
+ return;
+}
+
+static int the_same(char *s1, char *s2)
+{ /* compare two character strings ignoring case sensitivity */
+ for (; *s1 != '\0'; s1++, s2++)
+ { if (tolower((unsigned char)*s1) != tolower((unsigned char)*s2))
+ return 0;
+ }
+ return 1;
+}
+
+static void scan_token(struct csa *csa)
+{ /* scan next token */
+ int flag;
+ csa->token = -1;
+ csa->image[0] = '\0';
+ csa->imlen = 0;
+ csa->value = 0.0;
+loop: flag = 0;
+ /* skip non-significant characters */
+ while (csa->c == ' ') read_char(csa);
+ /* recognize and scan current token */
+ if (csa->c == EOF)
+ csa->token = T_EOF;
+ else if (csa->c == '\n')
+ { read_char(csa);
+ /* if the next character is letter, it may begin a keyword */
+ if (isalpha(csa->c))
+ { flag = 1;
+ goto name;
+ }
+ goto loop;
+ }
+ else if (csa->c == '\\')
+ { /* comment; ignore everything until end-of-line */
+ while (csa->c != '\n') read_char(csa);
+ goto loop;
+ }
+ else if (isalpha(csa->c) || csa->c != '.' && strchr(CHAR_SET,
+ csa->c) != NULL)
+name: { /* symbolic name */
+ csa->token = T_NAME;
+ while (isalnum(csa->c) || strchr(CHAR_SET, csa->c) != NULL)
+ add_char(csa);
+ if (flag)
+ { /* check for keyword */
+ if (the_same(csa->image, "minimize"))
+ csa->token = T_MINIMIZE;
+ else if (the_same(csa->image, "minimum"))
+ csa->token = T_MINIMIZE;
+ else if (the_same(csa->image, "min"))
+ csa->token = T_MINIMIZE;
+ else if (the_same(csa->image, "maximize"))
+ csa->token = T_MAXIMIZE;
+ else if (the_same(csa->image, "maximum"))
+ csa->token = T_MAXIMIZE;
+ else if (the_same(csa->image, "max"))
+ csa->token = T_MAXIMIZE;
+ else if (the_same(csa->image, "subject"))
+ { if (csa->c == ' ')
+ { read_char(csa);
+ if (tolower(csa->c) == 't')
+ { csa->token = T_SUBJECT_TO;
+ csa->image[csa->imlen++] = ' ';
+ csa->image[csa->imlen] = '\0';
+ add_char(csa);
+ if (tolower(csa->c) != 'o')
+ error(csa, "keyword 'subject to' incomplete\n");
+ add_char(csa);
+ if (isalpha(csa->c))
+ error(csa, "keyword '%s%c...' not recognized\n",
+ csa->image, csa->c);
+ }
+ }
+ }
+ else if (the_same(csa->image, "such"))
+ { if (csa->c == ' ')
+ { read_char(csa);
+ if (tolower(csa->c) == 't')
+ { csa->token = T_SUBJECT_TO;
+ csa->image[csa->imlen++] = ' ';
+ csa->image[csa->imlen] = '\0';
+ add_char(csa);
+ if (tolower(csa->c) != 'h')
+err: error(csa, "keyword 'such that' incomplete\n");
+ add_char(csa);
+ if (tolower(csa->c) != 'a') goto err;
+ add_char(csa);
+ if (tolower(csa->c) != 't') goto err;
+ add_char(csa);
+ if (isalpha(csa->c))
+ error(csa, "keyword '%s%c...' not recognized\n",
+ csa->image, csa->c);
+ }
+ }
+ }
+ else if (the_same(csa->image, "st"))
+ csa->token = T_SUBJECT_TO;
+ else if (the_same(csa->image, "s.t."))
+ csa->token = T_SUBJECT_TO;
+ else if (the_same(csa->image, "st."))
+ csa->token = T_SUBJECT_TO;
+ else if (the_same(csa->image, "bounds"))
+ csa->token = T_BOUNDS;
+ else if (the_same(csa->image, "bound"))
+ csa->token = T_BOUNDS;
+ else if (the_same(csa->image, "general"))
+ csa->token = T_GENERAL;
+ else if (the_same(csa->image, "generals"))
+ csa->token = T_GENERAL;
+ else if (the_same(csa->image, "gen"))
+ csa->token = T_GENERAL;
+ else if (the_same(csa->image, "integer"))
+ csa->token = T_INTEGER;
+ else if (the_same(csa->image, "integers"))
+ csa->token = T_INTEGER;
+ else if (the_same(csa->image, "int"))
+ csa->token = T_INTEGER;
+ else if (the_same(csa->image, "binary"))
+ csa->token = T_BINARY;
+ else if (the_same(csa->image, "binaries"))
+ csa->token = T_BINARY;
+ else if (the_same(csa->image, "bin"))
+ csa->token = T_BINARY;
+ else if (the_same(csa->image, "end"))
+ csa->token = T_END;
+ }
+ }
+ else if (isdigit(csa->c) || csa->c == '.')
+ { /* numeric constant */
+ csa->token = T_NUMBER;
+ /* scan integer part */
+ while (isdigit(csa->c)) add_char(csa);
+ /* scan optional fractional part (it is mandatory, if there is
+ no integer part) */
+ if (csa->c == '.')
+ { add_char(csa);
+ if (csa->imlen == 1 && !isdigit(csa->c))
+ error(csa, "invalid use of decimal point\n");
+ while (isdigit(csa->c)) add_char(csa);
+ }
+ /* scan optional decimal exponent */
+ if (csa->c == 'e' || csa->c == 'E')
+ { add_char(csa);
+ if (csa->c == '+' || csa->c == '-') add_char(csa);
+ if (!isdigit(csa->c))
+ error(csa, "numeric constant '%s' incomplete\n",
+ csa->image);
+ while (isdigit(csa->c)) add_char(csa);
+ }
+ /* convert the numeric constant to floating-point */
+ if (str2num(csa->image, &csa->value))
+ error(csa, "numeric constant '%s' out of range\n",
+ csa->image);
+ }
+ else if (csa->c == '+')
+ csa->token = T_PLUS, add_char(csa);
+ else if (csa->c == '-')
+ csa->token = T_MINUS, add_char(csa);
+ else if (csa->c == ':')
+ csa->token = T_COLON, add_char(csa);
+ else if (csa->c == '<')
+ { csa->token = T_LE, add_char(csa);
+ if (csa->c == '=') add_char(csa);
+ }
+ else if (csa->c == '>')
+ { csa->token = T_GE, add_char(csa);
+ if (csa->c == '=') add_char(csa);
+ }
+ else if (csa->c == '=')
+ { csa->token = T_EQ, add_char(csa);
+ if (csa->c == '<')
+ csa->token = T_LE, add_char(csa);
+ else if (csa->c == '>')
+ csa->token = T_GE, add_char(csa);
+ }
+ else
+ error(csa, "character '%c' not recognized\n", csa->c);
+ /* skip non-significant characters */
+ while (csa->c == ' ') read_char(csa);
+ return;
+}
+
+static int find_col(struct csa *csa, char *name)
+{ /* find column by its symbolic name */
+ int j;
+ j = glp_find_col(csa->P, name);
+ if (j == 0)
+ { /* not found; create new column */
+ j = glp_add_cols(csa->P, 1);
+ glp_set_col_name(csa->P, j, name);
+ /* enlarge working arrays, if necessary */
+ if (csa->n_max < j)
+ { int n_max = csa->n_max;
+ int *ind = csa->ind;
+ double *val = csa->val;
+ char *flag = csa->flag;
+ double *lb = csa->lb;
+ double *ub = csa->ub;
+ csa->n_max += csa->n_max;
+ csa->ind = xcalloc(1+csa->n_max, sizeof(int));
+ memcpy(&csa->ind[1], &ind[1], n_max * sizeof(int));
+ xfree(ind);
+ csa->val = xcalloc(1+csa->n_max, sizeof(double));
+ memcpy(&csa->val[1], &val[1], n_max * sizeof(double));
+ xfree(val);
+ csa->flag = xcalloc(1+csa->n_max, sizeof(char));
+ memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
+ memcpy(&csa->flag[1], &flag[1], n_max * sizeof(char));
+ xfree(flag);
+ csa->lb = xcalloc(1+csa->n_max, sizeof(double));
+ memcpy(&csa->lb[1], &lb[1], n_max * sizeof(double));
+ xfree(lb);
+ csa->ub = xcalloc(1+csa->n_max, sizeof(double));
+ memcpy(&csa->ub[1], &ub[1], n_max * sizeof(double));
+ xfree(ub);
+ }
+ csa->lb[j] = +DBL_MAX, csa->ub[j] = -DBL_MAX;
+ }
+ return j;
+}
+
+/***********************************************************************
+* parse_linear_form - parse linear form
+*
+* This routine parses the linear form using the following syntax:
+*
+* <variable> ::= <symbolic name>
+* <coefficient> ::= <numeric constant>
+* <term> ::= <variable> | <numeric constant> <variable>
+* <linear form> ::= <term> | + <term> | - <term> |
+* <linear form> + <term> | <linear form> - <term>
+*
+* The routine returns the number of terms in the linear form. */
+
+static int parse_linear_form(struct csa *csa)
+{ int j, k, len = 0, newlen;
+ double s, coef;
+loop: /* parse an optional sign */
+ if (csa->token == T_PLUS)
+ s = +1.0, scan_token(csa);
+ else if (csa->token == T_MINUS)
+ s = -1.0, scan_token(csa);
+ else
+ s = +1.0;
+ /* parse an optional coefficient */
+ if (csa->token == T_NUMBER)
+ coef = csa->value, scan_token(csa);
+ else
+ coef = 1.0;
+ /* parse a variable name */
+ if (csa->token != T_NAME)
+ error(csa, "missing variable name\n");
+ /* find the corresponding column */
+ j = find_col(csa, csa->image);
+ /* check if the variable is already used in the linear form */
+ if (csa->flag[j])
+ error(csa, "multiple use of variable '%s' not allowed\n",
+ csa->image);
+ /* add new term to the linear form */
+ len++, csa->ind[len] = j, csa->val[len] = s * coef;
+ /* and mark that the variable is used in the linear form */
+ csa->flag[j] = 1;
+ scan_token(csa);
+ /* if the next token is a sign, there is another term */
+ if (csa->token == T_PLUS || csa->token == T_MINUS) goto loop;
+ /* clear marks of the variables used in the linear form */
+ for (k = 1; k <= len; k++) csa->flag[csa->ind[k]] = 0;
+ /* remove zero coefficients */
+ newlen = 0;
+ for (k = 1; k <= len; k++)
+ { if (csa->val[k] != 0.0)
+ { newlen++;
+ csa->ind[newlen] = csa->ind[k];
+ csa->val[newlen] = csa->val[k];
+ }
+ }
+ return newlen;
+}
+
+/***********************************************************************
+* parse_objective - parse objective function
+*
+* This routine parses definition of the objective function using the
+* following syntax:
+*
+* <obj sense> ::= minimize | minimum | min | maximize | maximum | max
+* <obj name> ::= <empty> | <symbolic name> :
+* <obj function> ::= <obj sense> <obj name> <linear form> */
+
+static void parse_objective(struct csa *csa)
+{ /* parse objective sense */
+ int k, len;
+ /* parse the keyword 'minimize' or 'maximize' */
+ if (csa->token == T_MINIMIZE)
+ glp_set_obj_dir(csa->P, GLP_MIN);
+ else if (csa->token == T_MAXIMIZE)
+ glp_set_obj_dir(csa->P, GLP_MAX);
+ else
+ xassert(csa != csa);
+ scan_token(csa);
+ /* parse objective name */
+ if (csa->token == T_NAME && csa->c == ':')
+ { /* objective name is followed by a colon */
+ glp_set_obj_name(csa->P, csa->image);
+ scan_token(csa);
+ xassert(csa->token == T_COLON);
+ scan_token(csa);
+ }
+ else
+ { /* objective name is not specified; use default */
+ glp_set_obj_name(csa->P, "obj");
+ }
+ /* parse linear form */
+ len = parse_linear_form(csa);
+ for (k = 1; k <= len; k++)
+ glp_set_obj_coef(csa->P, csa->ind[k], csa->val[k]);
+ return;
+}
+
+/***********************************************************************
+* parse_constraints - parse constraints section
+*
+* This routine parses the constraints section using the following
+* syntax:
+*
+* <row name> ::= <empty> | <symbolic name> :
+* <row sense> ::= < | <= | =< | > | >= | => | =
+* <right-hand side> ::= <numeric constant> | + <numeric constant> |
+* - <numeric constant>
+* <constraint> ::= <row name> <linear form> <row sense>
+* <right-hand side>
+* <subject to> ::= subject to | such that | st | s.t. | st.
+* <constraints section> ::= <subject to> <constraint> |
+* <constraints section> <constraint> */
+
+static void parse_constraints(struct csa *csa)
+{ int i, len, type;
+ double s;
+ /* parse the keyword 'subject to' */
+ xassert(csa->token == T_SUBJECT_TO);
+ scan_token(csa);
+loop: /* create new row (constraint) */
+ i = glp_add_rows(csa->P, 1);
+ /* parse row name */
+ if (csa->token == T_NAME && csa->c == ':')
+ { /* row name is followed by a colon */
+ if (glp_find_row(csa->P, csa->image) != 0)
+ error(csa, "constraint '%s' multiply defined\n",
+ csa->image);
+ glp_set_row_name(csa->P, i, csa->image);
+ scan_token(csa);
+ xassert(csa->token == T_COLON);
+ scan_token(csa);
+ }
+ else
+ { /* row name is not specified; use default */
+ char name[50];
+ sprintf(name, "r.%d", csa->count);
+ glp_set_row_name(csa->P, i, name);
+ }
+ /* parse linear form */
+ len = parse_linear_form(csa);
+ glp_set_mat_row(csa->P, i, len, csa->ind, csa->val);
+ /* parse constraint sense */
+ if (csa->token == T_LE)
+ type = GLP_UP, scan_token(csa);
+ else if (csa->token == T_GE)
+ type = GLP_LO, scan_token(csa);
+ else if (csa->token == T_EQ)
+ type = GLP_FX, scan_token(csa);
+ else
+ error(csa, "missing constraint sense\n");
+ /* parse right-hand side */
+ if (csa->token == T_PLUS)
+ s = +1.0, scan_token(csa);
+ else if (csa->token == T_MINUS)
+ s = -1.0, scan_token(csa);
+ else
+ s = +1.0;
+ if (csa->token != T_NUMBER)
+ error(csa, "missing right-hand side\n");
+ glp_set_row_bnds(csa->P, i, type, s * csa->value, s * csa->value);
+ /* the rest of the current line must be empty */
+ if (!(csa->c == '\n' || csa->c == EOF))
+ error(csa, "invalid symbol(s) beyond right-hand side\n");
+ scan_token(csa);
+ /* if the next token is a sign, numeric constant, or a symbolic
+ name, here is another constraint */
+ if (csa->token == T_PLUS || csa->token == T_MINUS ||
+ csa->token == T_NUMBER || csa->token == T_NAME) goto loop;
+ return;
+}
+
+static void set_lower_bound(struct csa *csa, int j, double lb)
+{ /* set lower bound of j-th variable */
+ if (csa->lb[j] != +DBL_MAX && !csa->lb_warn)
+ { warning(csa, "lower bound of variable '%s' redefined\n",
+ glp_get_col_name(csa->P, j));
+ csa->lb_warn = 1;
+ }
+ csa->lb[j] = lb;
+ return;
+}
+
+static void set_upper_bound(struct csa *csa, int j, double ub)
+{ /* set upper bound of j-th variable */
+ if (csa->ub[j] != -DBL_MAX && !csa->ub_warn)
+ { warning(csa, "upper bound of variable '%s' redefined\n",
+ glp_get_col_name(csa->P, j));
+ csa->ub_warn = 1;
+ }
+ csa->ub[j] = ub;
+ return;
+}
+
+/***********************************************************************
+* parse_bounds - parse bounds section
+*
+* This routine parses the bounds section using the following syntax:
+*
+* <variable> ::= <symbolic name>
+* <infinity> ::= infinity | inf
+* <bound> ::= <numeric constant> | + <numeric constant> |
+* - <numeric constant> | + <infinity> | - <infinity>
+* <lt> ::= < | <= | =<
+* <gt> ::= > | >= | =>
+* <bound definition> ::= <bound> <lt> <variable> <lt> <bound> |
+* <bound> <lt> <variable> | <variable> <lt> <bound> |
+* <variable> <gt> <bound> | <variable> = <bound> | <variable> free
+* <bounds> ::= bounds | bound
+* <bounds section> ::= <bounds> |
+* <bounds section> <bound definition> */
+
+static void parse_bounds(struct csa *csa)
+{ int j, lb_flag;
+ double lb, s;
+ /* parse the keyword 'bounds' */
+ xassert(csa->token == T_BOUNDS);
+ scan_token(csa);
+loop: /* bound definition can start with a sign, numeric constant, or
+ a symbolic name */
+ if (!(csa->token == T_PLUS || csa->token == T_MINUS ||
+ csa->token == T_NUMBER || csa->token == T_NAME)) goto done;
+ /* parse bound definition */
+ if (csa->token == T_PLUS || csa->token == T_MINUS)
+ { /* parse signed lower bound */
+ lb_flag = 1;
+ s = (csa->token == T_PLUS ? +1.0 : -1.0);
+ scan_token(csa);
+ if (csa->token == T_NUMBER)
+ lb = s * csa->value, scan_token(csa);
+ else if (the_same(csa->image, "infinity") ||
+ the_same(csa->image, "inf"))
+ { if (s > 0.0)
+ error(csa, "invalid use of '+inf' as lower bound\n");
+ lb = -DBL_MAX, scan_token(csa);
+ }
+ else
+ error(csa, "missing lower bound\n");
+ }
+ else if (csa->token == T_NUMBER)
+ { /* parse unsigned lower bound */
+ lb_flag = 1;
+ lb = csa->value, scan_token(csa);
+ }
+ else
+ { /* lower bound is not specified */
+ lb_flag = 0;
+ }
+ /* parse the token that should follow the lower bound */
+ if (lb_flag)
+ { if (csa->token != T_LE)
+ error(csa, "missing '<', '<=', or '=<' after lower bound\n")
+ ;
+ scan_token(csa);
+ }
+ /* parse variable name */
+ if (csa->token != T_NAME)
+ error(csa, "missing variable name\n");
+ j = find_col(csa, csa->image);
+ /* set lower bound */
+ if (lb_flag) set_lower_bound(csa, j, lb);
+ scan_token(csa);
+ /* parse the context that follows the variable name */
+ if (csa->token == T_LE)
+ { /* parse upper bound */
+ scan_token(csa);
+ if (csa->token == T_PLUS || csa->token == T_MINUS)
+ { /* parse signed upper bound */
+ s = (csa->token == T_PLUS ? +1.0 : -1.0);
+ scan_token(csa);
+ if (csa->token == T_NUMBER)
+ { set_upper_bound(csa, j, s * csa->value);
+ scan_token(csa);
+ }
+ else if (the_same(csa->image, "infinity") ||
+ the_same(csa->image, "inf"))
+ { if (s < 0.0)
+ error(csa, "invalid use of '-inf' as upper bound\n");
+ set_upper_bound(csa, j, +DBL_MAX);
+ scan_token(csa);
+ }
+ else
+ error(csa, "missing upper bound\n");
+ }
+ else if (csa->token == T_NUMBER)
+ { /* parse unsigned upper bound */
+ set_upper_bound(csa, j, csa->value);
+ scan_token(csa);
+ }
+ else
+ error(csa, "missing upper bound\n");
+ }
+ else if (csa->token == T_GE)
+ { /* parse lower bound */
+ if (lb_flag)
+ { /* the context '... <= x >= ...' is invalid */
+ error(csa, "invalid bound definition\n");
+ }
+ scan_token(csa);
+ if (csa->token == T_PLUS || csa->token == T_MINUS)
+ { /* parse signed lower bound */
+ s = (csa->token == T_PLUS ? +1.0 : -1.0);
+ scan_token(csa);
+ if (csa->token == T_NUMBER)
+ { set_lower_bound(csa, j, s * csa->value);
+ scan_token(csa);
+ }
+ else if (the_same(csa->image, "infinity") ||
+ the_same(csa->image, "inf") == 0)
+ { if (s > 0.0)
+ error(csa, "invalid use of '+inf' as lower bound\n");
+ set_lower_bound(csa, j, -DBL_MAX);
+ scan_token(csa);
+ }
+ else
+ error(csa, "missing lower bound\n");
+ }
+ else if (csa->token == T_NUMBER)
+ { /* parse unsigned lower bound */
+ set_lower_bound(csa, j, csa->value);
+ scan_token(csa);
+ }
+ else
+ error(csa, "missing lower bound\n");
+ }
+ else if (csa->token == T_EQ)
+ { /* parse fixed value */
+ if (lb_flag)
+ { /* the context '... <= x = ...' is invalid */
+ error(csa, "invalid bound definition\n");
+ }
+ scan_token(csa);
+ if (csa->token == T_PLUS || csa->token == T_MINUS)
+ { /* parse signed fixed value */
+ s = (csa->token == T_PLUS ? +1.0 : -1.0);
+ scan_token(csa);
+ if (csa->token == T_NUMBER)
+ { set_lower_bound(csa, j, s * csa->value);
+ set_upper_bound(csa, j, s * csa->value);
+ scan_token(csa);
+ }
+ else
+ error(csa, "missing fixed value\n");
+ }
+ else if (csa->token == T_NUMBER)
+ { /* parse unsigned fixed value */
+ set_lower_bound(csa, j, csa->value);
+ set_upper_bound(csa, j, csa->value);
+ scan_token(csa);
+ }
+ else
+ error(csa, "missing fixed value\n");
+ }
+ else if (the_same(csa->image, "free"))
+ { /* parse the keyword 'free' */
+ if (lb_flag)
+ { /* the context '... <= x free ...' is invalid */
+ error(csa, "invalid bound definition\n");
+ }
+ set_lower_bound(csa, j, -DBL_MAX);
+ set_upper_bound(csa, j, +DBL_MAX);
+ scan_token(csa);
+ }
+ else if (!lb_flag)
+ { /* neither lower nor upper bounds are specified */
+ error(csa, "invalid bound definition\n");
+ }
+ goto loop;
+done: return;
+}
+
+/***********************************************************************
+* parse_integer - parse general, integer, or binary section
+*
+* <variable> ::= <symbolic name>
+* <general> ::= general | generals | gen
+* <integer> ::= integer | integers | int
+* <binary> ::= binary | binaries | bin
+* <section head> ::= <general> <integer> <binary>
+* <additional section> ::= <section head> |
+* <additional section> <variable> */
+
+static void parse_integer(struct csa *csa)
+{ int j, binary;
+ /* parse the keyword 'general', 'integer', or 'binary' */
+ if (csa->token == T_GENERAL)
+ binary = 0, scan_token(csa);
+ else if (csa->token == T_INTEGER)
+ binary = 0, scan_token(csa);
+ else if (csa->token == T_BINARY)
+ binary = 1, scan_token(csa);
+ else
+ xassert(csa != csa);
+ /* parse list of variables (may be empty) */
+ while (csa->token == T_NAME)
+ { /* find the corresponding column */
+ j = find_col(csa, csa->image);
+ /* change kind of the variable */
+ glp_set_col_kind(csa->P, j, GLP_IV);
+ /* set bounds for the binary variable */
+ if (binary)
+#if 0 /* 07/VIII-2013 */
+ { set_lower_bound(csa, j, 0.0);
+ set_upper_bound(csa, j, 1.0);
+ }
+#else
+ { set_lower_bound(csa, j,
+ csa->lb[j] == +DBL_MAX ? 0.0 : csa->lb[j]);
+ set_upper_bound(csa, j,
+ csa->ub[j] == -DBL_MAX ? 1.0 : csa->ub[j]);
+ }
+#endif
+ scan_token(csa);
+ }
+ return;
+}
+
+int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
+{ /* read problem data in CPLEX LP format */
+ glp_cpxcp _parm;
+ struct csa _csa, *csa = &_csa;
+ int ret;
+ xprintf("Reading problem data from '%s'...\n", fname);
+ if (parm == NULL)
+ glp_init_cpxcp(&_parm), parm = &_parm;
+ /* check control parameters */
+ check_parm("glp_read_lp", parm);
+ /* initialize common storage area */
+ csa->P = P;
+ csa->parm = parm;
+ csa->fname = fname;
+ csa->fp = NULL;
+ if (setjmp(csa->jump))
+ { ret = 1;
+ goto done;
+ }
+ csa->count = 0;
+ csa->c = '\n';
+ csa->token = T_EOF;
+ csa->image[0] = '\0';
+ csa->imlen = 0;
+ csa->value = 0.0;
+ csa->n_max = 100;
+ csa->ind = xcalloc(1+csa->n_max, sizeof(int));
+ csa->val = xcalloc(1+csa->n_max, sizeof(double));
+ csa->flag = xcalloc(1+csa->n_max, sizeof(char));
+ memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
+ csa->lb = xcalloc(1+csa->n_max, sizeof(double));
+ csa->ub = xcalloc(1+csa->n_max, sizeof(double));
+#if 1 /* 27/VII-2013 */
+ csa->lb_warn = csa->ub_warn = 0;
+#endif
+ /* erase problem object */
+ glp_erase_prob(P);
+ glp_create_index(P);
+ /* open input CPLEX LP file */
+ csa->fp = glp_open(fname, "r");
+ if (csa->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ /* scan very first token */
+ scan_token(csa);
+ /* parse definition of the objective function */
+ if (!(csa->token == T_MINIMIZE || csa->token == T_MAXIMIZE))
+ error(csa, "'minimize' or 'maximize' keyword missing\n");
+ parse_objective(csa);
+ /* parse constraints section */
+ if (csa->token != T_SUBJECT_TO)
+ error(csa, "constraints section missing\n");
+ parse_constraints(csa);
+ /* parse optional bounds section */
+ if (csa->token == T_BOUNDS) parse_bounds(csa);
+ /* parse optional general, integer, and binary sections */
+ while (csa->token == T_GENERAL ||
+ csa->token == T_INTEGER ||
+ csa->token == T_BINARY) parse_integer(csa);
+ /* check for the keyword 'end' */
+ if (csa->token == T_END)
+ scan_token(csa);
+ else if (csa->token == T_EOF)
+ warning(csa, "keyword 'end' missing\n");
+ else
+ error(csa, "symbol '%s' in wrong position\n", csa->image);
+ /* nothing must follow the keyword 'end' (except comments) */
+ if (csa->token != T_EOF)
+ error(csa, "extra symbol(s) detected beyond 'end'\n");
+ /* set bounds of variables */
+ { int j, type;
+ double lb, ub;
+ for (j = 1; j <= P->n; j++)
+ { lb = csa->lb[j];
+ ub = csa->ub[j];
+ if (lb == +DBL_MAX) lb = 0.0; /* default lb */
+ if (ub == -DBL_MAX) ub = +DBL_MAX; /* default ub */
+ if (lb == -DBL_MAX && ub == +DBL_MAX)
+ type = GLP_FR;
+ else if (ub == +DBL_MAX)
+ type = GLP_LO;
+ else if (lb == -DBL_MAX)
+ type = GLP_UP;
+ else if (lb != ub)
+ type = GLP_DB;
+ else
+ type = GLP_FX;
+ glp_set_col_bnds(csa->P, j, type, lb, ub);
+ }
+ }
+ /* print some statistics */
+ xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+ P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+ P->nnz, P->nnz == 1 ? "" : "s");
+ if (glp_get_num_int(P) > 0)
+ { int ni = glp_get_num_int(P);
+ int nb = glp_get_num_bin(P);
+ if (ni == 1)
+ { if (nb == 0)
+ xprintf("One variable is integer\n");
+ else
+ xprintf("One variable is binary\n");
+ }
+ else
+ { xprintf("%d integer variables, ", ni);
+ if (nb == 0)
+ xprintf("none");
+ else if (nb == 1)
+ xprintf("one");
+ else if (nb == ni)
+ xprintf("all");
+ else
+ xprintf("%d", nb);
+ xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
+ }
+ }
+ xprintf("%d lines were read\n", csa->count);
+ /* problem data has been successfully read */
+ glp_delete_index(P);
+ glp_sort_matrix(P);
+ ret = 0;
+done: if (csa->fp != NULL) glp_close(csa->fp);
+ xfree(csa->ind);
+ xfree(csa->val);
+ xfree(csa->flag);
+ xfree(csa->lb);
+ xfree(csa->ub);
+ if (ret != 0) glp_erase_prob(P);
+ return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_write_lp - write problem data in CPLEX LP format
+*
+* SYNOPSIS
+*
+* int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char
+* *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_write_lp writes problem data in CPLEX LP format to
+* a text file.
+*
+* The parameter parm is a pointer to the structure glp_cpxcp, which
+* specifies control parameters used by the routine. If parm is NULL,
+* the routine uses default settings.
+*
+* The character string fname specifies a name of the text file to be
+* written.
+*
+* RETURNS
+*
+* If the operation was successful, the routine glp_write_lp returns
+* zero. Otherwise, it prints an error message and returns non-zero. */
+
+#define csa csa1
+
+struct csa
+{ /* common storage area */
+ glp_prob *P;
+ /* pointer to problem object */
+ const glp_cpxcp *parm;
+ /* pointer to control parameters */
+};
+
+static int check_name(char *name)
+{ /* check if specified name is valid for CPLEX LP format */
+ if (*name == '.') return 1;
+ if (isdigit((unsigned char)*name)) return 1;
+ for (; *name; name++)
+ { if (!isalnum((unsigned char)*name) &&
+ strchr(CHAR_SET, (unsigned char)*name) == NULL) return 1;
+ }
+ return 0; /* name is ok */
+}
+
+static void adjust_name(char *name)
+{ /* attempt to adjust specified name to make it valid for CPLEX LP
+ format */
+ for (; *name; name++)
+ { if (*name == ' ')
+ *name = '_';
+ else if (*name == '-')
+ *name = '~';
+ else if (*name == '[')
+ *name = '(';
+ else if (*name == ']')
+ *name = ')';
+ }
+ return;
+}
+
+static char *row_name(struct csa *csa, int i, char rname[255+1])
+{ /* construct symbolic name of i-th row (constraint) */
+ const char *name;
+ if (i == 0)
+ name = glp_get_obj_name(csa->P);
+ else
+ name = glp_get_row_name(csa->P, i);
+ if (name == NULL) goto fake;
+ strcpy(rname, name);
+ adjust_name(rname);
+ if (check_name(rname)) goto fake;
+ return rname;
+fake: if (i == 0)
+ strcpy(rname, "obj");
+ else
+ sprintf(rname, "r_%d", i);
+ return rname;
+}
+
+static char *col_name(struct csa *csa, int j, char cname[255+1])
+{ /* construct symbolic name of j-th column (variable) */
+ const char *name;
+ name = glp_get_col_name(csa->P, j);
+ if (name == NULL) goto fake;
+ strcpy(cname, name);
+ adjust_name(cname);
+ if (check_name(cname)) goto fake;
+ return cname;
+#if 0 /* 18/I-2018 */
+fake: sprintf(cname, "x_%d", j);
+#else
+fake: /* construct fake name depending on column's attributes */
+ { GLPCOL *col = csa->P->col[j];
+ if (col->type == GLP_FX)
+ { /* fixed column */
+ sprintf(cname, "s_%d", j);
+ }
+ else if (col->kind == GLP_CV)
+ { /* continuous variable */
+ sprintf(cname, "x_%d", j);
+ }
+ else if (!(col->lb == 0 && col->ub == 1))
+ { /* general (non-binary) integer variable */
+ sprintf(cname, "y_%d", j);
+ }
+ else
+ { /* binary variable */
+ sprintf(cname, "z_%d", j);
+ }
+ }
+#endif
+ return cname;
+}
+
+int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
+{ /* write problem data in CPLEX LP format */
+ glp_cpxcp _parm;
+ struct csa _csa, *csa = &_csa;
+ glp_file *fp;
+ GLPROW *row;
+ GLPCOL *col;
+ GLPAIJ *aij;
+ int i, j, len, flag, count, ret;
+ char line[1000+1], term[500+1], name[255+1];
+ xprintf("Writing problem data to '%s'...\n", fname);
+ if (parm == NULL)
+ glp_init_cpxcp(&_parm), parm = &_parm;
+ /* check control parameters */
+ check_parm("glp_write_lp", parm);
+ /* initialize common storage area */
+ csa->P = P;
+ csa->parm = parm;
+ /* create output CPLEX LP file */
+ fp = glp_open(fname, "w"), count = 0;
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ /* write problem name */
+ xfprintf(fp, "\\* Problem: %s *\\\n",
+ P->name == NULL ? "Unknown" : P->name), count++;
+ xfprintf(fp, "\n"), count++;
+ /* the problem should contain at least one row and one column */
+ if (!(P->m > 0 && P->n > 0))
+ { xprintf("Warning: problem has no rows/columns\n");
+ xfprintf(fp, "\\* WARNING: PROBLEM HAS NO ROWS/COLUMNS *\\\n"),
+ count++;
+ xfprintf(fp, "\n"), count++;
+ goto skip;
+ }
+ /* write the objective function definition */
+ if (P->dir == GLP_MIN)
+ xfprintf(fp, "Minimize\n"), count++;
+ else if (P->dir == GLP_MAX)
+ xfprintf(fp, "Maximize\n"), count++;
+ else
+ xassert(P != P);
+ row_name(csa, 0, name);
+ sprintf(line, " %s:", name);
+ len = 0;
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (col->coef != 0.0 || col->ptr == NULL)
+ { len++;
+ col_name(csa, j, name);
+ if (col->coef == 0.0)
+ sprintf(term, " + 0 %s", name); /* empty column */
+ else if (col->coef == +1.0)
+ sprintf(term, " + %s", name);
+ else if (col->coef == -1.0)
+ sprintf(term, " - %s", name);
+ else if (col->coef > 0.0)
+ sprintf(term, " + %.*g %s", DBL_DIG, +col->coef, name);
+ else
+ sprintf(term, " - %.*g %s", DBL_DIG, -col->coef, name);
+ if (strlen(line) + strlen(term) > 72)
+ xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+ strcat(line, term);
+ }
+ }
+ if (len == 0)
+ { /* empty objective */
+ sprintf(term, " 0 %s", col_name(csa, 1, name));
+ strcat(line, term);
+ }
+ xfprintf(fp, "%s\n", line), count++;
+ if (P->c0 != 0.0)
+ xfprintf(fp, "\\* constant term = %.*g *\\\n", DBL_DIG, P->c0),
+ count++;
+ xfprintf(fp, "\n"), count++;
+ /* write the constraints section */
+ xfprintf(fp, "Subject To\n"), count++;
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ if (row->type == GLP_FR) continue; /* skip free row */
+ row_name(csa, i, name);
+ sprintf(line, " %s:", name);
+ /* linear form */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col_name(csa, aij->col->j, name);
+ if (aij->val == +1.0)
+ sprintf(term, " + %s", name);
+ else if (aij->val == -1.0)
+ sprintf(term, " - %s", name);
+ else if (aij->val > 0.0)
+ sprintf(term, " + %.*g %s", DBL_DIG, +aij->val, name);
+ else
+ sprintf(term, " - %.*g %s", DBL_DIG, -aij->val, name);
+ if (strlen(line) + strlen(term) > 72)
+ xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+ strcat(line, term);
+ }
+ if (row->type == GLP_DB)
+ { /* double-bounded (ranged) constraint */
+ sprintf(term, " - ~r_%d", i);
+ if (strlen(line) + strlen(term) > 72)
+ xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+ strcat(line, term);
+ }
+ else if (row->ptr == NULL)
+ { /* empty constraint */
+ sprintf(term, " 0 %s", col_name(csa, 1, name));
+ strcat(line, term);
+ }
+ /* right hand-side */
+ if (row->type == GLP_LO)
+ sprintf(term, " >= %.*g", DBL_DIG, row->lb);
+ else if (row->type == GLP_UP)
+ sprintf(term, " <= %.*g", DBL_DIG, row->ub);
+ else if (row->type == GLP_DB || row->type == GLP_FX)
+ sprintf(term, " = %.*g", DBL_DIG, row->lb);
+ else
+ xassert(row != row);
+ if (strlen(line) + strlen(term) > 72)
+ xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+ strcat(line, term);
+ xfprintf(fp, "%s\n", line), count++;
+ }
+ xfprintf(fp, "\n"), count++;
+ /* write the bounds section */
+ flag = 0;
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ if (row->type != GLP_DB) continue;
+ if (!flag)
+ xfprintf(fp, "Bounds\n"), flag = 1, count++;
+ xfprintf(fp, " 0 <= ~r_%d <= %.*g\n",
+ i, DBL_DIG, row->ub - row->lb), count++;
+ }
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (col->type == GLP_LO && col->lb == 0.0) continue;
+ if (!flag)
+ xfprintf(fp, "Bounds\n"), flag = 1, count++;
+ col_name(csa, j, name);
+ if (col->type == GLP_FR)
+ xfprintf(fp, " %s free\n", name), count++;
+ else if (col->type == GLP_LO)
+ xfprintf(fp, " %s >= %.*g\n",
+ name, DBL_DIG, col->lb), count++;
+ else if (col->type == GLP_UP)
+ xfprintf(fp, " -Inf <= %s <= %.*g\n",
+ name, DBL_DIG, col->ub), count++;
+ else if (col->type == GLP_DB)
+ xfprintf(fp, " %.*g <= %s <= %.*g\n",
+ DBL_DIG, col->lb, name, DBL_DIG, col->ub), count++;
+ else if (col->type == GLP_FX)
+ xfprintf(fp, " %s = %.*g\n",
+ name, DBL_DIG, col->lb), count++;
+ else
+ xassert(col != col);
+ }
+ if (flag) xfprintf(fp, "\n"), count++;
+ /* write the integer section */
+ flag = 0;
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (col->kind == GLP_CV) continue;
+ xassert(col->kind == GLP_IV);
+ if (!flag)
+ xfprintf(fp, "Generals\n"), flag = 1, count++;
+ xfprintf(fp, " %s\n", col_name(csa, j, name)), count++;
+ }
+ if (flag) xfprintf(fp, "\n"), count++;
+skip: /* write the end keyword */
+ xfprintf(fp, "End\n"), count++;
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ /* problem data has been successfully written */
+ xprintf("%d lines were written\n", count);
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/cpp.c b/test/monniaux/glpk-4.65/src/api/cpp.c
new file mode 100644
index 00000000..ac3d63ef
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/cpp.c
@@ -0,0 +1,185 @@
+/* cpp.c (solve critical path problem) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_cpp - solve critical path problem
+*
+* SYNOPSIS
+*
+* double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
+*
+* DESCRIPTION
+*
+* The routine glp_cpp solves the critical path problem represented in
+* the form of the project network.
+*
+* The parameter G is a pointer to the graph object, which specifies
+* the project network. This graph must be acyclic. Multiple arcs are
+* allowed being considered as single arcs.
+*
+* The parameter v_t specifies an offset of the field of type double
+* in the vertex data block, which contains time t[i] >= 0 needed to
+* perform corresponding job j. If v_t < 0, it is assumed that t[i] = 1
+* for all jobs.
+*
+* The parameter v_es specifies an offset of the field of type double
+* in the vertex data block, to which the routine stores earliest start
+* time for corresponding job. If v_es < 0, this time is not stored.
+*
+* The parameter v_ls specifies an offset of the field of type double
+* in the vertex data block, to which the routine stores latest start
+* time for corresponding job. If v_ls < 0, this time is not stored.
+*
+* RETURNS
+*
+* The routine glp_cpp returns the minimal project duration, that is,
+* minimal time needed to perform all jobs in the project. */
+
+static void sorting(glp_graph *G, int list[]);
+
+double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls)
+{ glp_vertex *v;
+ glp_arc *a;
+ int i, j, k, nv, *list;
+ double temp, total, *t, *es, *ls;
+ if (v_t >= 0 && v_t > G->v_size - (int)sizeof(double))
+ xerror("glp_cpp: v_t = %d; invalid offset\n", v_t);
+ if (v_es >= 0 && v_es > G->v_size - (int)sizeof(double))
+ xerror("glp_cpp: v_es = %d; invalid offset\n", v_es);
+ if (v_ls >= 0 && v_ls > G->v_size - (int)sizeof(double))
+ xerror("glp_cpp: v_ls = %d; invalid offset\n", v_ls);
+ nv = G->nv;
+ if (nv == 0)
+ { total = 0.0;
+ goto done;
+ }
+ /* allocate working arrays */
+ t = xcalloc(1+nv, sizeof(double));
+ es = xcalloc(1+nv, sizeof(double));
+ ls = xcalloc(1+nv, sizeof(double));
+ list = xcalloc(1+nv, sizeof(int));
+ /* retrieve job times */
+ for (i = 1; i <= nv; i++)
+ { v = G->v[i];
+ if (v_t >= 0)
+ { memcpy(&t[i], (char *)v->data + v_t, sizeof(double));
+ if (t[i] < 0.0)
+ xerror("glp_cpp: t[%d] = %g; invalid time\n", i, t[i]);
+ }
+ else
+ t[i] = 1.0;
+ }
+ /* perform topological sorting to determine the list of nodes
+ (jobs) such that if list[k] = i and list[kk] = j and there
+ exists arc (i->j), then k < kk */
+ sorting(G, list);
+ /* FORWARD PASS */
+ /* determine earliest start times */
+ for (k = 1; k <= nv; k++)
+ { j = list[k];
+ es[j] = 0.0;
+ for (a = G->v[j]->in; a != NULL; a = a->h_next)
+ { i = a->tail->i;
+ /* there exists arc (i->j) in the project network */
+ temp = es[i] + t[i];
+ if (es[j] < temp) es[j] = temp;
+ }
+ }
+ /* determine the minimal project duration */
+ total = 0.0;
+ for (i = 1; i <= nv; i++)
+ { temp = es[i] + t[i];
+ if (total < temp) total = temp;
+ }
+ /* BACKWARD PASS */
+ /* determine latest start times */
+ for (k = nv; k >= 1; k--)
+ { i = list[k];
+ ls[i] = total - t[i];
+ for (a = G->v[i]->out; a != NULL; a = a->t_next)
+ { j = a->head->i;
+ /* there exists arc (i->j) in the project network */
+ temp = ls[j] - t[i];
+ if (ls[i] > temp) ls[i] = temp;
+ }
+ /* avoid possible round-off errors */
+ if (ls[i] < es[i]) ls[i] = es[i];
+ }
+ /* store results, if necessary */
+ if (v_es >= 0)
+ { for (i = 1; i <= nv; i++)
+ { v = G->v[i];
+ memcpy((char *)v->data + v_es, &es[i], sizeof(double));
+ }
+ }
+ if (v_ls >= 0)
+ { for (i = 1; i <= nv; i++)
+ { v = G->v[i];
+ memcpy((char *)v->data + v_ls, &ls[i], sizeof(double));
+ }
+ }
+ /* free working arrays */
+ xfree(t);
+ xfree(es);
+ xfree(ls);
+ xfree(list);
+done: return total;
+}
+
+static void sorting(glp_graph *G, int list[])
+{ /* perform topological sorting to determine the list of nodes
+ (jobs) such that if list[k] = i and list[kk] = j and there
+ exists arc (i->j), then k < kk */
+ int i, k, nv, v_size, *num;
+ void **save;
+ nv = G->nv;
+ v_size = G->v_size;
+ save = xcalloc(1+nv, sizeof(void *));
+ num = xcalloc(1+nv, sizeof(int));
+ G->v_size = sizeof(int);
+ for (i = 1; i <= nv; i++)
+ { save[i] = G->v[i]->data;
+ G->v[i]->data = &num[i];
+ list[i] = 0;
+ }
+ if (glp_top_sort(G, 0) != 0)
+ xerror("glp_cpp: project network is not acyclic\n");
+ G->v_size = v_size;
+ for (i = 1; i <= nv; i++)
+ { G->v[i]->data = save[i];
+ k = num[i];
+ xassert(1 <= k && k <= nv);
+ xassert(list[k] == 0);
+ list[k] = i;
+ }
+ xfree(save);
+ xfree(num);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/cpxbas.c b/test/monniaux/glpk-4.65/src/api/cpxbas.c
new file mode 100644
index 00000000..e1c656a7
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/cpxbas.c
@@ -0,0 +1,269 @@
+/* cpxbas.c (construct Bixby's initial LP basis) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2008-2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+struct var
+{ /* structural variable */
+ int j;
+ /* ordinal number */
+ double q;
+ /* penalty value */
+};
+
+static int CDECL fcmp(const void *ptr1, const void *ptr2)
+{ /* this routine is passed to the qsort() function */
+ struct var *col1 = (void *)ptr1, *col2 = (void *)ptr2;
+ if (col1->q < col2->q) return -1;
+ if (col1->q > col2->q) return +1;
+ return 0;
+}
+
+static int get_column(glp_prob *lp, int j, int ind[], double val[])
+{ /* Bixby's algorithm assumes that the constraint matrix is scaled
+ such that the maximum absolute value in every non-zero row and
+ column is 1 */
+ int k, len;
+ double big;
+ len = glp_get_mat_col(lp, j, ind, val);
+ big = 0.0;
+ for (k = 1; k <= len; k++)
+ if (big < fabs(val[k])) big = fabs(val[k]);
+ if (big == 0.0) big = 1.0;
+ for (k = 1; k <= len; k++) val[k] /= big;
+ return len;
+}
+
+static void cpx_basis(glp_prob *lp)
+{ /* main routine */
+ struct var *C, *C2, *C3, *C4;
+ int m, n, i, j, jk, k, l, ll, t, n2, n3, n4, type, len, *I, *r,
+ *ind;
+ double alpha, gamma, cmax, temp, *v, *val;
+ xprintf("Constructing initial basis...\n");
+ /* determine the number of rows and columns */
+ m = glp_get_num_rows(lp);
+ n = glp_get_num_cols(lp);
+ /* allocate working arrays */
+ C = xcalloc(1+n, sizeof(struct var));
+ I = xcalloc(1+m, sizeof(int));
+ r = xcalloc(1+m, sizeof(int));
+ v = xcalloc(1+m, sizeof(double));
+ ind = xcalloc(1+m, sizeof(int));
+ val = xcalloc(1+m, sizeof(double));
+ /* make all auxiliary variables non-basic */
+ for (i = 1; i <= m; i++)
+ { if (glp_get_row_type(lp, i) != GLP_DB)
+ glp_set_row_stat(lp, i, GLP_NS);
+ else if (fabs(glp_get_row_lb(lp, i)) <=
+ fabs(glp_get_row_ub(lp, i)))
+ glp_set_row_stat(lp, i, GLP_NL);
+ else
+ glp_set_row_stat(lp, i, GLP_NU);
+ }
+ /* make all structural variables non-basic */
+ for (j = 1; j <= n; j++)
+ { if (glp_get_col_type(lp, j) != GLP_DB)
+ glp_set_col_stat(lp, j, GLP_NS);
+ else if (fabs(glp_get_col_lb(lp, j)) <=
+ fabs(glp_get_col_ub(lp, j)))
+ glp_set_col_stat(lp, j, GLP_NL);
+ else
+ glp_set_col_stat(lp, j, GLP_NU);
+ }
+ /* C2 is a set of free structural variables */
+ n2 = 0, C2 = C + 0;
+ for (j = 1; j <= n; j++)
+ { type = glp_get_col_type(lp, j);
+ if (type == GLP_FR)
+ { n2++;
+ C2[n2].j = j;
+ C2[n2].q = 0.0;
+ }
+ }
+ /* C3 is a set of structural variables having excatly one (lower
+ or upper) bound */
+ n3 = 0, C3 = C2 + n2;
+ for (j = 1; j <= n; j++)
+ { type = glp_get_col_type(lp, j);
+ if (type == GLP_LO)
+ { n3++;
+ C3[n3].j = j;
+ C3[n3].q = + glp_get_col_lb(lp, j);
+ }
+ else if (type == GLP_UP)
+ { n3++;
+ C3[n3].j = j;
+ C3[n3].q = - glp_get_col_ub(lp, j);
+ }
+ }
+ /* C4 is a set of structural variables having both (lower and
+ upper) bounds */
+ n4 = 0, C4 = C3 + n3;
+ for (j = 1; j <= n; j++)
+ { type = glp_get_col_type(lp, j);
+ if (type == GLP_DB)
+ { n4++;
+ C4[n4].j = j;
+ C4[n4].q = glp_get_col_lb(lp, j) - glp_get_col_ub(lp, j);
+ }
+ }
+ /* compute gamma = max{|c[j]|: 1 <= j <= n} */
+ gamma = 0.0;
+ for (j = 1; j <= n; j++)
+ { temp = fabs(glp_get_obj_coef(lp, j));
+ if (gamma < temp) gamma = temp;
+ }
+ /* compute cmax */
+ cmax = (gamma == 0.0 ? 1.0 : 1000.0 * gamma);
+ /* compute final penalty for all structural variables within sets
+ C2, C3, and C4 */
+ switch (glp_get_obj_dir(lp))
+ { case GLP_MIN: temp = +1.0; break;
+ case GLP_MAX: temp = -1.0; break;
+ default: xassert(lp != lp);
+ }
+ for (k = 1; k <= n2+n3+n4; k++)
+ { j = C[k].j;
+ C[k].q += (temp * glp_get_obj_coef(lp, j)) / cmax;
+ }
+ /* sort structural variables within C2, C3, and C4 in ascending
+ order of penalty value */
+ qsort(C2+1, n2, sizeof(struct var), fcmp);
+ for (k = 1; k < n2; k++) xassert(C2[k].q <= C2[k+1].q);
+ qsort(C3+1, n3, sizeof(struct var), fcmp);
+ for (k = 1; k < n3; k++) xassert(C3[k].q <= C3[k+1].q);
+ qsort(C4+1, n4, sizeof(struct var), fcmp);
+ for (k = 1; k < n4; k++) xassert(C4[k].q <= C4[k+1].q);
+ /*** STEP 1 ***/
+ for (i = 1; i <= m; i++)
+ { type = glp_get_row_type(lp, i);
+ if (type != GLP_FX)
+ { /* row i is either free or inequality constraint */
+ glp_set_row_stat(lp, i, GLP_BS);
+ I[i] = 1;
+ r[i] = 1;
+ }
+ else
+ { /* row i is equality constraint */
+ I[i] = 0;
+ r[i] = 0;
+ }
+ v[i] = +DBL_MAX;
+ }
+ /*** STEP 2 ***/
+ for (k = 1; k <= n2+n3+n4; k++)
+ { jk = C[k].j;
+ len = get_column(lp, jk, ind, val);
+ /* let alpha = max{|A[l,jk]|: r[l] = 0} and let l' be such
+ that alpha = |A[l',jk]| */
+ alpha = 0.0, ll = 0;
+ for (t = 1; t <= len; t++)
+ { l = ind[t];
+ if (r[l] == 0 && alpha < fabs(val[t]))
+ alpha = fabs(val[t]), ll = l;
+ }
+ if (alpha >= 0.99)
+ { /* B := B union {jk} */
+ glp_set_col_stat(lp, jk, GLP_BS);
+ I[ll] = 1;
+ v[ll] = alpha;
+ /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */
+ for (t = 1; t <= len; t++)
+ { l = ind[t];
+ if (val[t] != 0.0) r[l]++;
+ }
+ /* continue to the next k */
+ continue;
+ }
+ /* if |A[l,jk]| > 0.01 * v[l] for some l, continue to the
+ next k */
+ for (t = 1; t <= len; t++)
+ { l = ind[t];
+ if (fabs(val[t]) > 0.01 * v[l]) break;
+ }
+ if (t <= len) continue;
+ /* otherwise, let alpha = max{|A[l,jk]|: I[l] = 0} and let l'
+ be such that alpha = |A[l',jk]| */
+ alpha = 0.0, ll = 0;
+ for (t = 1; t <= len; t++)
+ { l = ind[t];
+ if (I[l] == 0 && alpha < fabs(val[t]))
+ alpha = fabs(val[t]), ll = l;
+ }
+ /* if alpha = 0, continue to the next k */
+ if (alpha == 0.0) continue;
+ /* B := B union {jk} */
+ glp_set_col_stat(lp, jk, GLP_BS);
+ I[ll] = 1;
+ v[ll] = alpha;
+ /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */
+ for (t = 1; t <= len; t++)
+ { l = ind[t];
+ if (val[t] != 0.0) r[l]++;
+ }
+ }
+ /*** STEP 3 ***/
+ /* add an artificial variable (auxiliary variable for equality
+ constraint) to cover each remaining uncovered row */
+ for (i = 1; i <= m; i++)
+ if (I[i] == 0) glp_set_row_stat(lp, i, GLP_BS);
+ /* free working arrays */
+ xfree(C);
+ xfree(I);
+ xfree(r);
+ xfree(v);
+ xfree(ind);
+ xfree(val);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_cpx_basis - construct Bixby's initial LP basis
+*
+* SYNOPSIS
+*
+* void glp_cpx_basis(glp_prob *lp);
+*
+* DESCRIPTION
+*
+* The routine glp_cpx_basis constructs an advanced initial basis for
+* the specified problem object.
+*
+* The routine is based on Bixby's algorithm described in the paper:
+*
+* Robert E. Bixby. Implementing the Simplex Method: The Initial Basis.
+* ORSA Journal on Computing, Vol. 4, No. 3, 1992, pp. 267-84. */
+
+void glp_cpx_basis(glp_prob *lp)
+{ if (lp->m == 0 || lp->n == 0)
+ glp_std_basis(lp);
+ else
+ cpx_basis(lp);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/graph.c b/test/monniaux/glpk-4.65/src/api/graph.c
new file mode 100644
index 00000000..82994c84
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/graph.c
@@ -0,0 +1,504 @@
+/* graph.c (basic graph routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "avl.h"
+#include "dmp.h"
+#include "env.h"
+#include "glpk.h"
+
+/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
+
+#define NV_MAX 100000000 /* = 100*10^6 */
+/* maximal number of vertices in the graph */
+
+#define NA_MAX 500000000 /* = 500*10^6 */
+/* maximal number of arcs in the graph */
+
+/***********************************************************************
+* NAME
+*
+* glp_create_graph - create graph
+*
+* SYNOPSIS
+*
+* glp_graph *glp_create_graph(int v_size, int a_size);
+*
+* DESCRIPTION
+*
+* The routine creates a new graph, which initially is empty, i.e. has
+* no vertices and arcs.
+*
+* The parameter v_size specifies the size of data associated with each
+* vertex of the graph (0 to 256 bytes).
+*
+* The parameter a_size specifies the size of data associated with each
+* arc of the graph (0 to 256 bytes).
+*
+* RETURNS
+*
+* The routine returns a pointer to the graph created. */
+
+static void create_graph(glp_graph *G, int v_size, int a_size)
+{ G->pool = dmp_create_pool();
+ G->name = NULL;
+ G->nv_max = 50;
+ G->nv = G->na = 0;
+ G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
+ G->index = NULL;
+ G->v_size = v_size;
+ G->a_size = a_size;
+ return;
+}
+
+glp_graph *glp_create_graph(int v_size, int a_size)
+{ glp_graph *G;
+ if (!(0 <= v_size && v_size <= 256))
+ xerror("glp_create_graph: v_size = %d; invalid size of vertex "
+ "data\n", v_size);
+ if (!(0 <= a_size && a_size <= 256))
+ xerror("glp_create_graph: a_size = %d; invalid size of arc dat"
+ "a\n", a_size);
+ G = xmalloc(sizeof(glp_graph));
+ create_graph(G, v_size, a_size);
+ return G;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_graph_name - assign (change) graph name
+*
+* SYNOPSIS
+*
+* void glp_set_graph_name(glp_graph *G, const char *name);
+*
+* DESCRIPTION
+*
+* The routine glp_set_graph_name assigns a symbolic name specified by
+* the character string name (1 to 255 chars) to the graph.
+*
+* If the parameter name is NULL or an empty string, the routine erases
+* the existing symbolic name of the graph. */
+
+void glp_set_graph_name(glp_graph *G, const char *name)
+{ if (G->name != NULL)
+ { dmp_free_atom(G->pool, G->name, strlen(G->name)+1);
+ G->name = NULL;
+ }
+ if (!(name == NULL || name[0] == '\0'))
+ { int j;
+ for (j = 0; name[j] != '\0'; j++)
+ { if (j == 256)
+ xerror("glp_set_graph_name: graph name too long\n");
+ if (iscntrl((unsigned char)name[j]))
+ xerror("glp_set_graph_name: graph name contains invalid "
+ "character(s)\n");
+ }
+ G->name = dmp_get_atom(G->pool, strlen(name)+1);
+ strcpy(G->name, name);
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_add_vertices - add new vertices to graph
+*
+* SYNOPSIS
+*
+* int glp_add_vertices(glp_graph *G, int nadd);
+*
+* DESCRIPTION
+*
+* The routine glp_add_vertices adds nadd vertices to the specified
+* graph. New vertices are always added to the end of the vertex list,
+* so ordinal numbers of existing vertices remain unchanged.
+*
+* Being added each new vertex is isolated (has no incident arcs).
+*
+* RETURNS
+*
+* The routine glp_add_vertices returns an ordinal number of the first
+* new vertex added to the graph. */
+
+int glp_add_vertices(glp_graph *G, int nadd)
+{ int i, nv_new;
+ if (nadd < 1)
+ xerror("glp_add_vertices: nadd = %d; invalid number of vertice"
+ "s\n", nadd);
+ if (nadd > NV_MAX - G->nv)
+ xerror("glp_add_vertices: nadd = %d; too many vertices\n",
+ nadd);
+ /* determine new number of vertices */
+ nv_new = G->nv + nadd;
+ /* increase the room, if necessary */
+ if (G->nv_max < nv_new)
+ { glp_vertex **save = G->v;
+ while (G->nv_max < nv_new)
+ { G->nv_max += G->nv_max;
+ xassert(G->nv_max > 0);
+ }
+ G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
+ memcpy(&G->v[1], &save[1], G->nv * sizeof(glp_vertex *));
+ xfree(save);
+ }
+ /* add new vertices to the end of the vertex list */
+ for (i = G->nv+1; i <= nv_new; i++)
+ { glp_vertex *v;
+ G->v[i] = v = dmp_get_atom(G->pool, sizeof(glp_vertex));
+ v->i = i;
+ v->name = NULL;
+ v->entry = NULL;
+ if (G->v_size == 0)
+ v->data = NULL;
+ else
+ { v->data = dmp_get_atom(G->pool, G->v_size);
+ memset(v->data, 0, G->v_size);
+ }
+ v->temp = NULL;
+ v->in = v->out = NULL;
+ }
+ /* set new number of vertices */
+ G->nv = nv_new;
+ /* return the ordinal number of the first vertex added */
+ return nv_new - nadd + 1;
+}
+
+/**********************************************************************/
+
+void glp_set_vertex_name(glp_graph *G, int i, const char *name)
+{ /* assign (change) vertex name */
+ glp_vertex *v;
+ if (!(1 <= i && i <= G->nv))
+ xerror("glp_set_vertex_name: i = %d; vertex number out of rang"
+ "e\n", i);
+ v = G->v[i];
+ if (v->name != NULL)
+ { if (v->entry != NULL)
+ { xassert(G->index != NULL);
+ avl_delete_node(G->index, v->entry);
+ v->entry = NULL;
+ }
+ dmp_free_atom(G->pool, v->name, strlen(v->name)+1);
+ v->name = NULL;
+ }
+ if (!(name == NULL || name[0] == '\0'))
+ { int k;
+ for (k = 0; name[k] != '\0'; k++)
+ { if (k == 256)
+ xerror("glp_set_vertex_name: i = %d; vertex name too lon"
+ "g\n", i);
+ if (iscntrl((unsigned char)name[k]))
+ xerror("glp_set_vertex_name: i = %d; vertex name contain"
+ "s invalid character(s)\n", i);
+ }
+ v->name = dmp_get_atom(G->pool, strlen(name)+1);
+ strcpy(v->name, name);
+ if (G->index != NULL)
+ { xassert(v->entry == NULL);
+ v->entry = avl_insert_node(G->index, v->name);
+ avl_set_node_link(v->entry, v);
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_add_arc - add new arc to graph
+*
+* SYNOPSIS
+*
+* glp_arc *glp_add_arc(glp_graph *G, int i, int j);
+*
+* DESCRIPTION
+*
+* The routine glp_add_arc adds a new arc to the specified graph.
+*
+* The parameters i and j specify the ordinal numbers of, resp., tail
+* and head vertices of the arc. Note that self-loops and multiple arcs
+* are allowed.
+*
+* RETURNS
+*
+* The routine glp_add_arc returns a pointer to the arc added. */
+
+glp_arc *glp_add_arc(glp_graph *G, int i, int j)
+{ glp_arc *a;
+ if (!(1 <= i && i <= G->nv))
+ xerror("glp_add_arc: i = %d; tail vertex number out of range\n"
+ , i);
+ if (!(1 <= j && j <= G->nv))
+ xerror("glp_add_arc: j = %d; head vertex number out of range\n"
+ , j);
+ if (G->na == NA_MAX)
+ xerror("glp_add_arc: too many arcs\n");
+ a = dmp_get_atom(G->pool, sizeof(glp_arc));
+ a->tail = G->v[i];
+ a->head = G->v[j];
+ if (G->a_size == 0)
+ a->data = NULL;
+ else
+ { a->data = dmp_get_atom(G->pool, G->a_size);
+ memset(a->data, 0, G->a_size);
+ }
+ a->temp = NULL;
+ a->t_prev = NULL;
+ a->t_next = G->v[i]->out;
+ if (a->t_next != NULL) a->t_next->t_prev = a;
+ a->h_prev = NULL;
+ a->h_next = G->v[j]->in;
+ if (a->h_next != NULL) a->h_next->h_prev = a;
+ G->v[i]->out = G->v[j]->in = a;
+ G->na++;
+ return a;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_del_vertices - delete vertices from graph
+*
+* SYNOPSIS
+*
+* void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
+*
+* DESCRIPTION
+*
+* The routine glp_del_vertices deletes vertices along with all
+* incident arcs from the specified graph. Ordinal numbers of vertices
+* to be deleted should be placed in locations num[1], ..., num[ndel],
+* ndel > 0.
+*
+* Note that deleting vertices involves changing ordinal numbers of
+* other vertices remaining in the graph. New ordinal numbers of the
+* remaining vertices are assigned under the assumption that the
+* original order of vertices is not changed. */
+
+void glp_del_vertices(glp_graph *G, int ndel, const int num[])
+{ glp_vertex *v;
+ int i, k, nv_new;
+ /* scan the list of vertices to be deleted */
+ if (!(1 <= ndel && ndel <= G->nv))
+ xerror("glp_del_vertices: ndel = %d; invalid number of vertice"
+ "s\n", ndel);
+ for (k = 1; k <= ndel; k++)
+ { /* take the number of vertex to be deleted */
+ i = num[k];
+ /* obtain pointer to i-th vertex */
+ if (!(1 <= i && i <= G->nv))
+ xerror("glp_del_vertices: num[%d] = %d; vertex number out o"
+ "f range\n", k, i);
+ v = G->v[i];
+ /* check that the vertex is not marked yet */
+ if (v->i == 0)
+ xerror("glp_del_vertices: num[%d] = %d; duplicate vertex nu"
+ "mbers not allowed\n", k, i);
+ /* erase symbolic name assigned to the vertex */
+ glp_set_vertex_name(G, i, NULL);
+ xassert(v->name == NULL);
+ xassert(v->entry == NULL);
+ /* free vertex data, if allocated */
+ if (v->data != NULL)
+ dmp_free_atom(G->pool, v->data, G->v_size);
+ /* delete all incoming arcs */
+ while (v->in != NULL)
+ glp_del_arc(G, v->in);
+ /* delete all outgoing arcs */
+ while (v->out != NULL)
+ glp_del_arc(G, v->out);
+ /* mark the vertex to be deleted */
+ v->i = 0;
+ }
+ /* delete all marked vertices from the vertex list */
+ nv_new = 0;
+ for (i = 1; i <= G->nv; i++)
+ { /* obtain pointer to i-th vertex */
+ v = G->v[i];
+ /* check if the vertex is marked */
+ if (v->i == 0)
+ { /* it is marked, delete it */
+ dmp_free_atom(G->pool, v, sizeof(glp_vertex));
+ }
+ else
+ { /* it is not marked, keep it */
+ v->i = ++nv_new;
+ G->v[v->i] = v;
+ }
+ }
+ /* set new number of vertices in the graph */
+ G->nv = nv_new;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_del_arc - delete arc from graph
+*
+* SYNOPSIS
+*
+* void glp_del_arc(glp_graph *G, glp_arc *a);
+*
+* DESCRIPTION
+*
+* The routine glp_del_arc deletes an arc from the specified graph.
+* The arc to be deleted must exist. */
+
+void glp_del_arc(glp_graph *G, glp_arc *a)
+{ /* some sanity checks */
+ xassert(G->na > 0);
+ xassert(1 <= a->tail->i && a->tail->i <= G->nv);
+ xassert(a->tail == G->v[a->tail->i]);
+ xassert(1 <= a->head->i && a->head->i <= G->nv);
+ xassert(a->head == G->v[a->head->i]);
+ /* remove the arc from the list of incoming arcs */
+ if (a->h_prev == NULL)
+ a->head->in = a->h_next;
+ else
+ a->h_prev->h_next = a->h_next;
+ if (a->h_next == NULL)
+ ;
+ else
+ a->h_next->h_prev = a->h_prev;
+ /* remove the arc from the list of outgoing arcs */
+ if (a->t_prev == NULL)
+ a->tail->out = a->t_next;
+ else
+ a->t_prev->t_next = a->t_next;
+ if (a->t_next == NULL)
+ ;
+ else
+ a->t_next->t_prev = a->t_prev;
+ /* free arc data, if allocated */
+ if (a->data != NULL)
+ dmp_free_atom(G->pool, a->data, G->a_size);
+ /* delete the arc from the graph */
+ dmp_free_atom(G->pool, a, sizeof(glp_arc));
+ G->na--;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_erase_graph - erase graph content
+*
+* SYNOPSIS
+*
+* void glp_erase_graph(glp_graph *G, int v_size, int a_size);
+*
+* DESCRIPTION
+*
+* The routine glp_erase_graph erases the content of the specified
+* graph. The effect of this operation is the same as if the graph
+* would be deleted with the routine glp_delete_graph and then created
+* anew with the routine glp_create_graph, with exception that the
+* handle (pointer) to the graph remains valid. */
+
+static void delete_graph(glp_graph *G)
+{ dmp_delete_pool(G->pool);
+ xfree(G->v);
+ if (G->index != NULL) avl_delete_tree(G->index);
+ return;
+}
+
+void glp_erase_graph(glp_graph *G, int v_size, int a_size)
+{ if (!(0 <= v_size && v_size <= 256))
+ xerror("glp_erase_graph: v_size = %d; invalid size of vertex d"
+ "ata\n", v_size);
+ if (!(0 <= a_size && a_size <= 256))
+ xerror("glp_erase_graph: a_size = %d; invalid size of arc data"
+ "\n", a_size);
+ delete_graph(G);
+ create_graph(G, v_size, a_size);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_delete_graph - delete graph
+*
+* SYNOPSIS
+*
+* void glp_delete_graph(glp_graph *G);
+*
+* DESCRIPTION
+*
+* The routine glp_delete_graph deletes the specified graph and frees
+* all the memory allocated to this program object. */
+
+void glp_delete_graph(glp_graph *G)
+{ delete_graph(G);
+ xfree(G);
+ return;
+}
+
+/**********************************************************************/
+
+void glp_create_v_index(glp_graph *G)
+{ /* create vertex name index */
+ glp_vertex *v;
+ int i;
+ if (G->index == NULL)
+ { G->index = avl_create_tree(avl_strcmp, NULL);
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ xassert(v->entry == NULL);
+ if (v->name != NULL)
+ { v->entry = avl_insert_node(G->index, v->name);
+ avl_set_node_link(v->entry, v);
+ }
+ }
+ }
+ return;
+}
+
+int glp_find_vertex(glp_graph *G, const char *name)
+{ /* find vertex by its name */
+ AVLNODE *node;
+ int i = 0;
+ if (G->index == NULL)
+ xerror("glp_find_vertex: vertex name index does not exist\n");
+ if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
+ { node = avl_find_node(G->index, name);
+ if (node != NULL)
+ i = ((glp_vertex *)avl_get_node_link(node))->i;
+ }
+ return i;
+}
+
+void glp_delete_v_index(glp_graph *G)
+{ /* delete vertex name index */
+ int i;
+ if (G->index != NULL)
+ { avl_delete_tree(G->index), G->index = NULL;
+ for (i = 1; i <= G->nv; i++) G->v[i]->entry = NULL;
+ }
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/gridgen.c b/test/monniaux/glpk-4.65/src/api/gridgen.c
new file mode 100644
index 00000000..8cd3517f
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/gridgen.c
@@ -0,0 +1,769 @@
+/* gridgen.c (grid-like network problem generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* This code is a modified version of the program GRIDGEN, a grid-like
+* network problem generator developed by Yusin Lee and Jim Orlin.
+* The original code is publically available on the DIMACS ftp site at:
+* <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/gridgen>.
+*
+* All changes concern only the program interface, so this modified
+* version produces exactly the same instances as the original version.
+*
+* Changes were made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_gridgen - grid-like network problem generator
+*
+* SYNOPSIS
+*
+* int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+* const int parm[1+14]);
+*
+* DESCRIPTION
+*
+* The routine glp_gridgen is a grid-like network problem generator
+* developed by Yusin Lee and Jim Orlin.
+*
+* The parameter G specifies the graph object, to which the generated
+* problem data have to be stored. Note that on entry the graph object
+* is erased with the routine glp_erase_graph.
+*
+* The parameter v_rhs specifies an offset of the field of type double
+* in the vertex data block, to which the routine stores the supply or
+* demand value. If v_rhs < 0, the value is not stored.
+*
+* The parameter a_cap specifies an offset of the field of type double
+* in the arc data block, to which the routine stores the arc capacity.
+* If a_cap < 0, the capacity is not stored.
+*
+* The parameter a_cost specifies an offset of the field of type double
+* in the arc data block, to which the routine stores the per-unit cost
+* if the arc flow. If a_cost < 0, the cost is not stored.
+*
+* The array parm contains description of the network to be generated:
+*
+* parm[0] not used
+* parm[1] two-ways arcs indicator:
+* 1 - if links in both direction should be generated
+* 0 - otherwise
+* parm[2] random number seed (a positive integer)
+* parm[3] number of nodes (the number of nodes generated might be
+* slightly different to make the network a grid)
+* parm[4] grid width
+* parm[5] number of sources
+* parm[6] number of sinks
+* parm[7] average degree
+* parm[8] total flow
+* parm[9] distribution of arc costs:
+* 1 - uniform
+* 2 - exponential
+* parm[10] lower bound for arc cost (uniform)
+* 100 * lambda (exponential)
+* parm[11] upper bound for arc cost (uniform)
+* not used (exponential)
+* parm[12] distribution of arc capacities:
+* 1 - uniform
+* 2 - exponential
+* parm[13] lower bound for arc capacity (uniform)
+* 100 * lambda (exponential)
+* parm[14] upper bound for arc capacity (uniform)
+* not used (exponential)
+*
+* RETURNS
+*
+* If the instance was successfully generated, the routine glp_gridgen
+* returns zero; otherwise, if specified parameters are inconsistent,
+* the routine returns a non-zero error code.
+*
+* COMMENTS
+*
+* This network generator generates a grid-like network plus a super
+* node. In additional to the arcs connecting the nodes in the grid,
+* there is an arc from each supply node to the super node and from the
+* super node to each demand node to guarantee feasiblity. These arcs
+* have very high costs and very big capacities.
+*
+* The idea of this network generator is as follows: First, a grid of
+* n1 * n2 is generated. For example, 5 * 3. The nodes are numbered as
+* 1 to 15, and the supernode is numbered as n1*n2+1. Then arcs between
+* adjacent nodes are generated. For these arcs, the user is allowed to
+* specify either to generate two-way arcs or one-way arcs. If two-way
+* arcs are to be generated, two arcs, one in each direction, will be
+* generated between each adjacent node pairs. Otherwise, only one arc
+* will be generated. If this is the case, the arcs will be generated
+* in alterntive directions as shown below.
+*
+* 1 ---> 2 ---> 3 ---> 4 ---> 5
+* | ^ | ^ |
+* | | | | |
+* V | V | V
+* 6 <--- 7 <--- 8 <--- 9 <--- 10
+* | ^ | ^ |
+* | | | | |
+* V | V | V
+* 11 --->12 --->13 --->14 ---> 15
+*
+* Then the arcs between the super node and the source/sink nodes are
+* added as mentioned before. If the number of arcs still doesn't reach
+* the requirement, additional arcs will be added by uniformly picking
+* random node pairs. There is no checking to prevent multiple arcs
+* between any pair of nodes. However, there will be no self-arcs (arcs
+* that poins back to its tail node) in the network.
+*
+* The source and sink nodes are selected uniformly in the network, and
+* the imbalances of each source/sink node are also assigned by uniform
+* distribution. */
+
+struct stat_para
+{ /* structure for statistical distributions */
+ int distribution;
+ /* the distribution: */
+#define UNIFORM 1 /* uniform distribution */
+#define EXPONENTIAL 2 /* exponential distribution */
+ double parameter[5];
+ /* the parameters of the distribution */
+};
+
+struct arcs
+{ int from;
+ /* the FROM node of that arc */
+ int to;
+ /* the TO node of that arc */
+ int cost;
+ /* original cost of that arc */
+ int u;
+ /* capacity of the arc */
+};
+
+struct imbalance
+{ int node;
+ /* Node ID */
+ int supply;
+ /* Supply of that node */
+};
+
+struct csa
+{ /* common storage area */
+ glp_graph *G;
+ int v_rhs, a_cap, a_cost;
+ int seed;
+ /* random number seed */
+ int seed_original;
+ /* the original seed from input */
+ int two_way;
+ /* 0: generate arcs in both direction for the basic grid, except
+ for the arcs to/from the super node. 1: o/w */
+ int n_node;
+ /* total number of nodes in the network, numbered 1 to n_node,
+ including the super node, which is the last one */
+ int n_arc;
+ /* total number of arcs in the network, counting EVERY arc. */
+ int n_grid_arc;
+ /* number of arcs in the basic grid, including the arcs to/from
+ the super node */
+ int n_source, n_sink;
+ /* number of source and sink nodes */
+ int avg_degree;
+ /* average degree, arcs to and from the super node are counted */
+ int t_supply;
+ /* total supply in the network */
+ int n1, n2;
+ /* the two edges of the network grid. n1 >= n2 */
+ struct imbalance *source_list, *sink_list;
+ /* head of the array of source/sink nodes */
+ struct stat_para arc_costs;
+ /* the distribution of arc costs */
+ struct stat_para capacities;
+ /* distribution of the capacities of the arcs */
+ struct arcs *arc_list;
+ /* head of the arc list array. Arcs in this array are in the
+ order of grid_arcs, arcs to/from super node, and other arcs */
+};
+
+#define G (csa->G)
+#define v_rhs (csa->v_rhs)
+#define a_cap (csa->a_cap)
+#define a_cost (csa->a_cost)
+#define seed (csa->seed)
+#define seed_original (csa->seed_original)
+#define two_way (csa->two_way)
+#define n_node (csa->n_node)
+#define n_arc (csa->n_arc)
+#define n_grid_arc (csa->n_grid_arc)
+#define n_source (csa->n_source)
+#define n_sink (csa->n_sink)
+#define avg_degree (csa->avg_degree)
+#define t_supply (csa->t_supply)
+#define n1 (csa->n1)
+#define n2 (csa->n2)
+#define source_list (csa->source_list)
+#define sink_list (csa->sink_list)
+#define arc_costs (csa->arc_costs)
+#define capacities (csa->capacities)
+#define arc_list (csa->arc_list)
+
+static void assign_capacities(struct csa *csa);
+static void assign_costs(struct csa *csa);
+static void assign_imbalance(struct csa *csa);
+static int exponential(struct csa *csa, double lambda[1]);
+static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs
+ *arc_ptr);
+static struct arcs *gen_basic_grid(struct csa *csa, struct arcs
+ *arc_ptr);
+static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr);
+static void generate(struct csa *csa);
+static void output(struct csa *csa);
+static double randy(struct csa *csa);
+static void select_source_sinks(struct csa *csa);
+static int uniform(struct csa *csa, double a[2]);
+
+int glp_gridgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
+ const int parm[1+14])
+{ struct csa _csa, *csa = &_csa;
+ int n, ret;
+ G = G_;
+ v_rhs = _v_rhs;
+ a_cap = _a_cap;
+ a_cost = _a_cost;
+ if (G != NULL)
+ { if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+ xerror("glp_gridgen: v_rhs = %d; invalid offset\n", v_rhs);
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_gridgen: a_cap = %d; invalid offset\n", a_cap);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_gridgen: a_cost = %d; invalid offset\n", a_cost)
+ ;
+ }
+ /* Check the parameters for consistency. */
+ if (!(parm[1] == 0 || parm[1] == 1))
+ { ret = 1;
+ goto done;
+ }
+ if (parm[2] < 1)
+ { ret = 2;
+ goto done;
+ }
+ if (!(10 <= parm[3] && parm[3] <= 40000))
+ { ret = 3;
+ goto done;
+ }
+ if (!(1 <= parm[4] && parm[4] <= 40000))
+ { ret = 4;
+ goto done;
+ }
+ if (!(parm[5] >= 0 && parm[6] >= 0 && parm[5] + parm[6] <=
+ parm[3]))
+ { ret = 5;
+ goto done;
+ }
+ if (!(1 <= parm[7] && parm[7] <= parm[3]))
+ { ret = 6;
+ goto done;
+ }
+ if (parm[8] < 0)
+ { ret = 7;
+ goto done;
+ }
+ if (!(parm[9] == 1 || parm[9] == 2))
+ { ret = 8;
+ goto done;
+ }
+ if (parm[9] == 1 && parm[10] > parm[11] ||
+ parm[9] == 2 && parm[10] < 1)
+ { ret = 9;
+ goto done;
+ }
+ if (!(parm[12] == 1 || parm[12] == 2))
+ { ret = 10;
+ goto done;
+ }
+ if (parm[12] == 1 && !(0 <= parm[13] && parm[13] <= parm[14]) ||
+ parm[12] == 2 && parm[13] < 1)
+ { ret = 11;
+ goto done;
+ }
+ /* Initialize the graph object. */
+ if (G != NULL)
+ { glp_erase_graph(G, G->v_size, G->a_size);
+ glp_set_graph_name(G, "GRIDGEN");
+ }
+ /* Copy the generator parameters. */
+ two_way = parm[1];
+ seed_original = seed = parm[2];
+ n_node = parm[3];
+ n = parm[4];
+ n_source = parm[5];
+ n_sink = parm[6];
+ avg_degree = parm[7];
+ t_supply = parm[8];
+ arc_costs.distribution = parm[9];
+ if (parm[9] == 1)
+ { arc_costs.parameter[0] = parm[10];
+ arc_costs.parameter[1] = parm[11];
+ }
+ else
+ { arc_costs.parameter[0] = (double)parm[10] / 100.0;
+ arc_costs.parameter[1] = 0.0;
+ }
+ capacities.distribution = parm[12];
+ if (parm[12] == 1)
+ { capacities.parameter[0] = parm[13];
+ capacities.parameter[1] = parm[14];
+ }
+ else
+ { capacities.parameter[0] = (double)parm[13] / 100.0;
+ capacities.parameter[1] = 0.0;
+ }
+ /* Calculate the edge lengths of the grid according to the
+ input. */
+ if (n * n >= n_node)
+ { n1 = n;
+ n2 = (int)((double)n_node / (double)n + 0.5);
+ }
+ else
+ { n2 = n;
+ n1 = (int)((double)n_node / (double)n + 0.5);
+ }
+ /* Recalculate the total number of nodes and plus 1 for the super
+ node. */
+ n_node = n1 * n2 + 1;
+ n_arc = n_node * avg_degree;
+ n_grid_arc = (two_way + 1) * ((n1 - 1) * n2 + (n2 - 1) * n1) +
+ n_source + n_sink;
+ if (n_grid_arc > n_arc) n_arc = n_grid_arc;
+ arc_list = xcalloc(n_arc, sizeof(struct arcs));
+ source_list = xcalloc(n_source, sizeof(struct imbalance));
+ sink_list = xcalloc(n_sink, sizeof(struct imbalance));
+ /* Generate a random network. */
+ generate(csa);
+ /* Output the network. */
+ output(csa);
+ /* Free all allocated memory. */
+ xfree(arc_list);
+ xfree(source_list);
+ xfree(sink_list);
+ /* The instance has been successfully generated. */
+ ret = 0;
+done: return ret;
+}
+
+#undef random
+
+static void assign_capacities(struct csa *csa)
+{ /* Assign a capacity to each arc. */
+ struct arcs *arc_ptr = arc_list;
+ int (*random)(struct csa *csa, double *);
+ int i;
+ /* Determine the random number generator to use. */
+ switch (arc_costs.distribution)
+ { case UNIFORM:
+ random = uniform;
+ break;
+ case EXPONENTIAL:
+ random = exponential;
+ break;
+ default:
+ xassert(csa != csa);
+ }
+ /* Assign capacities to grid arcs. */
+ for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++)
+ arc_ptr->u = random(csa, capacities.parameter);
+ i = i - n_source - n_sink;
+ /* Assign capacities to arcs to/from supernode. */
+ for (; i < n_grid_arc; i++, arc_ptr++)
+ arc_ptr->u = t_supply;
+ /* Assign capacities to all other arcs. */
+ for (; i < n_arc; i++, arc_ptr++)
+ arc_ptr->u = random(csa, capacities.parameter);
+ return;
+}
+
+static void assign_costs(struct csa *csa)
+{ /* Assign a cost to each arc. */
+ struct arcs *arc_ptr = arc_list;
+ int (*random)(struct csa *csa, double *);
+ int i;
+ /* A high cost assigned to arcs to/from the supernode. */
+ int high_cost;
+ /* The maximum cost assigned to arcs in the base grid. */
+ int max_cost = 0;
+ /* Determine the random number generator to use. */
+ switch (arc_costs.distribution)
+ { case UNIFORM:
+ random = uniform;
+ break;
+ case EXPONENTIAL:
+ random = exponential;
+ break;
+ default:
+ xassert(csa != csa);
+ }
+ /* Assign costs to arcs in the base grid. */
+ for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++)
+ { arc_ptr->cost = random(csa, arc_costs.parameter);
+ if (max_cost < arc_ptr->cost) max_cost = arc_ptr->cost;
+ }
+ i = i - n_source - n_sink;
+ /* Assign costs to arcs to/from the super node. */
+ high_cost = max_cost * 2;
+ for (; i < n_grid_arc; i++, arc_ptr++)
+ arc_ptr->cost = high_cost;
+ /* Assign costs to all other arcs. */
+ for (; i < n_arc; i++, arc_ptr++)
+ arc_ptr->cost = random(csa, arc_costs.parameter);
+ return;
+}
+
+static void assign_imbalance(struct csa *csa)
+{ /* Assign an imbalance to each node. */
+ int total, i;
+ double avg;
+ struct imbalance *ptr;
+ /* assign the supply nodes */
+ avg = 2.0 * t_supply / n_source;
+ do
+ { for (i = 1, total = t_supply, ptr = source_list + 1;
+ i < n_source; i++, ptr++)
+ { ptr->supply = (int)(randy(csa) * avg + 0.5);
+ total -= ptr->supply;
+ }
+ source_list->supply = total;
+ }
+ /* redo all if the assignment "overshooted" */
+ while (total <= 0);
+ /* assign the demand nodes */
+ avg = -2.0 * t_supply / n_sink;
+ do
+ { for (i = 1, total = t_supply, ptr = sink_list + 1;
+ i < n_sink; i++, ptr++)
+ { ptr->supply = (int)(randy(csa) * avg - 0.5);
+ total += ptr->supply;
+ }
+ sink_list->supply = - total;
+ }
+ while (total <= 0);
+ return;
+}
+
+static int exponential(struct csa *csa, double lambda[1])
+{ /* Returns an "exponentially distributed" integer with parameter
+ lambda. */
+ return ((int)(- lambda[0] * log((double)randy(csa)) + 0.5));
+}
+
+static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs
+ *arc_ptr)
+{ /* Generate an arc from each source to the supernode and from
+ supernode to each sink. */
+ int i;
+ for (i = 0; i < n_source; i++, arc_ptr++)
+ { arc_ptr->from = source_list[i].node;
+ arc_ptr->to = n_node;
+ }
+ for (i = 0; i < n_sink; i++, arc_ptr++)
+ { arc_ptr->to = sink_list[i].node;
+ arc_ptr->from = n_node;
+ }
+ return arc_ptr;
+}
+
+static struct arcs *gen_basic_grid(struct csa *csa, struct arcs
+ *arc_ptr)
+{ /* Generate the basic grid. */
+ int direction = 1, i, j, k;
+ if (two_way)
+ { /* Generate an arc in each direction. */
+ for (i = 1; i < n_node; i += n1)
+ { for (j = i, k = j + n1 - 1; j < k; j++)
+ { arc_ptr->from = j;
+ arc_ptr->to = j + 1;
+ arc_ptr++;
+ arc_ptr->from = j + 1;
+ arc_ptr->to = j;
+ arc_ptr++;
+ }
+ }
+ for (i = 1; i <= n1; i++)
+ { for (j = i + n1; j < n_node; j += n1)
+ { arc_ptr->from = j;
+ arc_ptr->to = j - n1;
+ arc_ptr++;
+ arc_ptr->from = j - n1;
+ arc_ptr->to = j;
+ arc_ptr++;
+ }
+ }
+ }
+ else
+ { /* Generate one arc in each direction. */
+ for (i = 1; i < n_node; i += n1)
+ { if (direction == 1)
+ j = i;
+ else
+ j = i + 1;
+ for (k = j + n1 - 1; j < k; j++)
+ { arc_ptr->from = j;
+ arc_ptr->to = j + direction;
+ arc_ptr++;
+ }
+ direction = - direction;
+ }
+ for (i = 1; i <= n1; i++)
+ { j = i + n1;
+ if (direction == 1)
+ { for (; j < n_node; j += n1)
+ { arc_ptr->from = j - n1;
+ arc_ptr->to = j;
+ arc_ptr++;
+ }
+ }
+ else
+ { for (; j < n_node; j += n1)
+ { arc_ptr->from = j - n1;
+ arc_ptr->to = j;
+ arc_ptr++;
+ }
+ }
+ direction = - direction;
+ }
+ }
+ return arc_ptr;
+}
+
+static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr)
+{ /* Generate random arcs to meet the specified density. */
+ int i;
+ double ab[2];
+ ab[0] = 0.9;
+ ab[1] = n_node - 0.99; /* upper limit is n_node-1 because the
+ supernode cannot be selected */
+ for (i = n_grid_arc; i < n_arc; i++, arc_ptr++)
+ { arc_ptr->from = uniform(csa, ab);
+ arc_ptr->to = uniform(csa, ab);
+ if (arc_ptr->from == arc_ptr->to)
+ { arc_ptr--;
+ i--;
+ }
+ }
+ return;
+}
+
+static void generate(struct csa *csa)
+{ /* Generate a random network. */
+ struct arcs *arc_ptr = arc_list;
+ arc_ptr = gen_basic_grid(csa, arc_ptr);
+ select_source_sinks(csa);
+ arc_ptr = gen_additional_arcs(csa, arc_ptr);
+ gen_more_arcs(csa, arc_ptr);
+ assign_costs(csa);
+ assign_capacities(csa);
+ assign_imbalance(csa);
+ return;
+}
+
+static void output(struct csa *csa)
+{ /* Output the network in DIMACS format. */
+ struct arcs *arc_ptr;
+ struct imbalance *imb_ptr;
+ int i;
+ if (G != NULL) goto skip;
+ /* Output "c", "p" records. */
+ xprintf("c generated by GRIDGEN\n");
+ xprintf("c seed %d\n", seed_original);
+ xprintf("c nodes %d\n", n_node);
+ xprintf("c grid size %d X %d\n", n1, n2);
+ xprintf("c sources %d sinks %d\n", n_source, n_sink);
+ xprintf("c avg. degree %d\n", avg_degree);
+ xprintf("c supply %d\n", t_supply);
+ switch (arc_costs.distribution)
+ { case UNIFORM:
+ xprintf("c arc costs: UNIFORM distr. min %d max %d\n",
+ (int)arc_costs.parameter[0],
+ (int)arc_costs.parameter[1]);
+ break;
+ case EXPONENTIAL:
+ xprintf("c arc costs: EXPONENTIAL distr. lambda %d\n",
+ (int)arc_costs.parameter[0]);
+ break;
+ default:
+ xassert(csa != csa);
+ }
+ switch (capacities.distribution)
+ { case UNIFORM:
+ xprintf("c arc caps : UNIFORM distr. min %d max %d\n",
+ (int)capacities.parameter[0],
+ (int)capacities.parameter[1]);
+ break;
+ case EXPONENTIAL:
+ xprintf("c arc caps : EXPONENTIAL distr. %d lambda %d\n",
+ (int)capacities.parameter[0]);
+ break;
+ default:
+ xassert(csa != csa);
+ }
+skip: if (G == NULL)
+ xprintf("p min %d %d\n", n_node, n_arc);
+ else
+ { glp_add_vertices(G, n_node);
+ if (v_rhs >= 0)
+ { double zero = 0.0;
+ for (i = 1; i <= n_node; i++)
+ { glp_vertex *v = G->v[i];
+ memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
+ }
+ }
+ }
+ /* Output "n node supply". */
+ for (i = 0, imb_ptr = source_list; i < n_source; i++, imb_ptr++)
+ { if (G == NULL)
+ xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply);
+ else
+ { if (v_rhs >= 0)
+ { double temp = (double)imb_ptr->supply;
+ glp_vertex *v = G->v[imb_ptr->node];
+ memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+ }
+ }
+ }
+ for (i = 0, imb_ptr = sink_list; i < n_sink; i++, imb_ptr++)
+ { if (G == NULL)
+ xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply);
+ else
+ { if (v_rhs >= 0)
+ { double temp = (double)imb_ptr->supply;
+ glp_vertex *v = G->v[imb_ptr->node];
+ memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+ }
+ }
+ }
+ /* Output "a from to lowcap=0 hicap cost". */
+ for (i = 0, arc_ptr = arc_list; i < n_arc; i++, arc_ptr++)
+ { if (G == NULL)
+ xprintf("a %d %d 0 %d %d\n", arc_ptr->from, arc_ptr->to,
+ arc_ptr->u, arc_ptr->cost);
+ else
+ { glp_arc *a = glp_add_arc(G, arc_ptr->from, arc_ptr->to);
+ if (a_cap >= 0)
+ { double temp = (double)arc_ptr->u;
+ memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+ }
+ if (a_cost >= 0)
+ { double temp = (double)arc_ptr->cost;
+ memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+ }
+ }
+ }
+ return;
+}
+
+static double randy(struct csa *csa)
+{ /* Returns a random number between 0.0 and 1.0.
+ See Ward Cheney & David Kincaid, "Numerical Mathematics and
+ Computing," 2Ed, pp. 335. */
+ seed = 16807 * seed % 2147483647;
+ if (seed < 0) seed = - seed;
+ return seed * 4.6566128752459e-10;
+}
+
+static void select_source_sinks(struct csa *csa)
+{ /* Randomly select the source nodes and sink nodes. */
+ int i, *int_ptr;
+ int *temp_list; /* a temporary list of nodes */
+ struct imbalance *ptr;
+ double ab[2]; /* parameter for random number generator */
+ ab[0] = 0.9;
+ ab[1] = n_node - 0.99; /* upper limit is n_node-1 because the
+ supernode cannot be selected */
+ temp_list = xcalloc(n_node, sizeof(int));
+ for (i = 0, int_ptr = temp_list; i < n_node; i++, int_ptr++)
+ *int_ptr = 0;
+ /* Select the source nodes. */
+ for (i = 0, ptr = source_list; i < n_source; i++, ptr++)
+ { ptr->node = uniform(csa, ab);
+ if (temp_list[ptr->node] == 1) /* check for duplicates */
+ { ptr--;
+ i--;
+ }
+ else
+ temp_list[ptr->node] = 1;
+ }
+ /* Select the sink nodes. */
+ for (i = 0, ptr = sink_list; i < n_sink; i++, ptr++)
+ { ptr->node = uniform(csa, ab);
+ if (temp_list[ptr->node] == 1)
+ { ptr--;
+ i--;
+ }
+ else
+ temp_list[ptr->node] = 1;
+ }
+ xfree(temp_list);
+ return;
+}
+
+int uniform(struct csa *csa, double a[2])
+{ /* Generates an integer uniformly selected from [a[0],a[1]]. */
+ return (int)((a[1] - a[0]) * randy(csa) + a[0] + 0.5);
+}
+
+/**********************************************************************/
+
+#if 0
+int main(void)
+{ int parm[1+14];
+ double temp;
+ scanf("%d", &parm[1]);
+ scanf("%d", &parm[2]);
+ scanf("%d", &parm[3]);
+ scanf("%d", &parm[4]);
+ scanf("%d", &parm[5]);
+ scanf("%d", &parm[6]);
+ scanf("%d", &parm[7]);
+ scanf("%d", &parm[8]);
+ scanf("%d", &parm[9]);
+ if (parm[9] == 1)
+ { scanf("%d", &parm[10]);
+ scanf("%d", &parm[11]);
+ }
+ else
+ { scanf("%le", &temp);
+ parm[10] = (int)(100.0 * temp + .5);
+ parm[11] = 0;
+ }
+ scanf("%d", &parm[12]);
+ if (parm[12] == 1)
+ { scanf("%d", &parm[13]);
+ scanf("%d", &parm[14]);
+ }
+ else
+ { scanf("%le", &temp);
+ parm[13] = (int)(100.0 * temp + .5);
+ parm[14] = 0;
+ }
+ glp_gridgen(NULL, 0, 0, 0, parm);
+ return 0;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/intfeas1.c b/test/monniaux/glpk-4.65/src/api/intfeas1.c
new file mode 100644
index 00000000..43064351
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/intfeas1.c
@@ -0,0 +1,267 @@
+/* intfeas1.c (solve integer feasibility problem) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2011-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+int glp_intfeas1(glp_prob *P, int use_bound, int obj_bound)
+{ /* solve integer feasibility problem */
+ NPP *npp = NULL;
+ glp_prob *mip = NULL;
+ int *obj_ind = NULL;
+ double *obj_val = NULL;
+ int obj_row = 0;
+ int i, j, k, obj_len, temp, ret;
+#if 0 /* 04/IV-2016 */
+ /* check the problem object */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_intfeas1: P = %p; invalid problem object\n",
+ P);
+#endif
+ if (P->tree != NULL)
+ xerror("glp_intfeas1: operation not allowed\n");
+ /* integer solution is currently undefined */
+ P->mip_stat = GLP_UNDEF;
+ P->mip_obj = 0.0;
+ /* check columns (variables) */
+ for (j = 1; j <= P->n; j++)
+ { GLPCOL *col = P->col[j];
+#if 0 /* binarization is not yet implemented */
+ if (!(col->kind == GLP_IV || col->type == GLP_FX))
+ { xprintf("glp_intfeas1: column %d: non-integer non-fixed var"
+ "iable not allowed\n", j);
+#else
+ if (!((col->kind == GLP_IV && col->lb == 0.0 && col->ub == 1.0)
+ || col->type == GLP_FX))
+ { xprintf("glp_intfeas1: column %d: non-binary non-fixed vari"
+ "able not allowed\n", j);
+#endif
+ ret = GLP_EDATA;
+ goto done;
+ }
+ temp = (int)col->lb;
+ if ((double)temp != col->lb)
+ { if (col->type == GLP_FX)
+ xprintf("glp_intfeas1: column %d: fixed value %g is non-"
+ "integer or out of range\n", j, col->lb);
+ else
+ xprintf("glp_intfeas1: column %d: lower bound %g is non-"
+ "integer or out of range\n", j, col->lb);
+ ret = GLP_EDATA;
+ goto done;
+ }
+ temp = (int)col->ub;
+ if ((double)temp != col->ub)
+ { xprintf("glp_intfeas1: column %d: upper bound %g is non-int"
+ "eger or out of range\n", j, col->ub);
+ ret = GLP_EDATA;
+ goto done;
+ }
+ if (col->type == GLP_DB && col->lb > col->ub)
+ { xprintf("glp_intfeas1: column %d: lower bound %g is greater"
+ " than upper bound %g\n", j, col->lb, col->ub);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ /* check rows (constraints) */
+ for (i = 1; i <= P->m; i++)
+ { GLPROW *row = P->row[i];
+ GLPAIJ *aij;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { temp = (int)aij->val;
+ if ((double)temp != aij->val)
+ { xprintf("glp_intfeas1: row = %d, column %d: constraint c"
+ "oefficient %g is non-integer or out of range\n",
+ i, aij->col->j, aij->val);
+ ret = GLP_EDATA;
+ goto done;
+ }
+ }
+ temp = (int)row->lb;
+ if ((double)temp != row->lb)
+ { if (row->type == GLP_FX)
+ xprintf("glp_intfeas1: row = %d: fixed value %g is non-i"
+ "nteger or out of range\n", i, row->lb);
+ else
+ xprintf("glp_intfeas1: row = %d: lower bound %g is non-i"
+ "nteger or out of range\n", i, row->lb);
+ ret = GLP_EDATA;
+ goto done;
+ }
+ temp = (int)row->ub;
+ if ((double)temp != row->ub)
+ { xprintf("glp_intfeas1: row = %d: upper bound %g is non-inte"
+ "ger or out of range\n", i, row->ub);
+ ret = GLP_EDATA;
+ goto done;
+ }
+ if (row->type == GLP_DB && row->lb > row->ub)
+ { xprintf("glp_intfeas1: row %d: lower bound %g is greater th"
+ "an upper bound %g\n", i, row->lb, row->ub);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ /* check the objective function */
+#if 1 /* 08/I-2017 by cmatraki & mao */
+ if (!use_bound)
+ { /* skip check if no obj. bound is specified */
+ goto skip;
+ }
+#endif
+ temp = (int)P->c0;
+ if ((double)temp != P->c0)
+ { xprintf("glp_intfeas1: objective constant term %g is non-integ"
+ "er or out of range\n", P->c0);
+ ret = GLP_EDATA;
+ goto done;
+ }
+ for (j = 1; j <= P->n; j++)
+ { temp = (int)P->col[j]->coef;
+ if ((double)temp != P->col[j]->coef)
+ { xprintf("glp_intfeas1: column %d: objective coefficient is "
+ "non-integer or out of range\n", j, P->col[j]->coef);
+ ret = GLP_EDATA;
+ goto done;
+ }
+ }
+#if 1 /* 08/I-2017 by cmatraki & mao */
+skip: ;
+#endif
+ /* save the objective function and set it to zero */
+ obj_ind = xcalloc(1+P->n, sizeof(int));
+ obj_val = xcalloc(1+P->n, sizeof(double));
+ obj_len = 0;
+ obj_ind[0] = 0;
+ obj_val[0] = P->c0;
+ P->c0 = 0.0;
+ for (j = 1; j <= P->n; j++)
+ { if (P->col[j]->coef != 0.0)
+ { obj_len++;
+ obj_ind[obj_len] = j;
+ obj_val[obj_len] = P->col[j]->coef;
+ P->col[j]->coef = 0.0;
+ }
+ }
+ /* add inequality to bound the objective function, if required */
+ if (!use_bound)
+ xprintf("Will search for ANY feasible solution\n");
+ else
+ { xprintf("Will search only for solution not worse than %d\n",
+ obj_bound);
+ obj_row = glp_add_rows(P, 1);
+ glp_set_mat_row(P, obj_row, obj_len, obj_ind, obj_val);
+ if (P->dir == GLP_MIN)
+ glp_set_row_bnds(P, obj_row,
+ GLP_UP, 0.0, (double)obj_bound - obj_val[0]);
+ else if (P->dir == GLP_MAX)
+ glp_set_row_bnds(P, obj_row,
+ GLP_LO, (double)obj_bound - obj_val[0], 0.0);
+ else
+ xassert(P != P);
+ }
+ /* create preprocessor workspace */
+ xprintf("Translating to CNF-SAT...\n");
+ xprintf("Original problem has %d row%s, %d column%s, and %d non-z"
+ "ero%s\n", P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" :
+ "s", P->nnz, P->nnz == 1 ? "" : "s");
+ npp = npp_create_wksp();
+ /* load the original problem into the preprocessor workspace */
+ npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF);
+ /* perform translation to SAT-CNF problem instance */
+ ret = npp_sat_encode_prob(npp);
+ if (ret == 0)
+ ;
+ else if (ret == GLP_ENOPFS)
+ xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n");
+ else if (ret == GLP_ERANGE)
+ xprintf("glp_intfeas1: translation to SAT-CNF failed because o"
+ "f integer overflow\n");
+ else
+ xassert(ret != ret);
+ if (ret != 0)
+ goto done;
+ /* build SAT-CNF problem instance and try to solve it */
+ mip = glp_create_prob();
+ npp_build_prob(npp, mip);
+ ret = glp_minisat1(mip);
+ /* only integer feasible solution can be postprocessed */
+ if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS))
+ { P->mip_stat = mip->mip_stat;
+ goto done;
+ }
+ /* postprocess the solution found */
+ npp_postprocess(npp, mip);
+ /* the transformed problem is no longer needed */
+ glp_delete_prob(mip), mip = NULL;
+ /* store solution to the original problem object */
+ npp_unload_sol(npp, P);
+ /* change the solution status to 'integer feasible' */
+ P->mip_stat = GLP_FEAS;
+ /* check integer feasibility */
+ for (i = 1; i <= P->m; i++)
+ { GLPROW *row;
+ GLPAIJ *aij;
+ double sum;
+ row = P->row[i];
+ sum = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ sum += aij->val * aij->col->mipx;
+ xassert(sum == row->mipx);
+ if (row->type == GLP_LO || row->type == GLP_DB ||
+ row->type == GLP_FX)
+ xassert(sum >= row->lb);
+ if (row->type == GLP_UP || row->type == GLP_DB ||
+ row->type == GLP_FX)
+ xassert(sum <= row->ub);
+ }
+ /* compute value of the original objective function */
+ P->mip_obj = obj_val[0];
+ for (k = 1; k <= obj_len; k++)
+ P->mip_obj += obj_val[k] * P->col[obj_ind[k]]->mipx;
+ xprintf("Objective value = %17.9e\n", P->mip_obj);
+done: /* delete the transformed problem, if it exists */
+ if (mip != NULL)
+ glp_delete_prob(mip);
+ /* delete the preprocessor workspace, if it exists */
+ if (npp != NULL)
+ npp_delete_wksp(npp);
+ /* remove inequality used to bound the objective function */
+ if (obj_row > 0)
+ { int ind[1+1];
+ ind[1] = obj_row;
+ glp_del_rows(P, 1, ind);
+ }
+ /* restore the original objective function */
+ if (obj_ind != NULL)
+ { P->c0 = obj_val[0];
+ for (k = 1; k <= obj_len; k++)
+ P->col[obj_ind[k]]->coef = obj_val[k];
+ xfree(obj_ind);
+ xfree(obj_val);
+ }
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/maxffalg.c b/test/monniaux/glpk-4.65/src/api/maxffalg.c
new file mode 100644
index 00000000..0f3f9b04
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/maxffalg.c
@@ -0,0 +1,130 @@
+/* maxffalg.c (find maximal flow with Ford-Fulkerson algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ffalg.h"
+#include "glpk.h"
+
+int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
+ double *sol, int a_x, int v_cut)
+{ /* find maximal flow with Ford-Fulkerson algorithm */
+ glp_vertex *v;
+ glp_arc *a;
+ int nv, na, i, k, flag, *tail, *head, *cap, *x, ret;
+ char *cut;
+ double temp;
+ if (!(1 <= s && s <= G->nv))
+ xerror("glp_maxflow_ffalg: s = %d; source node number out of r"
+ "ange\n", s);
+ if (!(1 <= t && t <= G->nv))
+ xerror("glp_maxflow_ffalg: t = %d: sink node number out of ran"
+ "ge\n", t);
+ if (s == t)
+ xerror("glp_maxflow_ffalg: s = t = %d; source and sink nodes m"
+ "ust be distinct\n", s);
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_maxflow_ffalg: a_cap = %d; invalid offset\n",
+ a_cap);
+ if (v_cut >= 0 && v_cut > G->v_size - (int)sizeof(int))
+ xerror("glp_maxflow_ffalg: v_cut = %d; invalid offset\n",
+ v_cut);
+ /* allocate working arrays */
+ nv = G->nv;
+ na = G->na;
+ tail = xcalloc(1+na, sizeof(int));
+ head = xcalloc(1+na, sizeof(int));
+ cap = xcalloc(1+na, sizeof(int));
+ x = xcalloc(1+na, sizeof(int));
+ if (v_cut < 0)
+ cut = NULL;
+ else
+ cut = xcalloc(1+nv, sizeof(char));
+ /* copy the flow network */
+ k = 0;
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { k++;
+ tail[k] = a->tail->i;
+ head[k] = a->head->i;
+ if (tail[k] == head[k])
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ if (a_cap >= 0)
+ memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
+ else
+ temp = 1.0;
+ if (!(0.0 <= temp && temp <= (double)INT_MAX &&
+ temp == floor(temp)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ cap[k] = (int)temp;
+ }
+ }
+ xassert(k == na);
+ /* find maximal flow in the flow network */
+ ffalg(nv, na, tail, head, s, t, cap, x, cut);
+ ret = 0;
+ /* store solution components */
+ /* (objective function = total flow through the network) */
+ if (sol != NULL)
+ { temp = 0.0;
+ for (k = 1; k <= na; k++)
+ { if (tail[k] == s)
+ temp += (double)x[k];
+ else if (head[k] == s)
+ temp -= (double)x[k];
+ }
+ *sol = temp;
+ }
+ /* (arc flows) */
+ if (a_x >= 0)
+ { k = 0;
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { temp = (double)x[++k];
+ memcpy((char *)a->data + a_x, &temp, sizeof(double));
+ }
+ }
+ }
+ /* (node flags) */
+ if (v_cut >= 0)
+ { for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ flag = cut[i];
+ memcpy((char *)v->data + v_cut, &flag, sizeof(int));
+ }
+ }
+done: /* free working arrays */
+ xfree(tail);
+ xfree(head);
+ xfree(cap);
+ xfree(x);
+ if (cut != NULL) xfree(cut);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/maxflp.c b/test/monniaux/glpk-4.65/src/api/maxflp.c
new file mode 100644
index 00000000..1135b78c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/maxflp.c
@@ -0,0 +1,114 @@
+/* maxflp.c (convert maximum flow problem to LP) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_maxflow_lp - convert maximum flow problem to LP
+*
+* SYNOPSIS
+*
+* void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
+* int t, int a_cap);
+*
+* DESCRIPTION
+*
+* The routine glp_maxflow_lp builds an LP problem, which corresponds
+* to the maximum flow problem on the specified network G. */
+
+void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
+ int t, int a_cap)
+{ glp_vertex *v;
+ glp_arc *a;
+ int i, j, type, ind[1+2];
+ double cap, val[1+2];
+ if (!(names == GLP_ON || names == GLP_OFF))
+ xerror("glp_maxflow_lp: names = %d; invalid parameter\n",
+ names);
+ if (!(1 <= s && s <= G->nv))
+ xerror("glp_maxflow_lp: s = %d; source node number out of rang"
+ "e\n", s);
+ if (!(1 <= t && t <= G->nv))
+ xerror("glp_maxflow_lp: t = %d: sink node number out of range "
+ "\n", t);
+ if (s == t)
+ xerror("glp_maxflow_lp: s = t = %d; source and sink nodes must"
+ " be distinct\n", s);
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_maxflow_lp: a_cap = %d; invalid offset\n", a_cap);
+ glp_erase_prob(lp);
+ if (names) glp_set_prob_name(lp, G->name);
+ glp_set_obj_dir(lp, GLP_MAX);
+ glp_add_rows(lp, G->nv);
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ if (names) glp_set_row_name(lp, i, v->name);
+ if (i == s)
+ type = GLP_LO;
+ else if (i == t)
+ type = GLP_UP;
+ else
+ type = GLP_FX;
+ glp_set_row_bnds(lp, i, type, 0.0, 0.0);
+ }
+ if (G->na > 0) glp_add_cols(lp, G->na);
+ for (i = 1, j = 0; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { j++;
+ if (names)
+ { char name[50+1];
+ sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
+ xassert(strlen(name) < sizeof(name));
+ glp_set_col_name(lp, j, name);
+ }
+ if (a->tail->i != a->head->i)
+ { ind[1] = a->tail->i, val[1] = +1.0;
+ ind[2] = a->head->i, val[2] = -1.0;
+ glp_set_mat_col(lp, j, 2, ind, val);
+ }
+ if (a_cap >= 0)
+ memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+ else
+ cap = 1.0;
+ if (cap == DBL_MAX)
+ type = GLP_LO;
+ else if (cap != 0.0)
+ type = GLP_DB;
+ else
+ type = GLP_FX;
+ glp_set_col_bnds(lp, j, type, 0.0, cap);
+ if (a->tail->i == s)
+ glp_set_obj_coef(lp, j, +1.0);
+ else if (a->head->i == s)
+ glp_set_obj_coef(lp, j, -1.0);
+ }
+ }
+ xassert(j == G->na);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/mcflp.c b/test/monniaux/glpk-4.65/src/api/mcflp.c
new file mode 100644
index 00000000..5cd24060
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/mcflp.c
@@ -0,0 +1,114 @@
+/* mcflp.c (convert minimum cost flow problem to LP) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_mincost_lp - convert minimum cost flow problem to LP
+*
+* SYNOPSIS
+*
+* void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names,
+* int v_rhs, int a_low, int a_cap, int a_cost);
+*
+* DESCRIPTION
+*
+* The routine glp_mincost_lp builds an LP problem, which corresponds
+* to the minimum cost flow problem on the specified network G. */
+
+void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, int v_rhs,
+ int a_low, int a_cap, int a_cost)
+{ glp_vertex *v;
+ glp_arc *a;
+ int i, j, type, ind[1+2];
+ double rhs, low, cap, cost, val[1+2];
+ if (!(names == GLP_ON || names == GLP_OFF))
+ xerror("glp_mincost_lp: names = %d; invalid parameter\n",
+ names);
+ if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+ xerror("glp_mincost_lp: v_rhs = %d; invalid offset\n", v_rhs);
+ if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_lp: a_low = %d; invalid offset\n", a_low);
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_lp: a_cap = %d; invalid offset\n", a_cap);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_lp: a_cost = %d; invalid offset\n", a_cost)
+ ;
+ glp_erase_prob(lp);
+ if (names) glp_set_prob_name(lp, G->name);
+ if (G->nv > 0) glp_add_rows(lp, G->nv);
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ if (names) glp_set_row_name(lp, i, v->name);
+ if (v_rhs >= 0)
+ memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
+ else
+ rhs = 0.0;
+ glp_set_row_bnds(lp, i, GLP_FX, rhs, rhs);
+ }
+ if (G->na > 0) glp_add_cols(lp, G->na);
+ for (i = 1, j = 0; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { j++;
+ if (names)
+ { char name[50+1];
+ sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
+ xassert(strlen(name) < sizeof(name));
+ glp_set_col_name(lp, j, name);
+ }
+ if (a->tail->i != a->head->i)
+ { ind[1] = a->tail->i, val[1] = +1.0;
+ ind[2] = a->head->i, val[2] = -1.0;
+ glp_set_mat_col(lp, j, 2, ind, val);
+ }
+ if (a_low >= 0)
+ memcpy(&low, (char *)a->data + a_low, sizeof(double));
+ else
+ low = 0.0;
+ if (a_cap >= 0)
+ memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+ else
+ cap = 1.0;
+ if (cap == DBL_MAX)
+ type = GLP_LO;
+ else if (low != cap)
+ type = GLP_DB;
+ else
+ type = GLP_FX;
+ glp_set_col_bnds(lp, j, type, low, cap);
+ if (a_cost >= 0)
+ memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+ else
+ cost = 0.0;
+ glp_set_obj_coef(lp, j, cost);
+ }
+ }
+ xassert(j == G->na);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/mcfokalg.c b/test/monniaux/glpk-4.65/src/api/mcfokalg.c
new file mode 100644
index 00000000..786dc71b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/mcfokalg.c
@@ -0,0 +1,221 @@
+/* mcfokalg.c (find minimum-cost flow with out-of-kilter algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+#include "okalg.h"
+
+int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
+ int a_cost, double *sol, int a_x, int v_pi)
+{ /* find minimum-cost flow with out-of-kilter algorithm */
+ glp_vertex *v;
+ glp_arc *a;
+ int nv, na, i, k, s, t, *tail, *head, *low, *cap, *cost, *x, *pi,
+ ret;
+ double sum, temp;
+ if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+ xerror("glp_mincost_okalg: v_rhs = %d; invalid offset\n",
+ v_rhs);
+ if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_okalg: a_low = %d; invalid offset\n",
+ a_low);
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_okalg: a_cap = %d; invalid offset\n",
+ a_cap);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_okalg: a_cost = %d; invalid offset\n",
+ a_cost);
+ if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_okalg: a_x = %d; invalid offset\n", a_x);
+ if (v_pi >= 0 && v_pi > G->v_size - (int)sizeof(double))
+ xerror("glp_mincost_okalg: v_pi = %d; invalid offset\n", v_pi);
+ /* s is artificial source node */
+ s = G->nv + 1;
+ /* t is artificial sink node */
+ t = s + 1;
+ /* nv is the total number of nodes in the resulting network */
+ nv = t;
+ /* na is the total number of arcs in the resulting network */
+ na = G->na + 1;
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ if (v_rhs >= 0)
+ memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
+ else
+ temp = 0.0;
+ if (temp != 0.0) na++;
+ }
+ /* allocate working arrays */
+ tail = xcalloc(1+na, sizeof(int));
+ head = xcalloc(1+na, sizeof(int));
+ low = xcalloc(1+na, sizeof(int));
+ cap = xcalloc(1+na, sizeof(int));
+ cost = xcalloc(1+na, sizeof(int));
+ x = xcalloc(1+na, sizeof(int));
+ pi = xcalloc(1+nv, sizeof(int));
+ /* construct the resulting network */
+ k = 0;
+ /* (original arcs) */
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { k++;
+ tail[k] = a->tail->i;
+ head[k] = a->head->i;
+ if (tail[k] == head[k])
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ if (a_low >= 0)
+ memcpy(&temp, (char *)a->data + a_low, sizeof(double));
+ else
+ temp = 0.0;
+ if (!(0.0 <= temp && temp <= (double)INT_MAX &&
+ temp == floor(temp)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ low[k] = (int)temp;
+ if (a_cap >= 0)
+ memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
+ else
+ temp = 1.0;
+ if (!((double)low[k] <= temp && temp <= (double)INT_MAX &&
+ temp == floor(temp)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ cap[k] = (int)temp;
+ if (a_cost >= 0)
+ memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
+ else
+ temp = 0.0;
+ if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ cost[k] = (int)temp;
+ }
+ }
+ /* (artificial arcs) */
+ sum = 0.0;
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ if (v_rhs >= 0)
+ memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
+ else
+ temp = 0.0;
+ if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ if (temp > 0.0)
+ { /* artificial arc from s to original source i */
+ k++;
+ tail[k] = s;
+ head[k] = i;
+ low[k] = cap[k] = (int)(+temp); /* supply */
+ cost[k] = 0;
+ sum += (double)temp;
+ }
+ else if (temp < 0.0)
+ { /* artificial arc from original sink i to t */
+ k++;
+ tail[k] = i;
+ head[k] = t;
+ low[k] = cap[k] = (int)(-temp); /* demand */
+ cost[k] = 0;
+ }
+ }
+ /* (feedback arc from t to s) */
+ k++;
+ xassert(k == na);
+ tail[k] = t;
+ head[k] = s;
+ if (sum > (double)INT_MAX)
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ low[k] = cap[k] = (int)sum; /* total supply/demand */
+ cost[k] = 0;
+ /* find minimal-cost circulation in the resulting network */
+ ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
+ switch (ret)
+ { case 0:
+ /* optimal circulation found */
+ ret = 0;
+ break;
+ case 1:
+ /* no feasible circulation exists */
+ ret = GLP_ENOPFS;
+ break;
+ case 2:
+ /* integer overflow occured */
+ ret = GLP_ERANGE;
+ goto done;
+ case 3:
+ /* optimality test failed (logic error) */
+ ret = GLP_EFAIL;
+ goto done;
+ default:
+ xassert(ret != ret);
+ }
+ /* store solution components */
+ /* (objective function = the total cost) */
+ if (sol != NULL)
+ { temp = 0.0;
+ for (k = 1; k <= na; k++)
+ temp += (double)cost[k] * (double)x[k];
+ *sol = temp;
+ }
+ /* (arc flows) */
+ if (a_x >= 0)
+ { k = 0;
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { temp = (double)x[++k];
+ memcpy((char *)a->data + a_x, &temp, sizeof(double));
+ }
+ }
+ }
+ /* (node potentials = Lagrange multipliers) */
+ if (v_pi >= 0)
+ { for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ temp = - (double)pi[i];
+ memcpy((char *)v->data + v_pi, &temp, sizeof(double));
+ }
+ }
+done: /* free working arrays */
+ xfree(tail);
+ xfree(head);
+ xfree(low);
+ xfree(cap);
+ xfree(cost);
+ xfree(x);
+ xfree(pi);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/mcfrelax.c b/test/monniaux/glpk-4.65/src/api/mcfrelax.c
new file mode 100644
index 00000000..9b34949a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/mcfrelax.c
@@ -0,0 +1,251 @@
+/* mcfrelax.c (find minimum-cost flow with RELAX-IV) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2013-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+#include "relax4.h"
+
+static int overflow(int u, int v)
+{ /* check for integer overflow on computing u + v */
+ if (u > 0 && v > 0 && u + v < 0) return 1;
+ if (u < 0 && v < 0 && u + v > 0) return 1;
+ return 0;
+}
+
+int glp_mincost_relax4(glp_graph *G, int v_rhs, int a_low, int a_cap,
+ int a_cost, int crash, double *sol, int a_x, int a_rc)
+{ /* find minimum-cost flow with Bertsekas-Tseng relaxation method
+ (RELAX-IV) */
+ glp_vertex *v;
+ glp_arc *a;
+ struct relax4_csa csa;
+ int i, k, large, n, na, ret;
+ double cap, cost, low, rc, rhs, sum, x;
+ if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+ xerror("glp_mincost_relax4: v_rhs = %d; invalid offset\n",
+ v_rhs);
+ if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_relax4: a_low = %d; invalid offset\n",
+ a_low);
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_relax4: a_cap = %d; invalid offset\n",
+ a_cap);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_relax4: a_cost = %d; invalid offset\n",
+ a_cost);
+ if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_relax4: a_x = %d; invalid offset\n",
+ a_x);
+ if (a_rc >= 0 && a_rc > G->a_size - (int)sizeof(double))
+ xerror("glp_mincost_relax4: a_rc = %d; invalid offset\n",
+ a_rc);
+ csa.n = n = G->nv; /* number of nodes */
+ csa.na = na = G->na; /* number of arcs */
+ csa.large = large = INT_MAX / 4;
+ csa.repeat = 0;
+ csa.crash = crash;
+ /* allocate working arrays */
+ csa.startn = xcalloc(1+na, sizeof(int));
+ csa.endn = xcalloc(1+na, sizeof(int));
+ csa.fou = xcalloc(1+n, sizeof(int));
+ csa.nxtou = xcalloc(1+na, sizeof(int));
+ csa.fin = xcalloc(1+n, sizeof(int));
+ csa.nxtin = xcalloc(1+na, sizeof(int));
+ csa.rc = xcalloc(1+na, sizeof(int));
+ csa.u = xcalloc(1+na, sizeof(int));
+ csa.dfct = xcalloc(1+n, sizeof(int));
+ csa.x = xcalloc(1+na, sizeof(int));
+ csa.label = xcalloc(1+n, sizeof(int));
+ csa.prdcsr = xcalloc(1+n, sizeof(int));
+ csa.save = xcalloc(1+na, sizeof(int));
+ csa.tfstou = xcalloc(1+n, sizeof(int));
+ csa.tnxtou = xcalloc(1+na, sizeof(int));
+ csa.tfstin = xcalloc(1+n, sizeof(int));
+ csa.tnxtin = xcalloc(1+na, sizeof(int));
+ csa.nxtqueue = xcalloc(1+n, sizeof(int));
+ csa.scan = xcalloc(1+n, sizeof(char));
+ csa.mark = xcalloc(1+n, sizeof(char));
+ if (crash)
+ { csa.extend_arc = xcalloc(1+n, sizeof(int));
+ csa.sb_level = xcalloc(1+n, sizeof(int));
+ csa.sb_arc = xcalloc(1+n, sizeof(int));
+ }
+ else
+ { csa.extend_arc = NULL;
+ csa.sb_level = NULL;
+ csa.sb_arc = NULL;
+ }
+ /* scan nodes */
+ for (i = 1; i <= n; i++)
+ { v = G->v[i];
+ /* get supply at i-th node */
+ if (v_rhs >= 0)
+ memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
+ else
+ rhs = 0.0;
+ if (!(fabs(rhs) <= (double)large && rhs == floor(rhs)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ /* set demand at i-th node */
+ csa.dfct[i] = -(int)rhs;
+ }
+ /* scan arcs */
+ k = 0;
+ for (i = 1; i <= n; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { k++;
+ /* set endpoints of k-th arc */
+ if (a->tail->i == a->head->i)
+ { /* self-loops not allowed */
+ ret = GLP_EDATA;
+ goto done;
+ }
+ csa.startn[k] = a->tail->i;
+ csa.endn[k] = a->head->i;
+ /* set per-unit cost for k-th arc flow */
+ if (a_cost >= 0)
+ memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+ else
+ cost = 0.0;
+ if (!(fabs(cost) <= (double)large && cost == floor(cost)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ csa.rc[k] = (int)cost;
+ /* get lower bound for k-th arc flow */
+ if (a_low >= 0)
+ memcpy(&low, (char *)a->data + a_low, sizeof(double));
+ else
+ low = 0.0;
+ if (!(0.0 <= low && low <= (double)large &&
+ low == floor(low)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ /* get upper bound for k-th arc flow */
+ if (a_cap >= 0)
+ memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+ else
+ cap = 1.0;
+ if (!(low <= cap && cap <= (double)large &&
+ cap == floor(cap)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ /* substitute x = x' + low, where 0 <= x' <= cap - low */
+ csa.u[k] = (int)(cap - low);
+ /* correct demands at endpoints of k-th arc */
+ if (overflow(csa.dfct[a->tail->i], +low))
+ { ret = GLP_ERANGE;
+ goto done;
+ }
+#if 0 /* 29/IX-2017 */
+ csa.dfct[a->tail->i] += low;
+#else
+ csa.dfct[a->tail->i] += (int)low;
+#endif
+ if (overflow(csa.dfct[a->head->i], -low))
+ { ret = GLP_ERANGE;
+ goto done;
+ }
+#if 0 /* 29/IX-2017 */
+ csa.dfct[a->head->i] -= low;
+#else
+ csa.dfct[a->head->i] -= (int)low;
+#endif
+ }
+ }
+ /* construct linked list for network topology */
+ relax4_inidat(&csa);
+ /* find minimum-cost flow */
+ ret = relax4(&csa);
+ if (ret != 0)
+ { /* problem is found to be infeasible */
+ xassert(1 <= ret && ret <= 8);
+ ret = GLP_ENOPFS;
+ goto done;
+ }
+ /* store solution */
+ sum = 0.0;
+ k = 0;
+ for (i = 1; i <= n; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { k++;
+ /* get lower bound for k-th arc flow */
+ if (a_low >= 0)
+ memcpy(&low, (char *)a->data + a_low, sizeof(double));
+ else
+ low = 0.0;
+ /* store original flow x = x' + low thru k-th arc */
+ x = (double)csa.x[k] + low;
+ if (a_x >= 0)
+ memcpy((char *)a->data + a_x, &x, sizeof(double));
+ /* store reduced cost for k-th arc flow */
+ rc = (double)csa.rc[k];
+ if (a_rc >= 0)
+ memcpy((char *)a->data + a_rc, &rc, sizeof(double));
+ /* get per-unit cost for k-th arc flow */
+ if (a_cost >= 0)
+ memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+ else
+ cost = 0.0;
+ /* compute the total cost */
+ sum += cost * x;
+ }
+ }
+ /* store the total cost */
+ if (sol != NULL)
+ *sol = sum;
+done: /* free working arrays */
+ xfree(csa.startn);
+ xfree(csa.endn);
+ xfree(csa.fou);
+ xfree(csa.nxtou);
+ xfree(csa.fin);
+ xfree(csa.nxtin);
+ xfree(csa.rc);
+ xfree(csa.u);
+ xfree(csa.dfct);
+ xfree(csa.x);
+ xfree(csa.label);
+ xfree(csa.prdcsr);
+ xfree(csa.save);
+ xfree(csa.tfstou);
+ xfree(csa.tnxtou);
+ xfree(csa.tfstin);
+ xfree(csa.tnxtin);
+ xfree(csa.nxtqueue);
+ xfree(csa.scan);
+ xfree(csa.mark);
+ if (crash)
+ { xfree(csa.extend_arc);
+ xfree(csa.sb_level);
+ xfree(csa.sb_arc);
+ }
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/minisat1.c b/test/monniaux/glpk-4.65/src/api/minisat1.c
new file mode 100644
index 00000000..a669c487
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/minisat1.c
@@ -0,0 +1,161 @@
+/* minisat1.c (driver to MiniSat solver) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2011-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "minisat.h"
+#include "prob.h"
+
+int glp_minisat1(glp_prob *P)
+{ /* solve CNF-SAT problem with MiniSat solver */
+ solver *s;
+ GLPAIJ *aij;
+ int i, j, len, ret, *ind;
+ double sum;
+#if 0 /* 04/IV-2016 */
+ /* check problem object */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_minisat1: P = %p; invalid problem object\n",
+ P);
+#endif
+ if (P->tree != NULL)
+ xerror("glp_minisat1: operation not allowed\n");
+ /* integer solution is currently undefined */
+ P->mip_stat = GLP_UNDEF;
+ P->mip_obj = 0.0;
+ /* check that problem object encodes CNF-SAT instance */
+ if (glp_check_cnfsat(P) != 0)
+ { xprintf("glp_minisat1: problem object does not encode CNF-SAT "
+ "instance\n");
+ ret = GLP_EDATA;
+ goto done;
+ }
+#if 0 /* 08/I-2017 by cmatraki */
+#if 1 /* 07/XI-2015 */
+ if (sizeof(void *) != sizeof(int))
+ { xprintf("glp_minisat1: sorry, MiniSat solver is not supported "
+ "on 64-bit platforms\n");
+ ret = GLP_EFAIL;
+ goto done;
+ }
+#endif
+#else
+ if (sizeof(void *) != sizeof(size_t))
+ { xprintf("glp_minisat1: sorry, MiniSat solver is not supported "
+ "on this platform\n");
+ ret = GLP_EFAIL;
+ goto done;
+ }
+#endif
+ /* solve CNF-SAT problem */
+ xprintf("Solving CNF-SAT problem...\n");
+ xprintf("Instance has %d variable%s, %d clause%s, and %d literal%"
+ "s\n", P->n, P->n == 1 ? "" : "s", P->m, P->m == 1 ? "" : "s",
+ P->nnz, P->nnz == 1 ? "" : "s");
+ /* if CNF-SAT has no clauses, it is satisfiable */
+ if (P->m == 0)
+ { P->mip_stat = GLP_OPT;
+ for (j = 1; j <= P->n; j++)
+ P->col[j]->mipx = 0.0;
+ goto fini;
+ }
+ /* if CNF-SAT has an empty clause, it is unsatisfiable */
+ for (i = 1; i <= P->m; i++)
+ { if (P->row[i]->ptr == NULL)
+ { P->mip_stat = GLP_NOFEAS;
+ goto fini;
+ }
+ }
+ /* prepare input data for the solver */
+ s = solver_new();
+ solver_setnvars(s, P->n);
+ ind = xcalloc(1+P->n, sizeof(int));
+ for (i = 1; i <= P->m; i++)
+ { len = 0;
+ for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ { ind[++len] = toLit(aij->col->j-1);
+ if (aij->val < 0.0)
+ ind[len] = lit_neg(ind[len]);
+ }
+ xassert(len > 0);
+#if 0 /* 08/I-2017 by cmatraki */
+ xassert(solver_addclause(s, &ind[1], &ind[1+len]));
+#else
+ if (!solver_addclause(s, &ind[1], &ind[1+len]))
+ { /* found trivial conflict */
+ xfree(ind);
+ solver_delete(s);
+ P->mip_stat = GLP_NOFEAS;
+ goto fini;
+ }
+#endif
+ }
+ xfree(ind);
+ /* call the solver */
+ s->verbosity = 1;
+ if (solver_solve(s, 0, 0))
+ { /* instance is reported as satisfiable */
+ P->mip_stat = GLP_OPT;
+ /* copy solution to the problem object */
+ xassert(s->model.size == P->n);
+ for (j = 1; j <= P->n; j++)
+ { P->col[j]->mipx =
+ s->model.ptr[j-1] == l_True ? 1.0 : 0.0;
+ }
+ /* compute row values */
+ for (i = 1; i <= P->m; i++)
+ { sum = 0;
+ for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ sum += aij->val * aij->col->mipx;
+ P->row[i]->mipx = sum;
+ }
+ /* check integer feasibility */
+ for (i = 1; i <= P->m; i++)
+ { if (P->row[i]->mipx < P->row[i]->lb)
+ { /* solution is wrong */
+ P->mip_stat = GLP_UNDEF;
+ break;
+ }
+ }
+ }
+ else
+ { /* instance is reported as unsatisfiable */
+ P->mip_stat = GLP_NOFEAS;
+ }
+ solver_delete(s);
+fini: /* report the instance status */
+ if (P->mip_stat == GLP_OPT)
+ { xprintf("SATISFIABLE\n");
+ ret = 0;
+ }
+ else if (P->mip_stat == GLP_NOFEAS)
+ { xprintf("UNSATISFIABLE\n");
+ ret = 0;
+ }
+ else
+ { xprintf("glp_minisat1: solver failed\n");
+ ret = GLP_EFAIL;
+ }
+done: return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/mpl.c b/test/monniaux/glpk-4.65/src/api/mpl.c
new file mode 100644
index 00000000..cfa6f75b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/mpl.c
@@ -0,0 +1,269 @@
+/* mpl.c (processing model in GNU MathProg language) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2008-2016 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/>.
+***********************************************************************/
+
+#include "mpl.h"
+#include "prob.h"
+
+glp_tran *glp_mpl_alloc_wksp(void)
+{ /* allocate the MathProg translator workspace */
+ glp_tran *tran;
+ tran = mpl_initialize();
+ return tran;
+}
+
+void glp_mpl_init_rand(glp_tran *tran, int seed)
+{ /* initialize pseudo-random number generator */
+ if (tran->phase != 0)
+ xerror("glp_mpl_init_rand: invalid call sequence\n");
+ rng_init_rand(tran->rand, seed);
+ return;
+}
+
+int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip)
+{ /* read and translate model section */
+ int ret;
+ if (tran->phase != 0)
+ xerror("glp_mpl_read_model: invalid call sequence\n");
+ ret = mpl_read_model(tran, (char *)fname, skip);
+ if (ret == 1 || ret == 2)
+ ret = 0;
+ else if (ret == 4)
+ ret = 1;
+ else
+ xassert(ret != ret);
+ return ret;
+}
+
+int glp_mpl_read_data(glp_tran *tran, const char *fname)
+{ /* read and translate data section */
+ int ret;
+ if (!(tran->phase == 1 || tran->phase == 2))
+ xerror("glp_mpl_read_data: invalid call sequence\n");
+ ret = mpl_read_data(tran, (char *)fname);
+ if (ret == 2)
+ ret = 0;
+ else if (ret == 4)
+ ret = 1;
+ else
+ xassert(ret != ret);
+ return ret;
+}
+
+int glp_mpl_generate(glp_tran *tran, const char *fname)
+{ /* generate the model */
+ int ret;
+ if (!(tran->phase == 1 || tran->phase == 2))
+ xerror("glp_mpl_generate: invalid call sequence\n");
+ ret = mpl_generate(tran, (char *)fname);
+ if (ret == 3)
+ ret = 0;
+ else if (ret == 4)
+ ret = 1;
+ return ret;
+}
+
+void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob)
+{ /* build LP/MIP problem instance from the model */
+ int m, n, i, j, t, kind, type, len, *ind;
+ double lb, ub, *val;
+ if (tran->phase != 3)
+ xerror("glp_mpl_build_prob: invalid call sequence\n");
+ /* erase the problem object */
+ glp_erase_prob(prob);
+ /* set problem name */
+ glp_set_prob_name(prob, mpl_get_prob_name(tran));
+ /* build rows (constraints) */
+ m = mpl_get_num_rows(tran);
+ if (m > 0)
+ glp_add_rows(prob, m);
+ for (i = 1; i <= m; i++)
+ { /* set row name */
+ glp_set_row_name(prob, i, mpl_get_row_name(tran, i));
+ /* set row bounds */
+ type = mpl_get_row_bnds(tran, i, &lb, &ub);
+ switch (type)
+ { case MPL_FR: type = GLP_FR; break;
+ case MPL_LO: type = GLP_LO; break;
+ case MPL_UP: type = GLP_UP; break;
+ case MPL_DB: type = GLP_DB; break;
+ case MPL_FX: type = GLP_FX; break;
+ default: xassert(type != type);
+ }
+ if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb)))
+ { type = GLP_FX;
+ if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub;
+ }
+ glp_set_row_bnds(prob, i, type, lb, ub);
+ /* warn about non-zero constant term */
+ if (mpl_get_row_c0(tran, i) != 0.0)
+ xprintf("glp_mpl_build_prob: row %s; constant term %.12g ig"
+ "nored\n",
+ mpl_get_row_name(tran, i), mpl_get_row_c0(tran, i));
+ }
+ /* build columns (variables) */
+ n = mpl_get_num_cols(tran);
+ if (n > 0)
+ glp_add_cols(prob, n);
+ for (j = 1; j <= n; j++)
+ { /* set column name */
+ glp_set_col_name(prob, j, mpl_get_col_name(tran, j));
+ /* set column kind */
+ kind = mpl_get_col_kind(tran, j);
+ switch (kind)
+ { case MPL_NUM:
+ break;
+ case MPL_INT:
+ case MPL_BIN:
+ glp_set_col_kind(prob, j, GLP_IV);
+ break;
+ default:
+ xassert(kind != kind);
+ }
+ /* set column bounds */
+ type = mpl_get_col_bnds(tran, j, &lb, &ub);
+ switch (type)
+ { case MPL_FR: type = GLP_FR; break;
+ case MPL_LO: type = GLP_LO; break;
+ case MPL_UP: type = GLP_UP; break;
+ case MPL_DB: type = GLP_DB; break;
+ case MPL_FX: type = GLP_FX; break;
+ default: xassert(type != type);
+ }
+ if (kind == MPL_BIN)
+ { if (type == GLP_FR || type == GLP_UP || lb < 0.0) lb = 0.0;
+ if (type == GLP_FR || type == GLP_LO || ub > 1.0) ub = 1.0;
+ type = GLP_DB;
+ }
+ if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb)))
+ { type = GLP_FX;
+ if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub;
+ }
+ glp_set_col_bnds(prob, j, type, lb, ub);
+ }
+ /* load the constraint matrix */
+ ind = xcalloc(1+n, sizeof(int));
+ val = xcalloc(1+n, sizeof(double));
+ for (i = 1; i <= m; i++)
+ { len = mpl_get_mat_row(tran, i, ind, val);
+ glp_set_mat_row(prob, i, len, ind, val);
+ }
+ /* build objective function (the first objective is used) */
+ for (i = 1; i <= m; i++)
+ { kind = mpl_get_row_kind(tran, i);
+ if (kind == MPL_MIN || kind == MPL_MAX)
+ { /* set objective name */
+ glp_set_obj_name(prob, mpl_get_row_name(tran, i));
+ /* set optimization direction */
+ glp_set_obj_dir(prob, kind == MPL_MIN ? GLP_MIN : GLP_MAX);
+ /* set constant term */
+ glp_set_obj_coef(prob, 0, mpl_get_row_c0(tran, i));
+ /* set objective coefficients */
+ len = mpl_get_mat_row(tran, i, ind, val);
+ for (t = 1; t <= len; t++)
+ glp_set_obj_coef(prob, ind[t], val[t]);
+ break;
+ }
+ }
+ /* free working arrays */
+ xfree(ind);
+ xfree(val);
+ return;
+}
+
+int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol)
+{ /* postsolve the model */
+ int i, j, m, n, stat, ret;
+ double prim, dual;
+ if (!(tran->phase == 3 && !tran->flag_p))
+ xerror("glp_mpl_postsolve: invalid call sequence\n");
+ if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
+ xerror("glp_mpl_postsolve: sol = %d; invalid parameter\n",
+ sol);
+ m = mpl_get_num_rows(tran);
+ n = mpl_get_num_cols(tran);
+ if (!(m == glp_get_num_rows(prob) &&
+ n == glp_get_num_cols(prob)))
+ xerror("glp_mpl_postsolve: wrong problem object\n");
+ if (!mpl_has_solve_stmt(tran))
+ { ret = 0;
+ goto done;
+ }
+ for (i = 1; i <= m; i++)
+ { if (sol == GLP_SOL)
+ { stat = glp_get_row_stat(prob, i);
+ prim = glp_get_row_prim(prob, i);
+ dual = glp_get_row_dual(prob, i);
+ }
+ else if (sol == GLP_IPT)
+ { stat = 0;
+ prim = glp_ipt_row_prim(prob, i);
+ dual = glp_ipt_row_dual(prob, i);
+ }
+ else if (sol == GLP_MIP)
+ { stat = 0;
+ prim = glp_mip_row_val(prob, i);
+ dual = 0.0;
+ }
+ else
+ xassert(sol != sol);
+ if (fabs(prim) < 1e-9) prim = 0.0;
+ if (fabs(dual) < 1e-9) dual = 0.0;
+ mpl_put_row_soln(tran, i, stat, prim, dual);
+ }
+ for (j = 1; j <= n; j++)
+ { if (sol == GLP_SOL)
+ { stat = glp_get_col_stat(prob, j);
+ prim = glp_get_col_prim(prob, j);
+ dual = glp_get_col_dual(prob, j);
+ }
+ else if (sol == GLP_IPT)
+ { stat = 0;
+ prim = glp_ipt_col_prim(prob, j);
+ dual = glp_ipt_col_dual(prob, j);
+ }
+ else if (sol == GLP_MIP)
+ { stat = 0;
+ prim = glp_mip_col_val(prob, j);
+ dual = 0.0;
+ }
+ else
+ xassert(sol != sol);
+ if (fabs(prim) < 1e-9) prim = 0.0;
+ if (fabs(dual) < 1e-9) dual = 0.0;
+ mpl_put_col_soln(tran, j, stat, prim, dual);
+ }
+ ret = mpl_postsolve(tran);
+ if (ret == 3)
+ ret = 0;
+ else if (ret == 4)
+ ret = 1;
+done: return ret;
+}
+
+void glp_mpl_free_wksp(glp_tran *tran)
+{ /* free the MathProg translator workspace */
+ mpl_terminate(tran);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/mps.c b/test/monniaux/glpk-4.65/src/api/mps.c
new file mode 100644
index 00000000..3bdc6db1
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/mps.c
@@ -0,0 +1,1452 @@
+/* mps.c (MPS format routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2008-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "misc.h"
+#include "prob.h"
+
+#define xfprintf glp_format
+
+/***********************************************************************
+* NAME
+*
+* glp_init_mpscp - initialize MPS format control parameters
+*
+* SYNOPSIS
+*
+* void glp_init_mpscp(glp_mpscp *parm);
+*
+* DESCRIPTION
+*
+* The routine glp_init_mpscp initializes control parameters, which are
+* used by the MPS input/output routines glp_read_mps and glp_write_mps,
+* with default values.
+*
+* Default values of the control parameters are stored in the glp_mpscp
+* structure, which the parameter parm points to. */
+
+void glp_init_mpscp(glp_mpscp *parm)
+{ parm->blank = '\0';
+ parm->obj_name = NULL;
+ parm->tol_mps = 1e-12;
+ return;
+}
+
+static void check_parm(const char *func, const glp_mpscp *parm)
+{ /* check control parameters */
+ if (!(0x00 <= parm->blank && parm->blank <= 0xFF) ||
+ !(parm->blank == '\0' || isprint(parm->blank)))
+ xerror("%s: blank = 0x%02X; invalid parameter\n",
+ func, parm->blank);
+ if (!(parm->obj_name == NULL || strlen(parm->obj_name) <= 255))
+ xerror("%s: obj_name = \"%.12s...\"; parameter too long\n",
+ func, parm->obj_name);
+ if (!(0.0 <= parm->tol_mps && parm->tol_mps < 1.0))
+ xerror("%s: tol_mps = %g; invalid parameter\n",
+ func, parm->tol_mps);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_read_mps - read problem data in MPS format
+*
+* SYNOPSIS
+*
+* int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+* const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_read_mps reads problem data in MPS format from a
+* text file.
+*
+* The parameter fmt specifies the version of MPS format:
+*
+* GLP_MPS_DECK - fixed (ancient) MPS format;
+* GLP_MPS_FILE - free (modern) MPS format.
+*
+* The parameter parm is a pointer to the structure glp_mpscp, which
+* specifies control parameters used by the routine. If parm is NULL,
+* the routine uses default settings.
+*
+* The character string fname specifies a name of the text file to be
+* read.
+*
+* Note that before reading data the current content of the problem
+* object is completely erased with the routine glp_erase_prob.
+*
+* RETURNS
+*
+* If the operation was successful, the routine glp_read_mps returns
+* zero. Otherwise, it prints an error message and returns non-zero. */
+
+struct csa
+{ /* common storage area */
+ glp_prob *P;
+ /* pointer to problem object */
+ int deck;
+ /* MPS format (0 - free, 1 - fixed) */
+ const glp_mpscp *parm;
+ /* pointer to control parameters */
+ const char *fname;
+ /* name of input MPS file */
+ glp_file *fp;
+ /* stream assigned to input MPS file */
+ jmp_buf jump;
+ /* label for go to in case of error */
+ int recno;
+ /* current record (card) number */
+ int recpos;
+ /* current record (card) position */
+ int c;
+ /* current character */
+ int fldno;
+ /* current field number */
+ char field[255+1];
+ /* current field content */
+ int w80;
+ /* warning 'record must not be longer than 80 chars' issued */
+ int wef;
+ /* warning 'extra fields detected beyond field 6' issued */
+ int obj_row;
+ /* objective row number */
+ void *work1, *work2, *work3;
+ /* working arrays */
+};
+
+static void error(struct csa *csa, const char *fmt, ...)
+{ /* print error message and terminate processing */
+ va_list arg;
+ xprintf("%s:%d: ", csa->fname, csa->recno);
+ va_start(arg, fmt);
+ xvprintf(fmt, arg);
+ va_end(arg);
+ longjmp(csa->jump, 1);
+ /* no return */
+}
+
+static void warning(struct csa *csa, const char *fmt, ...)
+{ /* print warning message and continue processing */
+ va_list arg;
+ xprintf("%s:%d: warning: ", csa->fname, csa->recno);
+ va_start(arg, fmt);
+ xvprintf(fmt, arg);
+ va_end(arg);
+ return;
+}
+
+static void read_char(struct csa *csa)
+{ /* read next character */
+ int c;
+ if (csa->c == '\n')
+ csa->recno++, csa->recpos = 0;
+ csa->recpos++;
+read: c = glp_getc(csa->fp);
+ if (c < 0)
+ { if (glp_ioerr(csa->fp))
+ error(csa, "read error - %s\n", get_err_msg());
+ else if (csa->c == '\n')
+ error(csa, "unexpected end of file\n");
+ else
+ { warning(csa, "missing final end of line\n");
+ c = '\n';
+ }
+ }
+ else if (c == '\n')
+ ;
+ else if (csa->c == '\r')
+ { c = '\r';
+ goto badc;
+ }
+ else if (csa->deck && c == '\r')
+ { csa->c = '\r';
+ goto read;
+ }
+ else if (c == ' ')
+ ;
+ else if (isspace(c))
+ { if (csa->deck)
+badc: error(csa, "in fixed MPS format white-space character 0x%02"
+ "X is not allowed\n", c);
+ c = ' ';
+ }
+ else if (iscntrl(c))
+ error(csa, "invalid control character 0x%02X\n", c);
+ if (csa->deck && csa->recpos == 81 && c != '\n' && csa->w80 < 1)
+ { warning(csa, "in fixed MPS format record must not be longer th"
+ "an 80 characters\n");
+ csa->w80++;
+ }
+ csa->c = c;
+ return;
+}
+
+static int indicator(struct csa *csa, int name)
+{ /* skip comment records and read possible indicator record */
+ int ret;
+ /* reset current field number */
+ csa->fldno = 0;
+loop: /* read the very first character of the next record */
+ xassert(csa->c == '\n');
+ read_char(csa);
+ if (csa->c == ' ' || csa->c == '\n')
+ { /* data record */
+ ret = 0;
+ }
+ else if (csa->c == '*')
+ { /* comment record */
+ while (csa->c != '\n')
+ read_char(csa);
+ goto loop;
+ }
+ else
+ { /* indicator record */
+ int len = 0;
+ while (csa->c != ' ' && csa->c != '\n' && len < 12)
+ { csa->field[len++] = (char)csa->c;
+ read_char(csa);
+ }
+ csa->field[len] = '\0';
+ if (!(strcmp(csa->field, "NAME") == 0 ||
+ strcmp(csa->field, "ROWS") == 0 ||
+ strcmp(csa->field, "COLUMNS") == 0 ||
+ strcmp(csa->field, "RHS") == 0 ||
+ strcmp(csa->field, "RANGES") == 0 ||
+ strcmp(csa->field, "BOUNDS") == 0 ||
+ strcmp(csa->field, "ENDATA") == 0))
+ error(csa, "invalid indicator record\n");
+ if (!name)
+ { while (csa->c != '\n')
+ read_char(csa);
+ }
+ ret = 1;
+ }
+ return ret;
+}
+
+static void read_field(struct csa *csa)
+{ /* read next field of the current data record */
+ csa->fldno++;
+ if (csa->deck)
+ { /* fixed MPS format */
+ int beg, end, pos;
+ /* determine predefined field positions */
+ if (csa->fldno == 1)
+ beg = 2, end = 3;
+ else if (csa->fldno == 2)
+ beg = 5, end = 12;
+ else if (csa->fldno == 3)
+ beg = 15, end = 22;
+ else if (csa->fldno == 4)
+ beg = 25, end = 36;
+ else if (csa->fldno == 5)
+ beg = 40, end = 47;
+ else if (csa->fldno == 6)
+ beg = 50, end = 61;
+ else
+ xassert(csa != csa);
+ /* skip blanks preceding the current field */
+ if (csa->c != '\n')
+ { pos = csa->recpos;
+ while (csa->recpos < beg)
+ { if (csa->c == ' ')
+ ;
+ else if (csa->c == '\n')
+ break;
+ else
+ error(csa, "in fixed MPS format positions %d-%d must "
+ "be blank\n", pos, beg-1);
+ read_char(csa);
+ }
+ }
+ /* skip possible comment beginning in the field 3 or 5 */
+ if ((csa->fldno == 3 || csa->fldno == 5) && csa->c == '$')
+ { while (csa->c != '\n')
+ read_char(csa);
+ }
+ /* read the current field */
+ for (pos = beg; pos <= end; pos++)
+ { if (csa->c == '\n') break;
+ csa->field[pos-beg] = (char)csa->c;
+ read_char(csa);
+ }
+ csa->field[pos-beg] = '\0';
+ strtrim(csa->field);
+ /* skip blanks following the last field */
+ if (csa->fldno == 6 && csa->c != '\n')
+ { while (csa->recpos <= 72)
+ { if (csa->c == ' ')
+ ;
+ else if (csa->c == '\n')
+ break;
+ else
+ error(csa, "in fixed MPS format positions 62-72 must "
+ "be blank\n");
+ read_char(csa);
+ }
+ while (csa->c != '\n')
+ read_char(csa);
+ }
+ }
+ else
+ { /* free MPS format */
+ int len;
+ /* skip blanks preceding the current field */
+ while (csa->c == ' ')
+ read_char(csa);
+ /* skip possible comment */
+ if (csa->c == '$')
+ { while (csa->c != '\n')
+ read_char(csa);
+ }
+ /* read the current field */
+ len = 0;
+ while (!(csa->c == ' ' || csa->c == '\n'))
+ { if (len == 255)
+ error(csa, "length of field %d exceeds 255 characters\n",
+ csa->fldno++);
+ csa->field[len++] = (char)csa->c;
+ read_char(csa);
+ }
+ csa->field[len] = '\0';
+ /* skip anything following the last field (any extra fields
+ are considered to be comments) */
+ if (csa->fldno == 6)
+ { while (csa->c == ' ')
+ read_char(csa);
+ if (csa->c != '$' && csa->c != '\n' && csa->wef < 1)
+ { warning(csa, "some extra field(s) detected beyond field "
+ "6; field(s) ignored\n");
+ csa->wef++;
+ }
+ while (csa->c != '\n')
+ read_char(csa);
+ }
+ }
+ return;
+}
+
+static void patch_name(struct csa *csa, char *name)
+{ /* process embedded blanks in symbolic name */
+ int blank = csa->parm->blank;
+ if (blank == '\0')
+ { /* remove emedded blanks */
+ strspx(name);
+ }
+ else
+ { /* replace embedded blanks by specified character */
+ for (; *name != '\0'; name++)
+ if (*name == ' ') *name = (char)blank;
+ }
+ return;
+}
+
+static double read_number(struct csa *csa)
+{ /* read next field and convert it to floating-point number */
+ double x;
+ char *s;
+ /* read next field */
+ read_field(csa);
+ xassert(csa->fldno == 4 || csa->fldno == 6);
+ if (csa->field[0] == '\0')
+ error(csa, "missing numeric value in field %d\n", csa->fldno);
+ /* skip initial spaces of the field */
+ for (s = csa->field; *s == ' '; s++);
+ /* perform conversion */
+ if (str2num(s, &x) != 0)
+ error(csa, "cannot convert '%s' to floating-point number\n",
+ s);
+ return x;
+}
+
+static void skip_field(struct csa *csa)
+{ /* read and skip next field (assumed to be blank) */
+ read_field(csa);
+ if (csa->field[0] != '\0')
+ error(csa, "field %d must be blank\n", csa->fldno);
+ return;
+}
+
+static void read_name(struct csa *csa)
+{ /* read NAME indicator record */
+ if (!(indicator(csa, 1) && strcmp(csa->field, "NAME") == 0))
+ error(csa, "missing NAME indicator record\n");
+ /* this indicator record looks like a data record; simulate that
+ fields 1 and 2 were read */
+ csa->fldno = 2;
+ /* field 3: model name */
+ read_field(csa), patch_name(csa, csa->field);
+ if (csa->field[0] == '\0')
+ warning(csa, "missing model name in field 3\n");
+ else
+ glp_set_prob_name(csa->P, csa->field);
+ /* skip anything following field 3 */
+ while (csa->c != '\n')
+ read_char(csa);
+ return;
+}
+
+static void read_rows(struct csa *csa)
+{ /* read ROWS section */
+ int i, type;
+loop: if (indicator(csa, 0)) goto done;
+ /* field 1: row type */
+ read_field(csa), strspx(csa->field);
+ if (strcmp(csa->field, "N") == 0)
+ type = GLP_FR;
+ else if (strcmp(csa->field, "G") == 0)
+ type = GLP_LO;
+ else if (strcmp(csa->field, "L") == 0)
+ type = GLP_UP;
+ else if (strcmp(csa->field, "E") == 0)
+ type = GLP_FX;
+ else if (csa->field[0] == '\0')
+ error(csa, "missing row type in field 1\n");
+ else
+ error(csa, "invalid row type in field 1\n");
+ /* field 2: row name */
+ read_field(csa), patch_name(csa, csa->field);
+ if (csa->field[0] == '\0')
+ error(csa, "missing row name in field 2\n");
+ if (glp_find_row(csa->P, csa->field) != 0)
+ error(csa, "row '%s' multiply specified\n", csa->field);
+ i = glp_add_rows(csa->P, 1);
+ glp_set_row_name(csa->P, i, csa->field);
+ glp_set_row_bnds(csa->P, i, type, 0.0, 0.0);
+ /* fields 3, 4, 5, and 6 must be blank */
+ skip_field(csa);
+ skip_field(csa);
+ skip_field(csa);
+ skip_field(csa);
+ goto loop;
+done: return;
+}
+
+static void read_columns(struct csa *csa)
+{ /* read COLUMNS section */
+ int i, j, f, len, kind = GLP_CV, *ind;
+ double aij, *val;
+ char name[255+1], *flag;
+ /* allocate working arrays */
+ csa->work1 = ind = xcalloc(1+csa->P->m, sizeof(int));
+ csa->work2 = val = xcalloc(1+csa->P->m, sizeof(double));
+ csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
+ memset(&flag[1], 0, csa->P->m);
+ /* no current column exists */
+ j = 0, len = 0;
+loop: if (indicator(csa, 0)) goto done;
+ /* field 1 must be blank */
+ if (csa->deck)
+ { read_field(csa);
+ if (csa->field[0] != '\0')
+ error(csa, "field 1 must be blank\n");
+ }
+ else
+ csa->fldno++;
+ /* field 2: column or kind name */
+ read_field(csa), patch_name(csa, csa->field);
+ strcpy(name, csa->field);
+ /* field 3: row name or keyword 'MARKER' */
+ read_field(csa), patch_name(csa, csa->field);
+ if (strcmp(csa->field, "'MARKER'") == 0)
+ { /* process kind data record */
+ /* field 4 must be blank */
+ if (csa->deck)
+ { read_field(csa);
+ if (csa->field[0] != '\0')
+ error(csa, "field 4 must be blank\n");
+ }
+ else
+ csa->fldno++;
+ /* field 5: keyword 'INTORG' or 'INTEND' */
+ read_field(csa), patch_name(csa, csa->field);
+ if (strcmp(csa->field, "'INTORG'") == 0)
+ kind = GLP_IV;
+ else if (strcmp(csa->field, "'INTEND'") == 0)
+ kind = GLP_CV;
+ else if (csa->field[0] == '\0')
+ error(csa, "missing keyword in field 5\n");
+ else
+ error(csa, "invalid keyword in field 5\n");
+ /* field 6 must be blank */
+ skip_field(csa);
+ goto loop;
+ }
+ /* process column name specified in field 2 */
+ if (name[0] == '\0')
+ { /* the same column as in previous data record */
+ if (j == 0)
+ error(csa, "missing column name in field 2\n");
+ }
+ else if (j != 0 && strcmp(name, csa->P->col[j]->name) == 0)
+ { /* the same column as in previous data record */
+ xassert(j != 0);
+ }
+ else
+ { /* store the current column */
+ if (j != 0)
+ { glp_set_mat_col(csa->P, j, len, ind, val);
+ while (len > 0) flag[ind[len--]] = 0;
+ }
+ /* create new column */
+ if (glp_find_col(csa->P, name) != 0)
+ error(csa, "column '%s' multiply specified\n", name);
+ j = glp_add_cols(csa->P, 1);
+ glp_set_col_name(csa->P, j, name);
+ glp_set_col_kind(csa->P, j, kind);
+ if (kind == GLP_CV)
+ glp_set_col_bnds(csa->P, j, GLP_LO, 0.0, 0.0);
+ else if (kind == GLP_IV)
+ glp_set_col_bnds(csa->P, j, GLP_DB, 0.0, 1.0);
+ else
+ xassert(kind != kind);
+ }
+ /* process fields 3-4 and 5-6 */
+ for (f = 3; f <= 5; f += 2)
+ { /* field 3 or 5: row name */
+ if (f == 3)
+ { if (csa->field[0] == '\0')
+ error(csa, "missing row name in field 3\n");
+ }
+ else
+ { read_field(csa), patch_name(csa, csa->field);
+ if (csa->field[0] == '\0')
+ { /* if field 5 is blank, field 6 also must be blank */
+ skip_field(csa);
+ continue;
+ }
+ }
+ i = glp_find_row(csa->P, csa->field);
+ if (i == 0)
+ error(csa, "row '%s' not found\n", csa->field);
+ if (flag[i])
+ error(csa, "duplicate coefficient in row '%s'\n",
+ csa->field);
+ /* field 4 or 6: coefficient value */
+ aij = read_number(csa);
+ if (fabs(aij) < csa->parm->tol_mps) aij = 0.0;
+ len++, ind[len] = i, val[len] = aij, flag[i] = 1;
+ }
+ goto loop;
+done: /* store the last column */
+ if (j != 0)
+ glp_set_mat_col(csa->P, j, len, ind, val);
+ /* free working arrays */
+ xfree(ind);
+ xfree(val);
+ xfree(flag);
+ csa->work1 = csa->work2 = csa->work3 = NULL;
+ return;
+}
+
+static void read_rhs(struct csa *csa)
+{ /* read RHS section */
+ int i, f, v, type;
+ double rhs;
+ char name[255+1], *flag;
+ /* allocate working array */
+ csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
+ memset(&flag[1], 0, csa->P->m);
+ /* no current RHS vector exists */
+ v = 0;
+loop: if (indicator(csa, 0)) goto done;
+ /* field 1 must be blank */
+ if (csa->deck)
+ { read_field(csa);
+ if (csa->field[0] != '\0')
+ error(csa, "field 1 must be blank\n");
+ }
+ else
+ csa->fldno++;
+ /* field 2: RHS vector name */
+ read_field(csa), patch_name(csa, csa->field);
+ if (csa->field[0] == '\0')
+ { /* the same RHS vector as in previous data record */
+ if (v == 0)
+ { warning(csa, "missing RHS vector name in field 2\n");
+ goto blnk;
+ }
+ }
+ else if (v != 0 && strcmp(csa->field, name) == 0)
+ { /* the same RHS vector as in previous data record */
+ xassert(v != 0);
+ }
+ else
+blnk: { /* new RHS vector */
+ if (v != 0)
+ error(csa, "multiple RHS vectors not supported\n");
+ v++;
+ strcpy(name, csa->field);
+ }
+ /* process fields 3-4 and 5-6 */
+ for (f = 3; f <= 5; f += 2)
+ { /* field 3 or 5: row name */
+ read_field(csa), patch_name(csa, csa->field);
+ if (csa->field[0] == '\0')
+ { if (f == 3)
+ error(csa, "missing row name in field 3\n");
+ else
+ { /* if field 5 is blank, field 6 also must be blank */
+ skip_field(csa);
+ continue;
+ }
+ }
+ i = glp_find_row(csa->P, csa->field);
+ if (i == 0)
+ error(csa, "row '%s' not found\n", csa->field);
+ if (flag[i])
+ error(csa, "duplicate right-hand side for row '%s'\n",
+ csa->field);
+ /* field 4 or 6: right-hand side value */
+ rhs = read_number(csa);
+ if (fabs(rhs) < csa->parm->tol_mps) rhs = 0.0;
+ type = csa->P->row[i]->type;
+ if (type == GLP_FR)
+ { if (i == csa->obj_row)
+ glp_set_obj_coef(csa->P, 0, rhs);
+ else if (rhs != 0.0)
+ warning(csa, "non-zero right-hand side for free row '%s'"
+ " ignored\n", csa->P->row[i]->name);
+ }
+ else
+ glp_set_row_bnds(csa->P, i, type, rhs, rhs);
+ flag[i] = 1;
+ }
+ goto loop;
+done: /* free working array */
+ xfree(flag);
+ csa->work3 = NULL;
+ return;
+}
+
+static void read_ranges(struct csa *csa)
+{ /* read RANGES section */
+ int i, f, v, type;
+ double rhs, rng;
+ char name[255+1], *flag;
+ /* allocate working array */
+ csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
+ memset(&flag[1], 0, csa->P->m);
+ /* no current RANGES vector exists */
+ v = 0;
+loop: if (indicator(csa, 0)) goto done;
+ /* field 1 must be blank */
+ if (csa->deck)
+ { read_field(csa);
+ if (csa->field[0] != '\0')
+ error(csa, "field 1 must be blank\n");
+ }
+ else
+ csa->fldno++;
+ /* field 2: RANGES vector name */
+ read_field(csa), patch_name(csa, csa->field);
+ if (csa->field[0] == '\0')
+ { /* the same RANGES vector as in previous data record */
+ if (v == 0)
+ { warning(csa, "missing RANGES vector name in field 2\n");
+ goto blnk;
+ }
+ }
+ else if (v != 0 && strcmp(csa->field, name) == 0)
+ { /* the same RANGES vector as in previous data record */
+ xassert(v != 0);
+ }
+ else
+blnk: { /* new RANGES vector */
+ if (v != 0)
+ error(csa, "multiple RANGES vectors not supported\n");
+ v++;
+ strcpy(name, csa->field);
+ }
+ /* process fields 3-4 and 5-6 */
+ for (f = 3; f <= 5; f += 2)
+ { /* field 3 or 5: row name */
+ read_field(csa), patch_name(csa, csa->field);
+ if (csa->field[0] == '\0')
+ { if (f == 3)
+ error(csa, "missing row name in field 3\n");
+ else
+ { /* if field 5 is blank, field 6 also must be blank */
+ skip_field(csa);
+ continue;
+ }
+ }
+ i = glp_find_row(csa->P, csa->field);
+ if (i == 0)
+ error(csa, "row '%s' not found\n", csa->field);
+ if (flag[i])
+ error(csa, "duplicate range for row '%s'\n", csa->field);
+ /* field 4 or 6: range value */
+ rng = read_number(csa);
+ if (fabs(rng) < csa->parm->tol_mps) rng = 0.0;
+ type = csa->P->row[i]->type;
+ if (type == GLP_FR)
+ warning(csa, "range for free row '%s' ignored\n",
+ csa->P->row[i]->name);
+ else if (type == GLP_LO)
+ { rhs = csa->P->row[i]->lb;
+#if 0 /* 26/V-2017 by cmatraki */
+ glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
+#else
+ glp_set_row_bnds(csa->P, i, rng == 0.0 ? GLP_FX : GLP_DB,
+#endif
+ rhs, rhs + fabs(rng));
+ }
+ else if (type == GLP_UP)
+ { rhs = csa->P->row[i]->ub;
+#if 0 /* 26/V-2017 by cmatraki */
+ glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
+#else
+ glp_set_row_bnds(csa->P, i, rng == 0.0 ? GLP_FX : GLP_DB,
+#endif
+ rhs - fabs(rng), rhs);
+ }
+ else if (type == GLP_FX)
+ { rhs = csa->P->row[i]->lb;
+ if (rng > 0.0)
+ glp_set_row_bnds(csa->P, i, GLP_DB, rhs, rhs + rng);
+ else if (rng < 0.0)
+ glp_set_row_bnds(csa->P, i, GLP_DB, rhs + rng, rhs);
+ }
+ else
+ xassert(type != type);
+ flag[i] = 1;
+ }
+ goto loop;
+done: /* free working array */
+ xfree(flag);
+ csa->work3 = NULL;
+ return;
+}
+
+static void read_bounds(struct csa *csa)
+{ /* read BOUNDS section */
+ GLPCOL *col;
+ int j, v, mask, data;
+ double bnd, lb, ub;
+ char type[2+1], name[255+1], *flag;
+ /* allocate working array */
+ csa->work3 = flag = xcalloc(1+csa->P->n, sizeof(char));
+ memset(&flag[1], 0, csa->P->n);
+ /* no current BOUNDS vector exists */
+ v = 0;
+loop: if (indicator(csa, 0)) goto done;
+ /* field 1: bound type */
+ read_field(csa);
+ if (strcmp(csa->field, "LO") == 0)
+ mask = 0x01, data = 1;
+ else if (strcmp(csa->field, "UP") == 0)
+ mask = 0x10, data = 1;
+ else if (strcmp(csa->field, "FX") == 0)
+ mask = 0x11, data = 1;
+ else if (strcmp(csa->field, "FR") == 0)
+ mask = 0x11, data = 0;
+ else if (strcmp(csa->field, "MI") == 0)
+ mask = 0x01, data = 0;
+ else if (strcmp(csa->field, "PL") == 0)
+ mask = 0x10, data = 0;
+ else if (strcmp(csa->field, "LI") == 0)
+ mask = 0x01, data = 1;
+ else if (strcmp(csa->field, "UI") == 0)
+ mask = 0x10, data = 1;
+ else if (strcmp(csa->field, "BV") == 0)
+ mask = 0x11, data = 0;
+ else if (csa->field[0] == '\0')
+ error(csa, "missing bound type in field 1\n");
+ else
+ error(csa, "invalid bound type in field 1\n");
+ strcpy(type, csa->field);
+ /* field 2: BOUNDS vector name */
+ read_field(csa), patch_name(csa, csa->field);
+ if (csa->field[0] == '\0')
+ { /* the same BOUNDS vector as in previous data record */
+ if (v == 0)
+ { warning(csa, "missing BOUNDS vector name in field 2\n");
+ goto blnk;
+ }
+ }
+ else if (v != 0 && strcmp(csa->field, name) == 0)
+ { /* the same BOUNDS vector as in previous data record */
+ xassert(v != 0);
+ }
+ else
+blnk: { /* new BOUNDS vector */
+ if (v != 0)
+ error(csa, "multiple BOUNDS vectors not supported\n");
+ v++;
+ strcpy(name, csa->field);
+ }
+ /* field 3: column name */
+ read_field(csa), patch_name(csa, csa->field);
+ if (csa->field[0] == '\0')
+ error(csa, "missing column name in field 3\n");
+ j = glp_find_col(csa->P, csa->field);
+ if (j == 0)
+ error(csa, "column '%s' not found\n", csa->field);
+ if ((flag[j] & mask) == 0x01)
+ error(csa, "duplicate lower bound for column '%s'\n",
+ csa->field);
+ if ((flag[j] & mask) == 0x10)
+ error(csa, "duplicate upper bound for column '%s'\n",
+ csa->field);
+ xassert((flag[j] & mask) == 0x00);
+ /* field 4: bound value */
+ if (data)
+ { bnd = read_number(csa);
+ if (fabs(bnd) < csa->parm->tol_mps) bnd = 0.0;
+ }
+ else
+ read_field(csa), bnd = 0.0;
+ /* get current column bounds */
+ col = csa->P->col[j];
+ if (col->type == GLP_FR)
+ lb = -DBL_MAX, ub = +DBL_MAX;
+ else if (col->type == GLP_LO)
+ lb = col->lb, ub = +DBL_MAX;
+ else if (col->type == GLP_UP)
+ lb = -DBL_MAX, ub = col->ub;
+ else if (col->type == GLP_DB)
+ lb = col->lb, ub = col->ub;
+ else if (col->type == GLP_FX)
+ lb = ub = col->lb;
+ else
+ xassert(col != col);
+ /* change column bounds */
+ if (strcmp(type, "LO") == 0)
+ lb = bnd;
+ else if (strcmp(type, "UP") == 0)
+ ub = bnd;
+ else if (strcmp(type, "FX") == 0)
+ lb = ub = bnd;
+ else if (strcmp(type, "FR") == 0)
+ lb = -DBL_MAX, ub = +DBL_MAX;
+ else if (strcmp(type, "MI") == 0)
+ lb = -DBL_MAX;
+ else if (strcmp(type, "PL") == 0)
+ ub = +DBL_MAX;
+ else if (strcmp(type, "LI") == 0)
+ { glp_set_col_kind(csa->P, j, GLP_IV);
+ lb = ceil(bnd);
+#if 1 /* 16/VII-2013 */
+ /* if column upper bound has not been explicitly specified,
+ take it as +inf */
+ if (!(flag[j] & 0x10))
+ ub = +DBL_MAX;
+#endif
+ }
+ else if (strcmp(type, "UI") == 0)
+ { glp_set_col_kind(csa->P, j, GLP_IV);
+ ub = floor(bnd);
+ }
+ else if (strcmp(type, "BV") == 0)
+ { glp_set_col_kind(csa->P, j, GLP_IV);
+ lb = 0.0, ub = 1.0;
+ }
+ else
+ xassert(type != type);
+ /* set new column bounds */
+ if (lb == -DBL_MAX && ub == +DBL_MAX)
+ glp_set_col_bnds(csa->P, j, GLP_FR, lb, ub);
+ else if (ub == +DBL_MAX)
+ glp_set_col_bnds(csa->P, j, GLP_LO, lb, ub);
+ else if (lb == -DBL_MAX)
+ glp_set_col_bnds(csa->P, j, GLP_UP, lb, ub);
+ else if (lb != ub)
+ glp_set_col_bnds(csa->P, j, GLP_DB, lb, ub);
+ else
+ glp_set_col_bnds(csa->P, j, GLP_FX, lb, ub);
+ flag[j] |= (char)mask;
+ /* fields 5 and 6 must be blank */
+ skip_field(csa);
+ skip_field(csa);
+ goto loop;
+done: /* free working array */
+ xfree(flag);
+ csa->work3 = NULL;
+ return;
+}
+
+int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+ const char *fname)
+{ /* read problem data in MPS format */
+ glp_mpscp _parm;
+ struct csa _csa, *csa = &_csa;
+ int ret;
+ xprintf("Reading problem data from '%s'...\n", fname);
+ if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
+ xerror("glp_read_mps: fmt = %d; invalid parameter\n", fmt);
+ if (parm == NULL)
+ glp_init_mpscp(&_parm), parm = &_parm;
+ /* check control parameters */
+ check_parm("glp_read_mps", parm);
+ /* initialize common storage area */
+ csa->P = P;
+ csa->deck = (fmt == GLP_MPS_DECK);
+ csa->parm = parm;
+ csa->fname = fname;
+ csa->fp = NULL;
+ if (setjmp(csa->jump))
+ { ret = 1;
+ goto done;
+ }
+ csa->recno = csa->recpos = 0;
+ csa->c = '\n';
+ csa->fldno = 0;
+ csa->field[0] = '\0';
+ csa->w80 = csa->wef = 0;
+ csa->obj_row = 0;
+ csa->work1 = csa->work2 = csa->work3 = NULL;
+ /* erase problem object */
+ glp_erase_prob(P);
+ glp_create_index(P);
+ /* open input MPS file */
+ csa->fp = glp_open(fname, "r");
+ if (csa->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ /* read NAME indicator record */
+ read_name(csa);
+ if (P->name != NULL)
+ xprintf("Problem: %s\n", P->name);
+ /* read ROWS section */
+ if (!(indicator(csa, 0) && strcmp(csa->field, "ROWS") == 0))
+ error(csa, "missing ROWS indicator record\n");
+ read_rows(csa);
+ /* determine objective row */
+ if (parm->obj_name == NULL || parm->obj_name[0] == '\0')
+ { /* use the first row of N type */
+ int i;
+ for (i = 1; i <= P->m; i++)
+ { if (P->row[i]->type == GLP_FR)
+ { csa->obj_row = i;
+ break;
+ }
+ }
+ if (csa->obj_row == 0)
+ warning(csa, "unable to determine objective row\n");
+ }
+ else
+ { /* use a row with specified name */
+ int i;
+ for (i = 1; i <= P->m; i++)
+ { xassert(P->row[i]->name != NULL);
+ if (strcmp(parm->obj_name, P->row[i]->name) == 0)
+ { csa->obj_row = i;
+ break;
+ }
+ }
+ if (csa->obj_row == 0)
+ error(csa, "objective row '%s' not found\n",
+ parm->obj_name);
+ }
+ if (csa->obj_row != 0)
+ { glp_set_obj_name(P, P->row[csa->obj_row]->name);
+ xprintf("Objective: %s\n", P->obj);
+ }
+ /* read COLUMNS section */
+ if (strcmp(csa->field, "COLUMNS") != 0)
+ error(csa, "missing COLUMNS indicator record\n");
+ read_columns(csa);
+ /* set objective coefficients */
+ if (csa->obj_row != 0)
+ { GLPAIJ *aij;
+ for (aij = P->row[csa->obj_row]->ptr; aij != NULL; aij =
+ aij->r_next) glp_set_obj_coef(P, aij->col->j, aij->val);
+ }
+ /* read optional RHS section */
+ if (strcmp(csa->field, "RHS") == 0)
+ read_rhs(csa);
+ /* read optional RANGES section */
+ if (strcmp(csa->field, "RANGES") == 0)
+ read_ranges(csa);
+ /* read optional BOUNDS section */
+ if (strcmp(csa->field, "BOUNDS") == 0)
+ read_bounds(csa);
+ /* read ENDATA indicator record */
+ if (strcmp(csa->field, "ENDATA") != 0)
+ error(csa, "invalid use of %s indicator record\n",
+ csa->field);
+ /* print some statistics */
+ xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+ P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+ P->nnz, P->nnz == 1 ? "" : "s");
+ if (glp_get_num_int(P) > 0)
+ { int ni = glp_get_num_int(P);
+ int nb = glp_get_num_bin(P);
+ if (ni == 1)
+ { if (nb == 0)
+ xprintf("One variable is integer\n");
+ else
+ xprintf("One variable is binary\n");
+ }
+ else
+ { xprintf("%d integer variables, ", ni);
+ if (nb == 0)
+ xprintf("none");
+ else if (nb == 1)
+ xprintf("one");
+ else if (nb == ni)
+ xprintf("all");
+ else
+ xprintf("%d", nb);
+ xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
+ }
+ }
+ xprintf("%d records were read\n", csa->recno);
+#if 1 /* 31/III-2016 */
+ /* free (unbounded) row(s) in MPS file are intended to specify
+ * objective function(s), so all such rows can be removed */
+#if 1 /* 08/VIII-2013 */
+ /* remove free rows */
+ { int i, nrs, *num;
+ num = talloc(1+P->m, int);
+ nrs = 0;
+ for (i = 1; i <= P->m; i++)
+ { if (P->row[i]->type == GLP_FR)
+ num[++nrs] = i;
+ }
+ if (nrs > 0)
+ { glp_del_rows(P, nrs, num);
+ if (nrs == 1)
+ xprintf("One free row was removed\n");
+ else
+ xprintf("%d free rows were removed\n", nrs);
+ }
+ tfree(num);
+ }
+#endif
+#else
+ /* if objective function row is free, remove it */
+ if (csa->obj_row != 0 && P->row[csa->obj_row]->type == GLP_FR)
+ { int num[1+1];
+ num[1] = csa->obj_row;
+ glp_del_rows(P, 1, num);
+ xprintf("Free objective row was removed\n");
+ }
+#endif
+ /* problem data has been successfully read */
+ glp_delete_index(P);
+ glp_sort_matrix(P);
+ ret = 0;
+done: if (csa->fp != NULL) glp_close(csa->fp);
+ if (csa->work1 != NULL) xfree(csa->work1);
+ if (csa->work2 != NULL) xfree(csa->work2);
+ if (csa->work3 != NULL) xfree(csa->work3);
+ if (ret != 0) glp_erase_prob(P);
+ return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_write_mps - write problem data in MPS format
+*
+* SYNOPSIS
+*
+* int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+* const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_write_mps writes problem data in MPS format to a
+* text file.
+*
+* The parameter fmt specifies the version of MPS format:
+*
+* GLP_MPS_DECK - fixed (ancient) MPS format;
+* GLP_MPS_FILE - free (modern) MPS format.
+*
+* The parameter parm is a pointer to the structure glp_mpscp, which
+* specifies control parameters used by the routine. If parm is NULL,
+* the routine uses default settings.
+*
+* The character string fname specifies a name of the text file to be
+* written.
+*
+* RETURNS
+*
+* If the operation was successful, the routine glp_read_mps returns
+* zero. Otherwise, it prints an error message and returns non-zero. */
+
+#define csa csa1
+
+struct csa
+{ /* common storage area */
+ glp_prob *P;
+ /* pointer to problem object */
+ int deck;
+ /* MPS format (0 - free, 1 - fixed) */
+ const glp_mpscp *parm;
+ /* pointer to control parameters */
+ char field[255+1];
+ /* field buffer */
+};
+
+static char *mps_name(struct csa *csa)
+{ /* make problem name */
+ char *f;
+ if (csa->P->name == NULL)
+ csa->field[0] = '\0';
+ else if (csa->deck)
+ { strncpy(csa->field, csa->P->name, 8);
+ csa->field[8] = '\0';
+ }
+ else
+ strcpy(csa->field, csa->P->name);
+ for (f = csa->field; *f != '\0'; f++)
+ if (*f == ' ') *f = '_';
+ return csa->field;
+}
+
+static char *row_name(struct csa *csa, int i)
+{ /* make i-th row name */
+ char *f;
+ xassert(0 <= i && i <= csa->P->m);
+ if (i == 0 || csa->P->row[i]->name == NULL ||
+ csa->deck && strlen(csa->P->row[i]->name) > 8)
+ sprintf(csa->field, "R%07d", i);
+ else
+ { strcpy(csa->field, csa->P->row[i]->name);
+ for (f = csa->field; *f != '\0'; f++)
+ if (*f == ' ') *f = '_';
+ }
+ return csa->field;
+}
+
+static char *col_name(struct csa *csa, int j)
+{ /* make j-th column name */
+ char *f;
+ xassert(1 <= j && j <= csa->P->n);
+ if (csa->P->col[j]->name == NULL ||
+ csa->deck && strlen(csa->P->col[j]->name) > 8)
+ sprintf(csa->field, "C%07d", j);
+ else
+ { strcpy(csa->field, csa->P->col[j]->name);
+ for (f = csa->field; *f != '\0'; f++)
+ if (*f == ' ') *f = '_';
+ }
+ return csa->field;
+}
+
+static char *mps_numb(struct csa *csa, double val)
+{ /* format floating-point number */
+ int dig;
+ char *exp;
+ for (dig = 12; dig >= 6; dig--)
+ { if (val != 0.0 && fabs(val) < 0.002)
+ sprintf(csa->field, "%.*E", dig-1, val);
+ else
+ sprintf(csa->field, "%.*G", dig, val);
+ exp = strchr(csa->field, 'E');
+ if (exp != NULL)
+ sprintf(exp+1, "%d", atoi(exp+1));
+ if (strlen(csa->field) <= 12) break;
+ }
+ xassert(strlen(csa->field) <= 12);
+ return csa->field;
+}
+
+int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+ const char *fname)
+{ /* write problem data in MPS format */
+ glp_mpscp _parm;
+ struct csa _csa, *csa = &_csa;
+ glp_file *fp;
+ int out_obj, one_col = 0, empty = 0;
+ int i, j, recno, marker, count, gap, ret;
+ xprintf("Writing problem data to '%s'...\n", fname);
+ if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
+ xerror("glp_write_mps: fmt = %d; invalid parameter\n", fmt);
+ if (parm == NULL)
+ glp_init_mpscp(&_parm), parm = &_parm;
+ /* check control parameters */
+ check_parm("glp_write_mps", parm);
+ /* initialize common storage area */
+ csa->P = P;
+ csa->deck = (fmt == GLP_MPS_DECK);
+ csa->parm = parm;
+ /* create output MPS file */
+ fp = glp_open(fname, "w"), recno = 0;
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ /* write comment records */
+ xfprintf(fp, "* %-*s%s\n", P->name == NULL ? 1 : 12, "Problem:",
+ P->name == NULL ? "" : P->name), recno++;
+ xfprintf(fp, "* %-12s%s\n", "Class:", glp_get_num_int(P) == 0 ?
+ "LP" : "MIP"), recno++;
+ xfprintf(fp, "* %-12s%d\n", "Rows:", P->m), recno++;
+ if (glp_get_num_int(P) == 0)
+ xfprintf(fp, "* %-12s%d\n", "Columns:", P->n), recno++;
+ else
+ xfprintf(fp, "* %-12s%d (%d integer, %d binary)\n",
+ "Columns:", P->n, glp_get_num_int(P), glp_get_num_bin(P)),
+ recno++;
+ xfprintf(fp, "* %-12s%d\n", "Non-zeros:", P->nnz), recno++;
+ xfprintf(fp, "* %-12s%s\n", "Format:", csa->deck ? "Fixed MPS" :
+ "Free MPS"), recno++;
+ xfprintf(fp, "*\n", recno++);
+ /* write NAME indicator record */
+ xfprintf(fp, "NAME%*s%s\n",
+ P->name == NULL ? 0 : csa->deck ? 10 : 1, "", mps_name(csa)),
+ recno++;
+#if 1
+ /* determine whether to write the objective row */
+ out_obj = 1;
+ for (i = 1; i <= P->m; i++)
+ { if (P->row[i]->type == GLP_FR)
+ { out_obj = 0;
+ break;
+ }
+ }
+#endif
+ /* write ROWS section */
+ xfprintf(fp, "ROWS\n"), recno++;
+ for (i = (out_obj ? 0 : 1); i <= P->m; i++)
+ { int type;
+ type = (i == 0 ? GLP_FR : P->row[i]->type);
+ if (type == GLP_FR)
+ type = 'N';
+ else if (type == GLP_LO)
+ type = 'G';
+ else if (type == GLP_UP)
+ type = 'L';
+ else if (type == GLP_DB || type == GLP_FX)
+ type = 'E';
+ else
+ xassert(type != type);
+ xfprintf(fp, " %c%*s%s\n", type, csa->deck ? 2 : 1, "",
+ row_name(csa, i)), recno++;
+ }
+ /* write COLUMNS section */
+ xfprintf(fp, "COLUMNS\n"), recno++;
+ marker = 0;
+ for (j = 1; j <= P->n; j++)
+ { GLPAIJ cj, *aij;
+ int kind;
+ kind = P->col[j]->kind;
+ if (kind == GLP_CV)
+ { if (marker % 2 == 1)
+ { /* close current integer block */
+ marker++;
+ xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
+ csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
+ csa->deck ? 17 : 1, ""), recno++;
+ }
+ }
+ else if (kind == GLP_IV)
+ { if (marker % 2 == 0)
+ { /* open new integer block */
+ marker++;
+ xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTORG'\n",
+ csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
+ csa->deck ? 17 : 1, ""), recno++;
+ }
+ }
+ else
+ xassert(kind != kind);
+ if (out_obj && P->col[j]->coef != 0.0)
+ { /* make fake objective coefficient */
+ aij = &cj;
+ aij->row = NULL;
+ aij->val = P->col[j]->coef;
+ aij->c_next = P->col[j]->ptr;
+ }
+ else
+ aij = P->col[j]->ptr;
+#if 1 /* FIXME */
+ if (aij == NULL)
+ { /* empty column */
+ empty++;
+ xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+ csa->deck ? 8 : 1, col_name(csa, j));
+ /* we need a row */
+ xassert(P->m > 0);
+ xfprintf(fp, "%*s%-*s",
+ csa->deck ? 2 : 1, "", csa->deck ? 8 : 1,
+ row_name(csa, 1));
+ xfprintf(fp, "%*s0%*s$ empty column\n",
+ csa->deck ? 13 : 1, "", csa->deck ? 3 : 1, ""), recno++;
+ }
+#endif
+ count = 0;
+ for (aij = aij; aij != NULL; aij = aij->c_next)
+ { if (one_col || count % 2 == 0)
+ xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+ csa->deck ? 8 : 1, col_name(csa, j));
+ gap = (one_col || count % 2 == 0 ? 2 : 3);
+ xfprintf(fp, "%*s%-*s",
+ csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
+ row_name(csa, aij->row == NULL ? 0 : aij->row->i));
+ xfprintf(fp, "%*s%*s",
+ csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
+ mps_numb(csa, aij->val)), count++;
+ if (one_col || count % 2 == 0)
+ xfprintf(fp, "\n"), recno++;
+ }
+ if (!(one_col || count % 2 == 0))
+ xfprintf(fp, "\n"), recno++;
+ }
+ if (marker % 2 == 1)
+ { /* close last integer block */
+ marker++;
+ xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
+ csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
+ csa->deck ? 17 : 1, ""), recno++;
+ }
+#if 1
+ if (empty > 0)
+ xprintf("Warning: problem has %d empty column(s)\n", empty);
+#endif
+ /* write RHS section */
+ xfprintf(fp, "RHS\n"), recno++;
+ count = 0;
+ for (i = (out_obj ? 0 : 1); i <= P->m; i++)
+ { int type;
+ double rhs;
+ if (i == 0)
+ rhs = P->c0;
+ else
+ { type = P->row[i]->type;
+ if (type == GLP_FR)
+ rhs = 0.0;
+ else if (type == GLP_LO)
+ rhs = P->row[i]->lb;
+ else if (type == GLP_UP)
+ rhs = P->row[i]->ub;
+ else if (type == GLP_DB || type == GLP_FX)
+ rhs = P->row[i]->lb;
+ else
+ xassert(type != type);
+ }
+ if (rhs != 0.0)
+ { if (one_col || count % 2 == 0)
+ xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+ csa->deck ? 8 : 1, "RHS1");
+ gap = (one_col || count % 2 == 0 ? 2 : 3);
+ xfprintf(fp, "%*s%-*s",
+ csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
+ row_name(csa, i));
+ xfprintf(fp, "%*s%*s",
+ csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
+ mps_numb(csa, rhs)), count++;
+ if (one_col || count % 2 == 0)
+ xfprintf(fp, "\n"), recno++;
+ }
+ }
+ if (!(one_col || count % 2 == 0))
+ xfprintf(fp, "\n"), recno++;
+ /* write RANGES section */
+ for (i = P->m; i >= 1; i--)
+ if (P->row[i]->type == GLP_DB) break;
+ if (i == 0) goto bnds;
+ xfprintf(fp, "RANGES\n"), recno++;
+ count = 0;
+ for (i = 1; i <= P->m; i++)
+ { if (P->row[i]->type == GLP_DB)
+ { if (one_col || count % 2 == 0)
+ xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+ csa->deck ? 8 : 1, "RNG1");
+ gap = (one_col || count % 2 == 0 ? 2 : 3);
+ xfprintf(fp, "%*s%-*s",
+ csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
+ row_name(csa, i));
+ xfprintf(fp, "%*s%*s",
+ csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
+ mps_numb(csa, P->row[i]->ub - P->row[i]->lb)), count++;
+ if (one_col || count % 2 == 0)
+ xfprintf(fp, "\n"), recno++;
+ }
+ }
+ if (!(one_col || count % 2 == 0))
+ xfprintf(fp, "\n"), recno++;
+bnds: /* write BOUNDS section */
+ for (j = P->n; j >= 1; j--)
+ if (!(P->col[j]->kind == GLP_CV &&
+ P->col[j]->type == GLP_LO && P->col[j]->lb == 0.0))
+ break;
+ if (j == 0) goto endt;
+ xfprintf(fp, "BOUNDS\n"), recno++;
+ for (j = 1; j <= P->n; j++)
+ { int type, data[2];
+ double bnd[2];
+ char *spec[2];
+ spec[0] = spec[1] = NULL;
+ type = P->col[j]->type;
+ if (type == GLP_FR)
+ spec[0] = "FR", data[0] = 0;
+ else if (type == GLP_LO)
+ { if (P->col[j]->lb != 0.0)
+ spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
+ if (P->col[j]->kind == GLP_IV)
+ spec[1] = "PL", data[1] = 0;
+ }
+ else if (type == GLP_UP)
+ { spec[0] = "MI", data[0] = 0;
+ spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
+ }
+ else if (type == GLP_DB)
+ { if (P->col[j]->lb != 0.0)
+ spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
+ spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
+ }
+ else if (type == GLP_FX)
+ spec[0] = "FX", data[0] = 1, bnd[0] = P->col[j]->lb;
+ else
+ xassert(type != type);
+ for (i = 0; i <= 1; i++)
+ { if (spec[i] != NULL)
+ { xfprintf(fp, " %s %-*s%*s%-*s", spec[i],
+ csa->deck ? 8 : 1, "BND1", csa->deck ? 2 : 1, "",
+ csa->deck ? 8 : 1, col_name(csa, j));
+ if (data[i])
+ xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "",
+ csa->deck ? 12 : 1, mps_numb(csa, bnd[i]));
+ xfprintf(fp, "\n"), recno++;
+ }
+ }
+ }
+endt: /* write ENDATA indicator record */
+ xfprintf(fp, "ENDATA\n"), recno++;
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ /* problem data has been successfully written */
+ xprintf("%d records were written\n", recno);
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/netgen.c b/test/monniaux/glpk-4.65/src/api/netgen.c
new file mode 100644
index 00000000..519fd609
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/netgen.c
@@ -0,0 +1,1020 @@
+/* netgen.c (Klingman's network problem generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* This code is the result of translation of the Fortran program NETGEN
+* developed by Dr. Darwin Klingman, which is publically available from
+* NETLIB at <http://www.netlib.org/lp/generators>.
+*
+* The translation was made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_netgen - Klingman's network problem generator
+*
+* SYNOPSIS
+*
+* int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+* const int parm[1+15]);
+*
+* DESCRIPTION
+*
+* The routine glp_netgen is a network problem generator developed by
+* Dr. Darwin Klingman. It can create capacitated and uncapacitated
+* minimum cost flow (or transshipment), transportation, and assignment
+* problems.
+*
+* The parameter G specifies the graph object, to which the generated
+* problem data have to be stored. Note that on entry the graph object
+* is erased with the routine glp_erase_graph.
+*
+* The parameter v_rhs specifies an offset of the field of type double
+* in the vertex data block, to which the routine stores the supply or
+* demand value. If v_rhs < 0, the value is not stored.
+*
+* The parameter a_cap specifies an offset of the field of type double
+* in the arc data block, to which the routine stores the arc capacity.
+* If a_cap < 0, the capacity is not stored.
+*
+* The parameter a_cost specifies an offset of the field of type double
+* in the arc data block, to which the routine stores the per-unit cost
+* if the arc flow. If a_cost < 0, the cost is not stored.
+*
+* The array parm contains description of the network to be generated:
+*
+* parm[0] not used
+* parm[1] (iseed) 8-digit positive random number seed
+* parm[2] (nprob) 8-digit problem id number
+* parm[3] (nodes) total number of nodes
+* parm[4] (nsorc) total number of source nodes (including
+* transshipment nodes)
+* parm[5] (nsink) total number of sink nodes (including
+* transshipment nodes)
+* parm[6] (iarcs) number of arcs
+* parm[7] (mincst) minimum cost for arcs
+* parm[8] (maxcst) maximum cost for arcs
+* parm[9] (itsup) total supply
+* parm[10] (ntsorc) number of transshipment source nodes
+* parm[11] (ntsink) number of transshipment sink nodes
+* parm[12] (iphic) percentage of skeleton arcs to be given
+* the maximum cost
+* parm[13] (ipcap) percentage of arcs to be capacitated
+* parm[14] (mincap) minimum upper bound for capacitated arcs
+* parm[15] (maxcap) maximum upper bound for capacitated arcs
+*
+* The routine generates a transportation problem if:
+*
+* nsorc + nsink = nodes, ntsorc = 0, and ntsink = 0.
+*
+* The routine generates an assignment problem if the requirements for
+* a transportation problem are met and:
+*
+* nsorc = nsink and itsup = nsorc.
+*
+* RETURNS
+*
+* If the instance was successfully generated, the routine glp_netgen
+* returns zero; otherwise, if specified parameters are inconsistent,
+* the routine returns a non-zero error code.
+*
+* REFERENCES
+*
+* D.Klingman, A.Napier, and J.Stutz. NETGEN: A program for generating
+* large scale capacitated assignment, transportation, and minimum cost
+* flow networks. Management Science 20 (1974), 814-20. */
+
+struct csa
+{ /* common storage area */
+ glp_graph *G;
+ int v_rhs, a_cap, a_cost;
+ int nodes, iarcs, mincst, maxcst, itsup, nsorc, nsink, nonsor,
+ nfsink, narcs, nsort, nftsor, ipcap, mincap, maxcap, ktl,
+ nodlft, *ipred, *ihead, *itail, *iflag, *isup, *lsinks, mult,
+ modul, i15, i16, jran;
+};
+
+#define G (csa->G)
+#define v_rhs (csa->v_rhs)
+#define a_cap (csa->a_cap)
+#define a_cost (csa->a_cost)
+#define nodes (csa->nodes)
+#define iarcs (csa->iarcs)
+#define mincst (csa->mincst)
+#define maxcst (csa->maxcst)
+#define itsup (csa->itsup)
+#define nsorc (csa->nsorc)
+#define nsink (csa->nsink)
+#define nonsor (csa->nonsor)
+#define nfsink (csa->nfsink)
+#define narcs (csa->narcs)
+#define nsort (csa->nsort)
+#define nftsor (csa->nftsor)
+#define ipcap (csa->ipcap)
+#define mincap (csa->mincap)
+#define maxcap (csa->maxcap)
+#define ktl (csa->ktl)
+#define nodlft (csa->nodlft)
+#if 0
+/* spent a day to find out this bug */
+#define ist (csa->ist)
+#else
+#define ist (ipred[0])
+#endif
+#define ipred (csa->ipred)
+#define ihead (csa->ihead)
+#define itail (csa->itail)
+#define iflag (csa->iflag)
+#define isup (csa->isup)
+#define lsinks (csa->lsinks)
+#define mult (csa->mult)
+#define modul (csa->modul)
+#define i15 (csa->i15)
+#define i16 (csa->i16)
+#define jran (csa->jran)
+
+static void cresup(struct csa *csa);
+static void chain(struct csa *csa, int lpick, int lsorc);
+static void chnarc(struct csa *csa, int lsorc);
+static void sort(struct csa *csa);
+static void pickj(struct csa *csa, int it);
+static void assign(struct csa *csa);
+static void setran(struct csa *csa, int iseed);
+static int iran(struct csa *csa, int ilow, int ihigh);
+
+int glp_netgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
+ const int parm[1+15])
+{ struct csa _csa, *csa = &_csa;
+ int iseed, nprob, ntsorc, ntsink, iphic, i, nskel, nltr, ltsink,
+ ntrans, npsink, nftr, npsorc, ntravl, ntrrem, lsorc, lpick,
+ nsksr, nsrchn, j, item, l, ks, k, ksp, li, n, ii, it, ih, icap,
+ jcap, icost, jcost, ret;
+ G = G_;
+ v_rhs = _v_rhs;
+ a_cap = _a_cap;
+ a_cost = _a_cost;
+ if (G != NULL)
+ { if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+ xerror("glp_netgen: v_rhs = %d; invalid offset\n", v_rhs);
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_netgen: a_cap = %d; invalid offset\n", a_cap);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_netgen: a_cost = %d; invalid offset\n", a_cost);
+ }
+ /* Input the user's random number seed and fix it if
+ non-positive. */
+ iseed = parm[1];
+ nprob = parm[2];
+ if (iseed <= 0) iseed = 13502460;
+ setran(csa, iseed);
+ /* Input the user's problem characteristics. */
+ nodes = parm[3];
+ nsorc = parm[4];
+ nsink = parm[5];
+ iarcs = parm[6];
+ mincst = parm[7];
+ maxcst = parm[8];
+ itsup = parm[9];
+ ntsorc = parm[10];
+ ntsink = parm[11];
+ iphic = parm[12];
+ ipcap = parm[13];
+ mincap = parm[14];
+ maxcap = parm[15];
+ /* Check the size of the problem. */
+ if (!(10 <= nodes && nodes <= 100000))
+ { ret = 1;
+ goto done;
+ }
+ /* Check user supplied parameters for consistency. */
+ if (!(nsorc >= 0 && nsink >= 0 && nsorc + nsink <= nodes))
+ { ret = 2;
+ goto done;
+ }
+ if (iarcs < 0)
+ { ret = 3;
+ goto done;
+ }
+ if (mincst > maxcst)
+ { ret = 4;
+ goto done;
+ }
+ if (itsup < 0)
+ { ret = 5;
+ goto done;
+ }
+ if (!(0 <= ntsorc && ntsorc <= nsorc))
+ { ret = 6;
+ goto done;
+ }
+ if (!(0 <= ntsink && ntsink <= nsink))
+ { ret = 7;
+ goto done;
+ }
+ if (!(0 <= iphic && iphic <= 100))
+ { ret = 8;
+ goto done;
+ }
+ if (!(0 <= ipcap && ipcap <= 100))
+ { ret = 9;
+ goto done;
+ }
+ if (mincap > maxcap)
+ { ret = 10;
+ goto done;
+ }
+ /* Initailize the graph object. */
+ if (G != NULL)
+ { glp_erase_graph(G, G->v_size, G->a_size);
+ glp_add_vertices(G, nodes);
+ if (v_rhs >= 0)
+ { double zero = 0.0;
+ for (i = 1; i <= nodes; i++)
+ { glp_vertex *v = G->v[i];
+ memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
+ }
+ }
+ }
+ /* Allocate working arrays. */
+ ipred = xcalloc(1+nodes, sizeof(int));
+ ihead = xcalloc(1+nodes, sizeof(int));
+ itail = xcalloc(1+nodes, sizeof(int));
+ iflag = xcalloc(1+nodes, sizeof(int));
+ isup = xcalloc(1+nodes, sizeof(int));
+ lsinks = xcalloc(1+nodes, sizeof(int));
+ /* Print the problem documentation records. */
+ if (G == NULL)
+ { xprintf("BEGIN\n");
+ xprintf("NETGEN PROBLEM%8d%10s%10d NODES AND%10d ARCS\n",
+ nprob, "", nodes, iarcs);
+ xprintf("USER:%11d%11d%11d%11d%11d%11d\nDATA:%11d%11d%11d%11d%"
+ "11d%11d\n", iseed, nsorc, nsink, mincst,
+ maxcst, itsup, ntsorc, ntsink, iphic, ipcap,
+ mincap, maxcap);
+ }
+ else
+ glp_set_graph_name(G, "NETGEN");
+ /* Set various constants used in the program. */
+ narcs = 0;
+ nskel = 0;
+ nltr = nodes - nsink;
+ ltsink = nltr + ntsink;
+ ntrans = nltr - nsorc;
+ nfsink = nltr + 1;
+ nonsor = nodes - nsorc + ntsorc;
+ npsink = nsink - ntsink;
+ nodlft = nodes - nsink + ntsink;
+ nftr = nsorc + 1;
+ nftsor = nsorc - ntsorc + 1;
+ npsorc = nsorc - ntsorc;
+ /* Randomly distribute the supply among the source nodes. */
+ if (npsorc + npsink == nodes && npsorc == npsink &&
+ itsup == nsorc)
+ { assign(csa);
+ nskel = nsorc;
+ goto L390;
+ }
+ cresup(csa);
+ /* Print the supply records. */
+ if (G == NULL)
+ { xprintf("SUPPLY\n");
+ for (i = 1; i <= nsorc; i++)
+ xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
+ xprintf("ARCS\n");
+ }
+ else
+ { if (v_rhs >= 0)
+ { for (i = 1; i <= nsorc; i++)
+ { double temp = (double)isup[i];
+ glp_vertex *v = G->v[i];
+ memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+ }
+ }
+ }
+ /* Make the sources point to themselves in ipred array. */
+ for (i = 1; i <= nsorc; i++)
+ ipred[i] = i;
+ if (ntrans == 0) goto L170;
+ /* Chain the transshipment nodes together in the ipred array. */
+ ist = nftr;
+ ipred[nltr] = 0;
+ for (i = nftr; i < nltr; i++)
+ ipred[i] = i+1;
+ /* Form even length chains for 60 percent of the transshipments.*/
+ ntravl = 6 * ntrans / 10;
+ ntrrem = ntrans - ntravl;
+L140: lsorc = 1;
+ while (ntravl != 0)
+ { lpick = iran(csa, 1, ntravl + ntrrem);
+ ntravl--;
+ chain(csa, lpick, lsorc);
+ if (lsorc == nsorc) goto L140;
+ lsorc++;
+ }
+ /* Add the remaining transshipments to the chains. */
+ while (ntrrem != 0)
+ {
+ lpick = iran(csa, 1, ntrrem);
+ ntrrem--;
+ lsorc = iran(csa, 1, nsorc);
+ chain(csa, lpick, lsorc);
+ }
+L170: /* Set all demands equal to zero. */
+ for (i = nfsink; i <= nodes; i++)
+ ipred[i] = 0;
+ /* The following loop takes one chain at a time (through the use
+ of logic contained in the loop and calls to other routines) and
+ creates the remaining network arcs. */
+ for (lsorc = 1; lsorc <= nsorc; lsorc++)
+ { chnarc(csa, lsorc);
+ for (i = nfsink; i <= nodes; i++)
+ iflag[i] = 0;
+ /* Choose the number of sinks to be hooked up to the current
+ chain. */
+ if (ntrans != 0)
+ nsksr = (nsort * 2 * nsink) / ntrans;
+ else
+ nsksr = nsink / nsorc + 1;
+ if (nsksr < 2) nsksr = 2;
+ if (nsksr > nsink) nsksr = nsink;
+ nsrchn = nsort;
+ /* Randomly pick nsksr sinks and put their names in lsinks. */
+ ktl = nsink;
+ for (j = 1; j <= nsksr; j++)
+ { item = iran(csa, 1, ktl);
+ ktl--;
+ for (l = nfsink; l <= nodes; l++)
+ { if (iflag[l] != 1)
+ { item--;
+ if (item == 0) goto L230;
+ }
+ }
+ break;
+L230: lsinks[j] = l;
+ iflag[l] = 1;
+ }
+ /* If last source chain, add all sinks with zero demand to
+ lsinks list. */
+ if (lsorc == nsorc)
+ { for (j = nfsink; j <= nodes; j++)
+ { if (ipred[j] == 0 && iflag[j] != 1)
+ { nsksr++;
+ lsinks[nsksr] = j;
+ iflag[j] = 1;
+ }
+ }
+ }
+ /* Create demands for group of sinks in lsinks. */
+ ks = isup[lsorc] / nsksr;
+ k = ipred[lsorc];
+ for (i = 1; i <= nsksr; i++)
+ { nsort++;
+ ksp = iran(csa, 1, ks);
+ j = iran(csa, 1, nsksr);
+ itail[nsort] = k;
+ li = lsinks[i];
+ ihead[nsort] = li;
+ ipred[li] += ksp;
+ li = lsinks[j];
+ ipred[li] += ks - ksp;
+ n = iran(csa, 1, nsrchn);
+ k = lsorc;
+ for (ii = 1; ii <= n; ii++)
+ k = ipred[k];
+ }
+ li = lsinks[1];
+ ipred[li] += isup[lsorc] - ks * nsksr;
+ nskel += nsort;
+ /* Sort the arcs in the chain from source lsorc using itail as
+ sort key. */
+ sort(csa);
+ /* Print this part of skeleton and create the arcs for these
+ nodes. */
+ i = 1;
+ itail[nsort+1] = 0;
+L300: for (j = nftsor; j <= nodes; j++)
+ iflag[j] = 0;
+ ktl = nonsor - 1;
+ it = itail[i];
+ iflag[it] = 1;
+L320: ih = ihead[i];
+ iflag[ih] = 1;
+ narcs++;
+ ktl--;
+ /* Determine if this skeleton arc should be capacitated. */
+ icap = itsup;
+ jcap = iran(csa, 1, 100);
+ if (jcap <= ipcap)
+ { icap = isup[lsorc];
+ if (mincap > icap) icap = mincap;
+ }
+ /* Determine if this skeleton arc should have the maximum
+ cost. */
+ icost = maxcst;
+ jcost = iran(csa, 1, 100);
+ if (jcost > iphic)
+ icost = iran(csa, mincst, maxcst);
+ if (G == NULL)
+ xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ih, "", icost,
+ icap);
+ else
+ { glp_arc *a = glp_add_arc(G, it, ih);
+ if (a_cap >= 0)
+ { double temp = (double)icap;
+ memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+ }
+ if (a_cost >= 0)
+ { double temp = (double)icost;
+ memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+ }
+ }
+ i++;
+ if (itail[i] == it) goto L320;
+ pickj(csa, it);
+ if (i <= nsort) goto L300;
+ }
+ /* Create arcs from the transshipment sinks. */
+ if (ntsink != 0)
+ { for (i = nfsink; i <= ltsink; i++)
+ { for (j = nftsor; j <= nodes; j++)
+ iflag[j] = 0;
+ ktl = nonsor - 1;
+ iflag[i] = 1;
+ pickj(csa, i);
+ }
+ }
+L390: /* Print the demand records and end record. */
+ if (G == NULL)
+ { xprintf("DEMAND\n");
+ for (i = nfsink; i <= nodes; i++)
+ xprintf("%6s%6d%18s%10d\n", "", i, "", ipred[i]);
+ xprintf("END\n");
+ }
+ else
+ { if (v_rhs >= 0)
+ { for (i = nfsink; i <= nodes; i++)
+ { double temp = - (double)ipred[i];
+ glp_vertex *v = G->v[i];
+ memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+ }
+ }
+ }
+ /* Free working arrays. */
+ xfree(ipred);
+ xfree(ihead);
+ xfree(itail);
+ xfree(iflag);
+ xfree(isup);
+ xfree(lsinks);
+ /* The instance has been successfully generated. */
+ ret = 0;
+done: return ret;
+}
+
+/***********************************************************************
+* The routine cresup randomly distributes the total supply among the
+* source nodes. */
+
+static void cresup(struct csa *csa)
+{ int i, j, ks, ksp;
+ xassert(itsup > nsorc);
+ ks = itsup / nsorc;
+ for (i = 1; i <= nsorc; i++)
+ isup[i] = 0;
+ for (i = 1; i <= nsorc; i++)
+ { ksp = iran(csa, 1, ks);
+ j = iran(csa, 1, nsorc);
+ isup[i] += ksp;
+ isup[j] += ks - ksp;
+ }
+ j = iran(csa, 1, nsorc);
+ isup[j] += itsup - ks * nsorc;
+ return;
+}
+
+/***********************************************************************
+* The routine chain adds node lpick to the end of the chain with source
+* node lsorc. */
+
+static void chain(struct csa *csa, int lpick, int lsorc)
+{ int i, j, k, l, m;
+ k = 0;
+ m = ist;
+ for (i = 1; i <= lpick; i++)
+ { l = k;
+ k = m;
+ m = ipred[k];
+ }
+ ipred[l] = m;
+ j = ipred[lsorc];
+ ipred[k] = j;
+ ipred[lsorc] = k;
+ return;
+}
+
+/***********************************************************************
+* The routine chnarc puts the arcs in the chain from source lsorc into
+* the ihead and itail arrays for sorting. */
+
+static void chnarc(struct csa *csa, int lsorc)
+{ int ito, ifrom;
+ nsort = 0;
+ ito = ipred[lsorc];
+L10: if (ito == lsorc) return;
+ nsort++;
+ ifrom = ipred[ito];
+ ihead[nsort] = ito;
+ itail[nsort] = ifrom;
+ ito = ifrom;
+ goto L10;
+}
+
+/***********************************************************************
+* The routine sort sorts the nsort arcs in the ihead and itail arrays.
+* ihead is used as the sort key (i.e. forward star sort order). */
+
+static void sort(struct csa *csa)
+{ int i, j, k, l, m, n, it;
+ n = nsort;
+ m = n;
+L10: m /= 2;
+ if (m == 0) return;
+ k = n - m;
+ j = 1;
+L20: i = j;
+L30: l = i + m;
+ if (itail[i] <= itail[l]) goto L40;
+ it = itail[i];
+ itail[i] = itail[l];
+ itail[l] = it;
+ it = ihead[i];
+ ihead[i] = ihead[l];
+ ihead[l] = it;
+ i -= m;
+ if (i >= 1) goto L30;
+L40: j++;
+ if (j <= k) goto L20;
+ goto L10;
+}
+
+/***********************************************************************
+* The routine pickj creates a random number of arcs out of node 'it'.
+* Various parameters are dynamically adjusted in an attempt to ensure
+* that the generated network has the correct number of arcs. */
+
+static void pickj(struct csa *csa, int it)
+{ int j, k, l, nn, nupbnd, icap, jcap, icost;
+ if ((nodlft - 1) * 2 > iarcs - narcs - 1)
+ { nodlft--;
+ return;
+ }
+ if ((iarcs - narcs + nonsor - ktl - 1) / nodlft - nonsor + 1 >= 0)
+ k = nonsor;
+ else
+ { nupbnd = (iarcs - narcs - nodlft) / nodlft * 2;
+L40: k = iran(csa, 1, nupbnd);
+ if (nodlft == 1) k = iarcs - narcs;
+ if ((nodlft - 1) * (nonsor - 1) < iarcs - narcs - k) goto L40;
+ }
+ nodlft--;
+ for (j = 1; j <= k; j++)
+ { nn = iran(csa, 1, ktl);
+ ktl--;
+ for (l = nftsor; l <= nodes; l++)
+ { if (iflag[l] != 1)
+ { nn--;
+ if (nn == 0) goto L70;
+ }
+ }
+ return;
+L70: iflag[l] = 1;
+ icap = itsup;
+ jcap = iran(csa, 1, 100);
+ if (jcap <= ipcap)
+ icap = iran(csa, mincap, maxcap);
+ icost = iran(csa, mincst, maxcst);
+ if (G == NULL)
+ xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, l, "", icost,
+ icap);
+ else
+ { glp_arc *a = glp_add_arc(G, it, l);
+ if (a_cap >= 0)
+ { double temp = (double)icap;
+ memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+ }
+ if (a_cost >= 0)
+ { double temp = (double)icost;
+ memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+ }
+ }
+ narcs++;
+ }
+ return;
+}
+
+/***********************************************************************
+* The routine assign generate assignment problems. It defines the unit
+* supplies, builds a skeleton, then calls pickj to create the arcs. */
+
+static void assign(struct csa *csa)
+{ int i, it, nn, l, ll, icost;
+ if (G == NULL)
+ xprintf("SUPPLY\n");
+ for (i = 1; i <= nsorc; i++)
+ { isup[i] = 1;
+ iflag[i] = 0;
+ if (G == NULL)
+ xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
+ else
+ { if (v_rhs >= 0)
+ { double temp = (double)isup[i];
+ glp_vertex *v = G->v[i];
+ memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+ }
+ }
+ }
+ if (G == NULL)
+ xprintf("ARCS\n");
+ for (i = nfsink; i <= nodes; i++)
+ ipred[i] = 1;
+ for (it = 1; it <= nsorc; it++)
+ { for (i = nfsink; i <= nodes; i++)
+ iflag[i] = 0;
+ ktl = nsink - 1;
+ nn = iran(csa, 1, nsink - it + 1);
+ for (l = 1; l <= nsorc; l++)
+ { if (iflag[l] != 1)
+ { nn--;
+ if (nn == 0) break;
+ }
+ }
+ narcs++;
+ ll = nsorc + l;
+ icost = iran(csa, mincst, maxcst);
+ if (G == NULL)
+ xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ll, "", icost,
+ isup[1]);
+ else
+ { glp_arc *a = glp_add_arc(G, it, ll);
+ if (a_cap >= 0)
+ { double temp = (double)isup[1];
+ memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+ }
+ if (a_cost >= 0)
+ { double temp = (double)icost;
+ memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+ }
+ }
+ iflag[l] = 1;
+ iflag[ll] = 1;
+ pickj(csa, it);
+ }
+ return;
+}
+
+/***********************************************************************
+* Portable congruential (uniform) random number generator:
+*
+* next_value = ((7**5) * previous_value) modulo ((2**31)-1)
+*
+* This generator consists of three routines:
+*
+* (1) setran - initializes constants and seed
+* (2) iran - generates an integer random number
+* (3) rran - generates a real random number
+*
+* The generator requires a machine with at least 32 bits of precision.
+* The seed (iseed) must be in the range [1,(2**31)-1]. */
+
+static void setran(struct csa *csa, int iseed)
+{ xassert(iseed >= 1);
+ mult = 16807;
+ modul = 2147483647;
+ i15 = 1 << 15;
+ i16 = 1 << 16;
+ jran = iseed;
+ return;
+}
+
+/***********************************************************************
+* The routine iran generates an integer random number between ilow and
+* ihigh. If ilow > ihigh then iran returns ihigh. */
+
+static int iran(struct csa *csa, int ilow, int ihigh)
+{ int ixhi, ixlo, ixalo, leftlo, ixahi, ifulhi, irtlo, iover,
+ irthi, j;
+ ixhi = jran / i16;
+ ixlo = jran - ixhi * i16;
+ ixalo = ixlo * mult;
+ leftlo = ixalo / i16;
+ ixahi = ixhi * mult;
+ ifulhi = ixahi + leftlo;
+ irtlo = ixalo - leftlo * i16;
+ iover = ifulhi / i15;
+ irthi = ifulhi - iover * i15;
+ jran = ((irtlo - modul) + irthi * i16) + iover;
+ if (jran < 0) jran += modul;
+ j = ihigh - ilow + 1;
+ if (j > 0)
+ return jran % j + ilow;
+ else
+ return ihigh;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_netgen_prob - Klingman's standard network problem instance
+*
+* SYNOPSIS
+*
+* void glp_netgen_prob(int nprob, int parm[1+15]);
+*
+* DESCRIPTION
+*
+* The routine glp_netgen_prob provides the set of parameters for
+* Klingman's network problem generator (see the routine glp_netgen),
+* which describe a standard network problem instance.
+*
+* The parameter nprob (101 <= nprob <= 150) specifies the problem
+* instance number.
+*
+* The array parm contains description of the network, provided by the
+* routine. (For detailed description of these parameters see comments
+* to the routine glp_netgen.)
+*
+* PROBLEM CHARACTERISTICS
+*
+* The table below shows characteristics of Klingman's standard network
+* problem instances.
+*
+* Problem Nodes Arcs Optimum
+* ------- ----- ----- ----------
+* 101 5000 25336 6191726
+* 102 5000 25387 72337144
+* 103 5000 25355 218947553
+* 104 5000 25344 -19100371
+* 105 5000 25332 31192578
+* 106 5000 12870 4314276
+* 107 5000 37832 7393769
+* 108 5000 50309 8405738
+* 109 5000 75299 9190300
+* 110 5000 12825 8975048
+* 111 5000 37828 4747532
+* 112 5000 50325 4012671
+* 113 5000 75318 2979725
+* 114 5000 26514 5821181
+* 115 5000 25962 6353310
+* 116 5000 25304 5915426
+* 117 5000 12816 4420560
+* 118 5000 37797 7045842
+* 119 5000 50301 7724179
+* 120 5000 75330 8455200
+* 121 5000 25000 66366360
+* 122 5000 25000 30997529
+* 123 5000 25000 23388777
+* 124 5000 25000 17803443
+* 125 5000 25000 14119622
+* 126 5000 12500 18802218
+* 127 5000 37500 27674647
+* 128 5000 50000 30906194
+* 129 5000 75000 40905209
+* 130 5000 12500 38939608
+* 131 5000 37500 16752978
+* 132 5000 50000 13302951
+* 133 5000 75000 9830268
+* 134 1000 25000 3804874
+* 135 2500 25000 11729616
+* 136 7500 25000 33318101
+* 137 10000 25000 46426030
+* 138 5000 25000 60710879
+* 139 5000 25000 32729682
+* 140 5000 25000 27183831
+* 141 5000 25000 19963286
+* 142 5000 25000 20243457
+* 143 5000 25000 18586777
+* 144 5000 25000 2504591
+* 145 5000 25000 215956138
+* 146 5000 25000 2253113811
+* 147 5000 25000 -427908373
+* 148 5000 25000 -92965318
+* 149 5000 25000 86051224
+* 150 5000 25000 619314919 */
+
+static const int data[50][1+15] =
+{ { 0, 13502460, 101, 5000, 2500, 2500, 25000,
+ 1, 100, 250000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 4281922, 102, 5000, 2500, 2500, 25000,
+ 1, 100, 2500000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 44820113, 103, 5000, 2500, 2500, 25000,
+ 1, 100, 6250000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 13450451, 104, 5000, 2500, 2500, 25000,
+ -100, -1, 250000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 14719436, 105, 5000, 2500, 2500, 25000,
+ 101, 200, 250000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 17365786, 106, 5000, 2500, 2500, 12500,
+ 1, 100, 125000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 19540113, 107, 5000, 2500, 2500, 37500,
+ 1, 100, 375000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 19560313, 108, 5000, 2500, 2500, 50000,
+ 1, 100, 500000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 2403509, 109, 5000, 2500, 2500, 75000,
+ 1, 100, 750000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 92480414, 110, 5000, 2500, 2500, 12500,
+ 1, 100, 250000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 4230140, 111, 5000, 2500, 2500, 37500,
+ 1, 100, 250000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 10032490, 112, 5000, 2500, 2500, 50000,
+ 1, 100, 250000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 17307474, 113, 5000, 2500, 2500, 75000,
+ 1, 100, 250000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 4925114, 114, 5000, 500, 4500, 25000,
+ 1, 100, 250000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 19842704, 115, 5000, 1500, 3500, 25000,
+ 1, 100, 250000, 0, 0, 0, 100, 1, 1000
+ },
+ { 0, 88392060, 116, 5000, 2500, 2500, 25000,
+ 1, 100, 250000, 0, 0, 0, 0, 1, 1000
+ },
+ { 0, 12904407, 117, 5000, 2500, 2500, 12500,
+ 1, 100, 125000, 0, 0, 0, 0, 1, 1000
+ },
+ { 0, 11811811, 118, 5000, 2500, 2500, 37500,
+ 1, 100, 375000, 0, 0, 0, 0, 1, 1000
+ },
+ { 0, 90023593, 119, 5000, 2500, 2500, 50000,
+ 1, 100, 500000, 0, 0, 0, 0, 1, 1000
+ },
+ { 0, 93028922, 120, 5000, 2500, 2500, 75000,
+ 1, 100, 750000, 0, 0, 0, 0, 1, 1000
+ },
+ { 0, 72707401, 121, 5000, 50, 50, 25000,
+ 1, 100, 250000, 50, 50, 0, 100, 1, 1000
+ },
+ { 0, 93040771, 122, 5000, 250, 250, 25000,
+ 1, 100, 250000, 250, 250, 0, 100, 1, 1000
+ },
+ { 0, 70220611, 123, 5000, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 52774811, 124, 5000, 1000, 1000, 25000,
+ 1, 100, 250000, 1000, 1000, 0, 100, 1, 1000
+ },
+ { 0, 22492311, 125, 5000, 1500, 1500, 25000,
+ 1, 100, 250000, 1500, 1500, 0, 100, 1, 1000
+ },
+ { 0, 35269337, 126, 5000, 500, 500, 12500,
+ 1, 100, 125000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 30140502, 127, 5000, 500, 500, 37500,
+ 1, 100, 375000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 49205455, 128, 5000, 500, 500, 50000,
+ 1, 100, 500000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 42958341, 129, 5000, 500, 500, 75000,
+ 1, 100, 750000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 25440925, 130, 5000, 500, 500, 12500,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 75294924, 131, 5000, 500, 500, 37500,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 4463965, 132, 5000, 500, 500, 50000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 13390427, 133, 5000, 500, 500, 75000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 95250971, 134, 1000, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 54830522, 135, 2500, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 520593, 136, 7500, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 52900925, 137, 10000, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 22603395, 138, 5000, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 50
+ },
+ { 0, 55253099, 139, 5000, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 250
+ },
+ { 0, 75357001, 140, 5000, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 500
+ },
+ { 0, 10072459, 141, 5000, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 2500
+ },
+ { 0, 55728492, 142, 5000, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 100, 1, 5000
+ },
+ { 0, 593043, 143, 5000, 500, 500, 25000,
+ 1, 100, 250000, 500, 500, 0, 0, 1, 1000
+ },
+ { 0, 94236572, 144, 5000, 500, 500, 25000,
+ 1, 10, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 94882955, 145, 5000, 500, 500, 25000,
+ 1, 1000, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 48489922, 146, 5000, 500, 500, 25000,
+ 1, 10000, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 75578374, 147, 5000, 500, 500, 25000,
+ -100, -1, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 44821152, 148, 5000, 500, 500, 25000,
+ -50, 49, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 45224103, 149, 5000, 500, 500, 25000,
+ 101, 200, 250000, 500, 500, 0, 100, 1, 1000
+ },
+ { 0, 63491741, 150, 5000, 500, 500, 25000,
+ 1001, 1100, 250000, 500, 500, 0, 100, 1, 1000
+ },
+};
+
+void glp_netgen_prob(int nprob, int parm[1+15])
+{ int k;
+ if (!(101 <= nprob && nprob <= 150))
+ xerror("glp_netgen_prob: nprob = %d; invalid problem instance "
+ "number\n", nprob);
+ for (k = 1; k <= 15; k++)
+ parm[k] = data[nprob-101][k];
+ return;
+}
+
+/**********************************************************************/
+
+#if 0
+static int scan(char card[80+1], int pos, int len)
+{ char buf[10+1];
+ memcpy(buf, &card[pos-1], len);
+ buf[len] = '\0';
+ return atoi(buf);
+}
+
+int main(void)
+{ int parm[1+15];
+ char card[80+1];
+ xassert(fgets(card, sizeof(card), stdin) == card);
+ parm[1] = scan(card, 1, 8);
+ parm[2] = scan(card, 9, 8);
+ xassert(fgets(card, sizeof(card), stdin) == card);
+ parm[3] = scan(card, 1, 5);
+ parm[4] = scan(card, 6, 5);
+ parm[5] = scan(card, 11, 5);
+ parm[6] = scan(card, 16, 5);
+ parm[7] = scan(card, 21, 5);
+ parm[8] = scan(card, 26, 5);
+ parm[9] = scan(card, 31, 10);
+ parm[10] = scan(card, 41, 5);
+ parm[11] = scan(card, 46, 5);
+ parm[12] = scan(card, 51, 5);
+ parm[13] = scan(card, 56, 5);
+ parm[14] = scan(card, 61, 10);
+ parm[15] = scan(card, 71, 10);
+ glp_netgen(NULL, 0, 0, 0, parm);
+ return 0;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/npp.c b/test/monniaux/glpk-4.65/src/api/npp.c
new file mode 100644
index 00000000..a7ae07c1
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/npp.c
@@ -0,0 +1,143 @@
+/* npp.c (LP/MIP preprocessing) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+glp_prep *glp_npp_alloc_wksp(void)
+{ /* allocate the preprocessor workspace */
+ glp_prep *prep;
+ prep = npp_create_wksp();
+ return prep;
+}
+
+void glp_npp_load_prob(glp_prep *prep, glp_prob *P, int sol, int names)
+{ /* load original problem instance */
+ if (prep->sol != 0)
+ xerror("glp_npp_load_prob: invalid call sequence (original ins"
+ "tance already loaded)\n");
+ if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
+ xerror("glp_npp_load_prob: sol = %d; invalid parameter\n",
+ sol);
+ if (!(names == GLP_ON || names == GLP_OFF))
+ xerror("glp_npp_load_prob: names = %d; invalid parameter\n",
+ names);
+ npp_load_prob(prep, P, names, sol, GLP_OFF);
+ return;
+}
+
+int glp_npp_preprocess1(glp_prep *prep, int hard)
+{ /* perform basic LP/MIP preprocessing */
+ if (prep->sol == 0)
+ xerror("glp_npp_preprocess1: invalid call sequence (original i"
+ "nstance not loaded yet)\n");
+ if (prep->pool == NULL)
+ xerror("glp_npp_preprocess1: invalid call sequence (preprocess"
+ "ing already finished)\n");
+ if (!(hard == GLP_ON || hard == GLP_OFF))
+ xerror("glp_npp_preprocess1: hard = %d; invalid parameter\n",
+ hard);
+ return npp_process_prob(prep, hard);
+}
+
+void glp_npp_build_prob(glp_prep *prep, glp_prob *Q)
+{ /* build resultant problem instance */
+ if (prep->sol == 0)
+ xerror("glp_npp_build_prob: invalid call sequence (original in"
+ "stance not loaded yet)\n");
+ if (prep->pool == NULL)
+ xerror("glp_npp_build_prob: invalid call sequence (resultant i"
+ "nstance already built)\n");
+ npp_build_prob(prep, Q);
+ return;
+}
+
+void glp_npp_postprocess(glp_prep *prep, glp_prob *Q)
+{ /* postprocess solution to resultant problem */
+ if (prep->pool != NULL)
+ xerror("glp_npp_postprocess: invalid call sequence (resultant "
+ "instance not built yet)\n");
+ if (!(prep->m == Q->m && prep->n == Q->n && prep->nnz == Q->nnz))
+ xerror("glp_npp_postprocess: resultant instance mismatch\n");
+ switch (prep->sol)
+ { case GLP_SOL:
+ if (glp_get_status(Q) != GLP_OPT)
+ xerror("glp_npp_postprocess: unable to recover non-optim"
+ "al basic solution\n");
+ break;
+ case GLP_IPT:
+ if (glp_ipt_status(Q) != GLP_OPT)
+ xerror("glp_npp_postprocess: unable to recover non-optim"
+ "al interior-point solution\n");
+ break;
+ case GLP_MIP:
+ if (!(glp_mip_status(Q) == GLP_OPT || glp_mip_status(Q) ==
+ GLP_FEAS))
+ xerror("glp_npp_postprocess: unable to recover integer n"
+ "on-feasible solution\n");
+ break;
+ default:
+ xassert(prep != prep);
+ }
+ npp_postprocess(prep, Q);
+ return;
+}
+
+void glp_npp_obtain_sol(glp_prep *prep, glp_prob *P)
+{ /* obtain solution to original problem */
+ if (prep->pool != NULL)
+ xerror("glp_npp_obtain_sol: invalid call sequence (resultant i"
+ "nstance not built yet)\n");
+ switch (prep->sol)
+ { case GLP_SOL:
+ if (prep->p_stat == 0 || prep->d_stat == 0)
+ xerror("glp_npp_obtain_sol: invalid call sequence (basic"
+ " solution not provided yet)\n");
+ break;
+ case GLP_IPT:
+ if (prep->t_stat == 0)
+ xerror("glp_npp_obtain_sol: invalid call sequence (inter"
+ "ior-point solution not provided yet)\n");
+ break;
+ case GLP_MIP:
+ if (prep->i_stat == 0)
+ xerror("glp_npp_obtain_sol: invalid call sequence (MIP s"
+ "olution not provided yet)\n");
+ break;
+ default:
+ xassert(prep != prep);
+ }
+ if (!(prep->orig_dir == P->dir && prep->orig_m == P->m &&
+ prep->orig_n == P->n && prep->orig_nnz == P->nnz))
+ xerror("glp_npp_obtain_sol: original instance mismatch\n");
+ npp_unload_sol(prep, P);
+ return;
+}
+
+void glp_npp_free_wksp(glp_prep *prep)
+{ /* free the preprocessor workspace */
+ npp_delete_wksp(prep);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/pript.c b/test/monniaux/glpk-4.65/src/api/pript.c
new file mode 100644
index 00000000..f123089d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/pript.c
@@ -0,0 +1,186 @@
+/* pript.c (write interior-point solution in printable format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+#define xfprintf glp_format
+
+int glp_print_ipt(glp_prob *P, const char *fname)
+{ /* write interior-point solution in printable format */
+ glp_file *fp;
+ GLPROW *row;
+ GLPCOL *col;
+ int i, j, t, ae_ind, re_ind, ret;
+ double ae_max, re_max;
+ xprintf("Writing interior-point solution to '%s'...\n", fname);
+ fp = glp_open(fname, "w");
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xfprintf(fp, "%-12s%s\n", "Problem:",
+ P->name == NULL ? "" : P->name);
+ xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
+ xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
+ xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
+ t = glp_ipt_status(P);
+ xfprintf(fp, "%-12s%s\n", "Status:",
+ t == GLP_OPT ? "OPTIMAL" :
+ t == GLP_UNDEF ? "UNDEFINED" :
+ t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
+ t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : "???");
+ xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+ P->obj == NULL ? "" : P->obj,
+ P->obj == NULL ? "" : " = ", P->ipt_obj,
+ P->dir == GLP_MIN ? "MINimum" :
+ P->dir == GLP_MAX ? "MAXimum" : "???");
+ xfprintf(fp, "\n");
+ xfprintf(fp, " No. Row name Activity Lower bound "
+ " Upper bound Marginal\n");
+ xfprintf(fp, "------ ------------ ------------- ------------- "
+ "------------- -------------\n");
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ xfprintf(fp, "%6d ", i);
+ if (row->name == NULL || strlen(row->name) <= 12)
+ xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
+ else
+ xfprintf(fp, "%s\n%20s", row->name, "");
+ xfprintf(fp, "%3s", "");
+ xfprintf(fp, "%13.6g ",
+ fabs(row->pval) <= 1e-9 ? 0.0 : row->pval);
+ if (row->type == GLP_LO || row->type == GLP_DB ||
+ row->type == GLP_FX)
+ xfprintf(fp, "%13.6g ", row->lb);
+ else
+ xfprintf(fp, "%13s ", "");
+ if (row->type == GLP_UP || row->type == GLP_DB)
+ xfprintf(fp, "%13.6g ", row->ub);
+ else
+ xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
+ if (fabs(row->dval) <= 1e-9)
+ xfprintf(fp, "%13s", "< eps");
+ else
+ xfprintf(fp, "%13.6g ", row->dval);
+ xfprintf(fp, "\n");
+ }
+ xfprintf(fp, "\n");
+ xfprintf(fp, " No. Column name Activity Lower bound "
+ " Upper bound Marginal\n");
+ xfprintf(fp, "------ ------------ ------------- ------------- "
+ "------------- -------------\n");
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ xfprintf(fp, "%6d ", j);
+ if (col->name == NULL || strlen(col->name) <= 12)
+ xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
+ else
+ xfprintf(fp, "%s\n%20s", col->name, "");
+ xfprintf(fp, "%3s", "");
+ xfprintf(fp, "%13.6g ",
+ fabs(col->pval) <= 1e-9 ? 0.0 : col->pval);
+ if (col->type == GLP_LO || col->type == GLP_DB ||
+ col->type == GLP_FX)
+ xfprintf(fp, "%13.6g ", col->lb);
+ else
+ xfprintf(fp, "%13s ", "");
+ if (col->type == GLP_UP || col->type == GLP_DB)
+ xfprintf(fp, "%13.6g ", col->ub);
+ else
+ xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
+ if (fabs(col->dval) <= 1e-9)
+ xfprintf(fp, "%13s", "< eps");
+ else
+ xfprintf(fp, "%13.6g ", col->dval);
+ xfprintf(fp, "\n");
+ }
+ xfprintf(fp, "\n");
+ xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
+ xfprintf(fp, "\n");
+ glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+ &re_ind);
+ xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
+ ae_max, ae_ind);
+ xfprintf(fp, " max.rel.err = %.2e on row %d\n",
+ re_max, re_ind);
+ xfprintf(fp, "%8s%s\n", "",
+ re_max <= 1e-9 ? "High quality" :
+ re_max <= 1e-6 ? "Medium quality" :
+ re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
+ xfprintf(fp, "\n");
+ glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+ &re_ind);
+ xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
+ ae_max, ae_ind <= P->m ? "row" : "column",
+ ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+ xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
+ re_max, re_ind <= P->m ? "row" : "column",
+ re_ind <= P->m ? re_ind : re_ind - P->m);
+ xfprintf(fp, "%8s%s\n", "",
+ re_max <= 1e-9 ? "High quality" :
+ re_max <= 1e-6 ? "Medium quality" :
+ re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
+ "E");
+ xfprintf(fp, "\n");
+ glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
+ &re_ind);
+ xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
+ ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
+ xfprintf(fp, " max.rel.err = %.2e on column %d\n",
+ re_max, re_ind == 0 ? 0 : re_ind - P->m);
+ xfprintf(fp, "%8s%s\n", "",
+ re_max <= 1e-9 ? "High quality" :
+ re_max <= 1e-6 ? "Medium quality" :
+ re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
+ xfprintf(fp, "\n");
+ glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
+ &re_ind);
+ xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
+ ae_max, ae_ind <= P->m ? "row" : "column",
+ ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+ xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
+ re_max, re_ind <= P->m ? "row" : "column",
+ re_ind <= P->m ? re_ind : re_ind - P->m);
+ xfprintf(fp, "%8s%s\n", "",
+ re_max <= 1e-9 ? "High quality" :
+ re_max <= 1e-6 ? "Medium quality" :
+ re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
+ ;
+ xfprintf(fp, "\n");
+ xfprintf(fp, "End of output\n");
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/prmip.c b/test/monniaux/glpk-4.65/src/api/prmip.c
new file mode 100644
index 00000000..885ed82a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/prmip.c
@@ -0,0 +1,155 @@
+/* prmip.c (write MIP solution in printable format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+#define xfprintf glp_format
+
+int glp_print_mip(glp_prob *P, const char *fname)
+{ /* write MIP solution in printable format */
+ glp_file *fp;
+ GLPROW *row;
+ GLPCOL *col;
+ int i, j, t, ae_ind, re_ind, ret;
+ double ae_max, re_max;
+ xprintf("Writing MIP solution to '%s'...\n", fname);
+ fp = glp_open(fname, "w");
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xfprintf(fp, "%-12s%s\n", "Problem:",
+ P->name == NULL ? "" : P->name);
+ xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
+ xfprintf(fp, "%-12s%d (%d integer, %d binary)\n", "Columns:",
+ P->n, glp_get_num_int(P), glp_get_num_bin(P));
+ xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
+ t = glp_mip_status(P);
+ xfprintf(fp, "%-12s%s\n", "Status:",
+ t == GLP_OPT ? "INTEGER OPTIMAL" :
+ t == GLP_FEAS ? "INTEGER NON-OPTIMAL" :
+ t == GLP_NOFEAS ? "INTEGER EMPTY" :
+ t == GLP_UNDEF ? "INTEGER UNDEFINED" : "???");
+ xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+ P->obj == NULL ? "" : P->obj,
+ P->obj == NULL ? "" : " = ", P->mip_obj,
+ P->dir == GLP_MIN ? "MINimum" :
+ P->dir == GLP_MAX ? "MAXimum" : "???");
+ xfprintf(fp, "\n");
+ xfprintf(fp, " No. Row name Activity Lower bound "
+ " Upper bound\n");
+ xfprintf(fp, "------ ------------ ------------- ------------- "
+ "-------------\n");
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ xfprintf(fp, "%6d ", i);
+ if (row->name == NULL || strlen(row->name) <= 12)
+ xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
+ else
+ xfprintf(fp, "%s\n%20s", row->name, "");
+ xfprintf(fp, "%3s", "");
+ xfprintf(fp, "%13.6g ",
+ fabs(row->mipx) <= 1e-9 ? 0.0 : row->mipx);
+ if (row->type == GLP_LO || row->type == GLP_DB ||
+ row->type == GLP_FX)
+ xfprintf(fp, "%13.6g ", row->lb);
+ else
+ xfprintf(fp, "%13s ", "");
+ if (row->type == GLP_UP || row->type == GLP_DB)
+ xfprintf(fp, "%13.6g ", row->ub);
+ else
+ xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
+ xfprintf(fp, "\n");
+ }
+ xfprintf(fp, "\n");
+ xfprintf(fp, " No. Column name Activity Lower bound "
+ " Upper bound\n");
+ xfprintf(fp, "------ ------------ ------------- ------------- "
+ "-------------\n");
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ xfprintf(fp, "%6d ", j);
+ if (col->name == NULL || strlen(col->name) <= 12)
+ xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
+ else
+ xfprintf(fp, "%s\n%20s", col->name, "");
+ xfprintf(fp, "%s ",
+ col->kind == GLP_CV ? " " :
+ col->kind == GLP_IV ? "*" : "?");
+ xfprintf(fp, "%13.6g ",
+ fabs(col->mipx) <= 1e-9 ? 0.0 : col->mipx);
+ if (col->type == GLP_LO || col->type == GLP_DB ||
+ col->type == GLP_FX)
+ xfprintf(fp, "%13.6g ", col->lb);
+ else
+ xfprintf(fp, "%13s ", "");
+ if (col->type == GLP_UP || col->type == GLP_DB)
+ xfprintf(fp, "%13.6g ", col->ub);
+ else
+ xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
+ xfprintf(fp, "\n");
+ }
+ xfprintf(fp, "\n");
+ xfprintf(fp, "Integer feasibility conditions:\n");
+ xfprintf(fp, "\n");
+ glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+ &re_ind);
+ xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
+ ae_max, ae_ind);
+ xfprintf(fp, " max.rel.err = %.2e on row %d\n",
+ re_max, re_ind);
+ xfprintf(fp, "%8s%s\n", "",
+ re_max <= 1e-9 ? "High quality" :
+ re_max <= 1e-6 ? "Medium quality" :
+ re_max <= 1e-3 ? "Low quality" : "SOLUTION IS WRONG");
+ xfprintf(fp, "\n");
+ glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+ &re_ind);
+ xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
+ ae_max, ae_ind <= P->m ? "row" : "column",
+ ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+ xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
+ re_max, re_ind <= P->m ? "row" : "column",
+ re_ind <= P->m ? re_ind : re_ind - P->m);
+ xfprintf(fp, "%8s%s\n", "",
+ re_max <= 1e-9 ? "High quality" :
+ re_max <= 1e-6 ? "Medium quality" :
+ re_max <= 1e-3 ? "Low quality" : "SOLUTION IS INFEASIBLE");
+ xfprintf(fp, "\n");
+ xfprintf(fp, "End of output\n");
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/prob.h b/test/monniaux/glpk-4.65/src/api/prob.h
new file mode 100644
index 00000000..cc9389b5
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/prob.h
@@ -0,0 +1,286 @@
+/* prob.h (LP/MIP problem object) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#ifndef PROB_H
+#define PROB_H
+
+#include "avl.h"
+#include "bfd.h"
+#include "dmp.h"
+#if 1 /* 28/III-2016 */
+#define GLP_UNDOC 1
+#endif
+#include "glpk.h"
+
+typedef struct GLPROW GLPROW;
+typedef struct GLPCOL GLPCOL;
+typedef struct GLPAIJ GLPAIJ;
+
+#if 0 /* 04/IV-2016 */
+#define GLP_PROB_MAGIC 0xD7D9D6C2
+#endif
+
+struct glp_prob
+{ /* LP/MIP problem object */
+#if 0 /* 04/IV-2016 */
+ unsigned magic;
+ /* magic value used for debugging */
+#endif
+ DMP *pool;
+ /* memory pool to store problem object components */
+ glp_tree *tree;
+ /* pointer to the search tree; set by the MIP solver when this
+ object is used in the tree as a core MIP object */
+#if 0 /* 08/III-2014 */
+ void *parms;
+ /* reserved for backward compatibility */
+#endif
+ /*--------------------------------------------------------------*/
+ /* LP/MIP data */
+ char *name;
+ /* problem name (1 to 255 chars); NULL means no name is assigned
+ to the problem */
+ char *obj;
+ /* objective function name (1 to 255 chars); NULL means no name
+ is assigned to the objective function */
+ int dir;
+ /* optimization direction flag (objective "sense"):
+ GLP_MIN - minimization
+ GLP_MAX - maximization */
+ double c0;
+ /* constant term of the objective function ("shift") */
+ int m_max;
+ /* length of the array of rows (enlarged automatically) */
+ int n_max;
+ /* length of the array of columns (enlarged automatically) */
+ int m;
+ /* number of rows, 0 <= m <= m_max */
+ int n;
+ /* number of columns, 0 <= n <= n_max */
+ int nnz;
+ /* number of non-zero constraint coefficients, nnz >= 0 */
+ GLPROW **row; /* GLPROW *row[1+m_max]; */
+ /* row[i], 1 <= i <= m, is a pointer to i-th row */
+ GLPCOL **col; /* GLPCOL *col[1+n_max]; */
+ /* col[j], 1 <= j <= n, is a pointer to j-th column */
+ AVL *r_tree;
+ /* row index to find rows by their names; NULL means this index
+ does not exist */
+ AVL *c_tree;
+ /* column index to find columns by their names; NULL means this
+ index does not exist */
+ /*--------------------------------------------------------------*/
+ /* basis factorization (LP) */
+ int valid;
+ /* the factorization is valid only if this flag is set */
+ int *head; /* int head[1+m_max]; */
+ /* basis header (valid only if the factorization is valid);
+ head[i] = k is the ordinal number of auxiliary (1 <= k <= m)
+ or structural (m+1 <= k <= m+n) variable which corresponds to
+ i-th basic variable xB[i], 1 <= i <= m */
+#if 0 /* 08/III-2014 */
+ glp_bfcp *bfcp;
+ /* basis factorization control parameters; may be NULL */
+#endif
+ BFD *bfd; /* BFD bfd[1:m,1:m]; */
+ /* basis factorization driver; may be NULL */
+ /*--------------------------------------------------------------*/
+ /* basic solution (LP) */
+ int pbs_stat;
+ /* primal basic solution status:
+ GLP_UNDEF - primal solution is undefined
+ GLP_FEAS - primal solution is feasible
+ GLP_INFEAS - primal solution is infeasible
+ GLP_NOFEAS - no primal feasible solution exists */
+ int dbs_stat;
+ /* dual basic solution status:
+ GLP_UNDEF - dual solution is undefined
+ GLP_FEAS - dual solution is feasible
+ GLP_INFEAS - dual solution is infeasible
+ GLP_NOFEAS - no dual feasible solution exists */
+ double obj_val;
+ /* objective function value */
+ int it_cnt;
+ /* simplex method iteration count; increases by one on performing
+ one simplex iteration */
+ int some;
+ /* ordinal number of some auxiliary or structural variable having
+ certain property, 0 <= some <= m+n */
+ /*--------------------------------------------------------------*/
+ /* interior-point solution (LP) */
+ int ipt_stat;
+ /* interior-point solution status:
+ GLP_UNDEF - interior solution is undefined
+ GLP_OPT - interior solution is optimal
+ GLP_INFEAS - interior solution is infeasible
+ GLP_NOFEAS - no feasible solution exists */
+ double ipt_obj;
+ /* objective function value */
+ /*--------------------------------------------------------------*/
+ /* integer solution (MIP) */
+ int mip_stat;
+ /* integer solution status:
+ GLP_UNDEF - integer solution is undefined
+ GLP_OPT - integer solution is optimal
+ GLP_FEAS - integer solution is feasible
+ GLP_NOFEAS - no integer solution exists */
+ double mip_obj;
+ /* objective function value */
+};
+
+struct GLPROW
+{ /* LP/MIP row (auxiliary variable) */
+ int i;
+ /* ordinal number (1 to m) assigned to this row */
+ char *name;
+ /* row name (1 to 255 chars); NULL means no name is assigned to
+ this row */
+ AVLNODE *node;
+ /* pointer to corresponding node in the row index; NULL means
+ that either the row index does not exist or this row has no
+ name assigned */
+#if 1 /* 20/IX-2008 */
+ int level;
+ unsigned char origin;
+ unsigned char klass;
+#endif
+ int type;
+ /* type of the auxiliary variable:
+ GLP_FR - free variable
+ GLP_LO - variable with lower bound
+ GLP_UP - variable with upper bound
+ GLP_DB - double-bounded variable
+ GLP_FX - fixed variable */
+ double lb; /* non-scaled */
+ /* lower bound; if the row has no lower bound, lb is zero */
+ double ub; /* non-scaled */
+ /* upper bound; if the row has no upper bound, ub is zero */
+ /* if the row type is GLP_FX, ub is equal to lb */
+ GLPAIJ *ptr; /* non-scaled */
+ /* pointer to doubly linked list of constraint coefficients which
+ are placed in this row */
+ double rii;
+ /* diagonal element r[i,i] of scaling matrix R for this row;
+ if the scaling is not used, r[i,i] is 1 */
+ int stat;
+ /* status of the auxiliary variable:
+ GLP_BS - basic variable
+ GLP_NL - non-basic variable on lower bound
+ GLP_NU - non-basic variable on upper bound
+ GLP_NF - non-basic free variable
+ GLP_NS - non-basic fixed variable */
+ int bind;
+ /* if the auxiliary variable is basic, head[bind] refers to this
+ row, otherwise, bind is 0; this attribute is valid only if the
+ basis factorization is valid */
+ double prim; /* non-scaled */
+ /* primal value of the auxiliary variable in basic solution */
+ double dual; /* non-scaled */
+ /* dual value of the auxiliary variable in basic solution */
+ double pval; /* non-scaled */
+ /* primal value of the auxiliary variable in interior solution */
+ double dval; /* non-scaled */
+ /* dual value of the auxiliary variable in interior solution */
+ double mipx; /* non-scaled */
+ /* primal value of the auxiliary variable in integer solution */
+};
+
+struct GLPCOL
+{ /* LP/MIP column (structural variable) */
+ int j;
+ /* ordinal number (1 to n) assigned to this column */
+ char *name;
+ /* column name (1 to 255 chars); NULL means no name is assigned
+ to this column */
+ AVLNODE *node;
+ /* pointer to corresponding node in the column index; NULL means
+ that either the column index does not exist or the column has
+ no name assigned */
+ int kind;
+ /* kind of the structural variable:
+ GLP_CV - continuous variable
+ GLP_IV - integer or binary variable */
+ int type;
+ /* type of the structural variable:
+ GLP_FR - free variable
+ GLP_LO - variable with lower bound
+ GLP_UP - variable with upper bound
+ GLP_DB - double-bounded variable
+ GLP_FX - fixed variable */
+ double lb; /* non-scaled */
+ /* lower bound; if the column has no lower bound, lb is zero */
+ double ub; /* non-scaled */
+ /* upper bound; if the column has no upper bound, ub is zero */
+ /* if the column type is GLP_FX, ub is equal to lb */
+ double coef; /* non-scaled */
+ /* objective coefficient at the structural variable */
+ GLPAIJ *ptr; /* non-scaled */
+ /* pointer to doubly linked list of constraint coefficients which
+ are placed in this column */
+ double sjj;
+ /* diagonal element s[j,j] of scaling matrix S for this column;
+ if the scaling is not used, s[j,j] is 1 */
+ int stat;
+ /* status of the structural variable:
+ GLP_BS - basic variable
+ GLP_NL - non-basic variable on lower bound
+ GLP_NU - non-basic variable on upper bound
+ GLP_NF - non-basic free variable
+ GLP_NS - non-basic fixed variable */
+ int bind;
+ /* if the structural variable is basic, head[bind] refers to
+ this column; otherwise, bind is 0; this attribute is valid only
+ if the basis factorization is valid */
+ double prim; /* non-scaled */
+ /* primal value of the structural variable in basic solution */
+ double dual; /* non-scaled */
+ /* dual value of the structural variable in basic solution */
+ double pval; /* non-scaled */
+ /* primal value of the structural variable in interior solution */
+ double dval; /* non-scaled */
+ /* dual value of the structural variable in interior solution */
+ double mipx; /* non-scaled */
+ /* primal value of the structural variable in integer solution */
+};
+
+struct GLPAIJ
+{ /* constraint coefficient a[i,j] */
+ GLPROW *row;
+ /* pointer to row, where this coefficient is placed */
+ GLPCOL *col;
+ /* pointer to column, where this coefficient is placed */
+ double val;
+ /* numeric (non-zero) value of this coefficient */
+ GLPAIJ *r_prev;
+ /* pointer to previous coefficient in the same row */
+ GLPAIJ *r_next;
+ /* pointer to next coefficient in the same row */
+ GLPAIJ *c_prev;
+ /* pointer to previous coefficient in the same column */
+ GLPAIJ *c_next;
+ /* pointer to next coefficient in the same column */
+};
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/prob1.c b/test/monniaux/glpk-4.65/src/api/prob1.c
new file mode 100644
index 00000000..6afad442
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/prob1.c
@@ -0,0 +1,1588 @@
+/* prob1.c (problem creating and modifying routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+
+/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
+
+#define M_MAX 100000000 /* = 100*10^6 */
+/* maximal number of rows in the problem object */
+
+#define N_MAX 100000000 /* = 100*10^6 */
+/* maximal number of columns in the problem object */
+
+#define NNZ_MAX 500000000 /* = 500*10^6 */
+/* maximal number of constraint coefficients in the problem object */
+
+/***********************************************************************
+* NAME
+*
+* glp_create_prob - create problem object
+*
+* SYNOPSIS
+*
+* glp_prob *glp_create_prob(void);
+*
+* DESCRIPTION
+*
+* The routine glp_create_prob creates a new problem object, which is
+* initially "empty", i.e. has no rows and columns.
+*
+* RETURNS
+*
+* The routine returns a pointer to the object created, which should be
+* used in any subsequent operations on this object. */
+
+static void create_prob(glp_prob *lp)
+#if 0 /* 04/IV-2016 */
+{ lp->magic = GLP_PROB_MAGIC;
+#else
+{
+#endif
+ lp->pool = dmp_create_pool();
+#if 0 /* 08/III-2014 */
+#if 0 /* 17/XI-2009 */
+ lp->cps = xmalloc(sizeof(struct LPXCPS));
+ lpx_reset_parms(lp);
+#else
+ lp->parms = NULL;
+#endif
+#endif
+ lp->tree = NULL;
+#if 0
+ lp->lwa = 0;
+ lp->cwa = NULL;
+#endif
+ /* LP/MIP data */
+ lp->name = NULL;
+ lp->obj = NULL;
+ lp->dir = GLP_MIN;
+ lp->c0 = 0.0;
+ lp->m_max = 100;
+ lp->n_max = 200;
+ lp->m = lp->n = 0;
+ lp->nnz = 0;
+ lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
+ lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
+ lp->r_tree = lp->c_tree = NULL;
+ /* basis factorization */
+ lp->valid = 0;
+ lp->head = xcalloc(1+lp->m_max, sizeof(int));
+#if 0 /* 08/III-2014 */
+ lp->bfcp = NULL;
+#endif
+ lp->bfd = NULL;
+ /* basic solution (LP) */
+ lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+ lp->obj_val = 0.0;
+ lp->it_cnt = 0;
+ lp->some = 0;
+ /* interior-point solution (LP) */
+ lp->ipt_stat = GLP_UNDEF;
+ lp->ipt_obj = 0.0;
+ /* integer solution (MIP) */
+ lp->mip_stat = GLP_UNDEF;
+ lp->mip_obj = 0.0;
+ return;
+}
+
+glp_prob *glp_create_prob(void)
+{ glp_prob *lp;
+ lp = xmalloc(sizeof(glp_prob));
+ create_prob(lp);
+ return lp;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_prob_name - assign (change) problem name
+*
+* SYNOPSIS
+*
+* void glp_set_prob_name(glp_prob *lp, const char *name);
+*
+* DESCRIPTION
+*
+* The routine glp_set_prob_name assigns a given symbolic name (1 up to
+* 255 characters) to the specified problem object.
+*
+* If the parameter name is NULL or empty string, the routine erases an
+* existing symbolic name of the problem object. */
+
+void glp_set_prob_name(glp_prob *lp, const char *name)
+{ glp_tree *tree = lp->tree;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_set_prob_name: operation not allowed\n");
+ if (lp->name != NULL)
+ { dmp_free_atom(lp->pool, lp->name, strlen(lp->name)+1);
+ lp->name = NULL;
+ }
+ if (!(name == NULL || name[0] == '\0'))
+ { int k;
+ for (k = 0; name[k] != '\0'; k++)
+ { if (k == 256)
+ xerror("glp_set_prob_name: problem name too long\n");
+ if (iscntrl((unsigned char)name[k]))
+ xerror("glp_set_prob_name: problem name contains invalid"
+ " character(s)\n");
+ }
+ lp->name = dmp_get_atom(lp->pool, strlen(name)+1);
+ strcpy(lp->name, name);
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_obj_name - assign (change) objective function name
+*
+* SYNOPSIS
+*
+* void glp_set_obj_name(glp_prob *lp, const char *name);
+*
+* DESCRIPTION
+*
+* The routine glp_set_obj_name assigns a given symbolic name (1 up to
+* 255 characters) to the objective function of the specified problem
+* object.
+*
+* If the parameter name is NULL or empty string, the routine erases an
+* existing name of the objective function. */
+
+void glp_set_obj_name(glp_prob *lp, const char *name)
+{ glp_tree *tree = lp->tree;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_set_obj_name: operation not allowed\n");
+ if (lp->obj != NULL)
+ { dmp_free_atom(lp->pool, lp->obj, strlen(lp->obj)+1);
+ lp->obj = NULL;
+ }
+ if (!(name == NULL || name[0] == '\0'))
+ { int k;
+ for (k = 0; name[k] != '\0'; k++)
+ { if (k == 256)
+ xerror("glp_set_obj_name: objective name too long\n");
+ if (iscntrl((unsigned char)name[k]))
+ xerror("glp_set_obj_name: objective name contains invali"
+ "d character(s)\n");
+ }
+ lp->obj = dmp_get_atom(lp->pool, strlen(name)+1);
+ strcpy(lp->obj, name);
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_obj_dir - set (change) optimization direction flag
+*
+* SYNOPSIS
+*
+* void glp_set_obj_dir(glp_prob *lp, int dir);
+*
+* DESCRIPTION
+*
+* The routine glp_set_obj_dir sets (changes) optimization direction
+* flag (i.e. "sense" of the objective function) as specified by the
+* parameter dir:
+*
+* GLP_MIN - minimization;
+* GLP_MAX - maximization. */
+
+void glp_set_obj_dir(glp_prob *lp, int dir)
+{ glp_tree *tree = lp->tree;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_set_obj_dir: operation not allowed\n");
+ if (!(dir == GLP_MIN || dir == GLP_MAX))
+ xerror("glp_set_obj_dir: dir = %d; invalid direction flag\n",
+ dir);
+ lp->dir = dir;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_add_rows - add new rows to problem object
+*
+* SYNOPSIS
+*
+* int glp_add_rows(glp_prob *lp, int nrs);
+*
+* DESCRIPTION
+*
+* The routine glp_add_rows adds nrs rows (constraints) to the specified
+* problem object. New rows are always added to the end of the row list,
+* so the ordinal numbers of existing rows remain unchanged.
+*
+* Being added each new row is initially free (unbounded) and has empty
+* list of the constraint coefficients.
+*
+* RETURNS
+*
+* The routine glp_add_rows returns the ordinal number of the first new
+* row added to the problem object. */
+
+int glp_add_rows(glp_prob *lp, int nrs)
+{ glp_tree *tree = lp->tree;
+ GLPROW *row;
+ int m_new, i;
+ /* determine new number of rows */
+ if (nrs < 1)
+ xerror("glp_add_rows: nrs = %d; invalid number of rows\n",
+ nrs);
+ if (nrs > M_MAX - lp->m)
+ xerror("glp_add_rows: nrs = %d; too many rows\n", nrs);
+ m_new = lp->m + nrs;
+ /* increase the room, if necessary */
+ if (lp->m_max < m_new)
+ { GLPROW **save = lp->row;
+ while (lp->m_max < m_new)
+ { lp->m_max += lp->m_max;
+ xassert(lp->m_max > 0);
+ }
+ lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
+ memcpy(&lp->row[1], &save[1], lp->m * sizeof(GLPROW *));
+ xfree(save);
+ /* do not forget about the basis header */
+ xfree(lp->head);
+ lp->head = xcalloc(1+lp->m_max, sizeof(int));
+ }
+ /* add new rows to the end of the row list */
+ for (i = lp->m+1; i <= m_new; i++)
+ { /* create row descriptor */
+ lp->row[i] = row = dmp_get_atom(lp->pool, sizeof(GLPROW));
+ row->i = i;
+ row->name = NULL;
+ row->node = NULL;
+#if 1 /* 20/IX-2008 */
+ row->level = 0;
+ row->origin = 0;
+ row->klass = 0;
+ if (tree != NULL)
+ { switch (tree->reason)
+ { case 0:
+ break;
+ case GLP_IROWGEN:
+ xassert(tree->curr != NULL);
+ row->level = tree->curr->level;
+ row->origin = GLP_RF_LAZY;
+ break;
+ case GLP_ICUTGEN:
+ xassert(tree->curr != NULL);
+ row->level = tree->curr->level;
+ row->origin = GLP_RF_CUT;
+ break;
+ default:
+ xassert(tree != tree);
+ }
+ }
+#endif
+ row->type = GLP_FR;
+ row->lb = row->ub = 0.0;
+ row->ptr = NULL;
+ row->rii = 1.0;
+ row->stat = GLP_BS;
+#if 0
+ row->bind = -1;
+#else
+ row->bind = 0;
+#endif
+ row->prim = row->dual = 0.0;
+ row->pval = row->dval = 0.0;
+ row->mipx = 0.0;
+ }
+ /* set new number of rows */
+ lp->m = m_new;
+ /* invalidate the basis factorization */
+ lp->valid = 0;
+#if 1
+ if (tree != NULL && tree->reason != 0) tree->reopt = 1;
+#endif
+ /* return the ordinal number of the first row added */
+ return m_new - nrs + 1;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_add_cols - add new columns to problem object
+*
+* SYNOPSIS
+*
+* int glp_add_cols(glp_prob *lp, int ncs);
+*
+* DESCRIPTION
+*
+* The routine glp_add_cols adds ncs columns (structural variables) to
+* the specified problem object. New columns are always added to the end
+* of the column list, so the ordinal numbers of existing columns remain
+* unchanged.
+*
+* Being added each new column is initially fixed at zero and has empty
+* list of the constraint coefficients.
+*
+* RETURNS
+*
+* The routine glp_add_cols returns the ordinal number of the first new
+* column added to the problem object. */
+
+int glp_add_cols(glp_prob *lp, int ncs)
+{ glp_tree *tree = lp->tree;
+ GLPCOL *col;
+ int n_new, j;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_add_cols: operation not allowed\n");
+ /* determine new number of columns */
+ if (ncs < 1)
+ xerror("glp_add_cols: ncs = %d; invalid number of columns\n",
+ ncs);
+ if (ncs > N_MAX - lp->n)
+ xerror("glp_add_cols: ncs = %d; too many columns\n", ncs);
+ n_new = lp->n + ncs;
+ /* increase the room, if necessary */
+ if (lp->n_max < n_new)
+ { GLPCOL **save = lp->col;
+ while (lp->n_max < n_new)
+ { lp->n_max += lp->n_max;
+ xassert(lp->n_max > 0);
+ }
+ lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
+ memcpy(&lp->col[1], &save[1], lp->n * sizeof(GLPCOL *));
+ xfree(save);
+ }
+ /* add new columns to the end of the column list */
+ for (j = lp->n+1; j <= n_new; j++)
+ { /* create column descriptor */
+ lp->col[j] = col = dmp_get_atom(lp->pool, sizeof(GLPCOL));
+ col->j = j;
+ col->name = NULL;
+ col->node = NULL;
+ col->kind = GLP_CV;
+ col->type = GLP_FX;
+ col->lb = col->ub = 0.0;
+ col->coef = 0.0;
+ col->ptr = NULL;
+ col->sjj = 1.0;
+ col->stat = GLP_NS;
+#if 0
+ col->bind = -1;
+#else
+ col->bind = 0; /* the basis may remain valid */
+#endif
+ col->prim = col->dual = 0.0;
+ col->pval = col->dval = 0.0;
+ col->mipx = 0.0;
+ }
+ /* set new number of columns */
+ lp->n = n_new;
+ /* return the ordinal number of the first column added */
+ return n_new - ncs + 1;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_row_name - assign (change) row name
+*
+* SYNOPSIS
+*
+* void glp_set_row_name(glp_prob *lp, int i, const char *name);
+*
+* DESCRIPTION
+*
+* The routine glp_set_row_name assigns a given symbolic name (1 up to
+* 255 characters) to i-th row (auxiliary variable) of the specified
+* problem object.
+*
+* If the parameter name is NULL or empty string, the routine erases an
+* existing name of i-th row. */
+
+void glp_set_row_name(glp_prob *lp, int i, const char *name)
+{ glp_tree *tree = lp->tree;
+ GLPROW *row;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_set_row_name: i = %d; row number out of range\n",
+ i);
+ row = lp->row[i];
+ if (tree != NULL && tree->reason != 0)
+ { xassert(tree->curr != NULL);
+ xassert(row->level == tree->curr->level);
+ }
+ if (row->name != NULL)
+ { if (row->node != NULL)
+ { xassert(lp->r_tree != NULL);
+ avl_delete_node(lp->r_tree, row->node);
+ row->node = NULL;
+ }
+ dmp_free_atom(lp->pool, row->name, strlen(row->name)+1);
+ row->name = NULL;
+ }
+ if (!(name == NULL || name[0] == '\0'))
+ { int k;
+ for (k = 0; name[k] != '\0'; k++)
+ { if (k == 256)
+ xerror("glp_set_row_name: i = %d; row name too long\n",
+ i);
+ if (iscntrl((unsigned char)name[k]))
+ xerror("glp_set_row_name: i = %d: row name contains inva"
+ "lid character(s)\n", i);
+ }
+ row->name = dmp_get_atom(lp->pool, strlen(name)+1);
+ strcpy(row->name, name);
+ if (lp->r_tree != NULL)
+ { xassert(row->node == NULL);
+ row->node = avl_insert_node(lp->r_tree, row->name);
+ avl_set_node_link(row->node, row);
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_col_name - assign (change) column name
+*
+* SYNOPSIS
+*
+* void glp_set_col_name(glp_prob *lp, int j, const char *name);
+*
+* DESCRIPTION
+*
+* The routine glp_set_col_name assigns a given symbolic name (1 up to
+* 255 characters) to j-th column (structural variable) of the specified
+* problem object.
+*
+* If the parameter name is NULL or empty string, the routine erases an
+* existing name of j-th column. */
+
+void glp_set_col_name(glp_prob *lp, int j, const char *name)
+{ glp_tree *tree = lp->tree;
+ GLPCOL *col;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_set_col_name: operation not allowed\n");
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_set_col_name: j = %d; column number out of range\n"
+ , j);
+ col = lp->col[j];
+ if (col->name != NULL)
+ { if (col->node != NULL)
+ { xassert(lp->c_tree != NULL);
+ avl_delete_node(lp->c_tree, col->node);
+ col->node = NULL;
+ }
+ dmp_free_atom(lp->pool, col->name, strlen(col->name)+1);
+ col->name = NULL;
+ }
+ if (!(name == NULL || name[0] == '\0'))
+ { int k;
+ for (k = 0; name[k] != '\0'; k++)
+ { if (k == 256)
+ xerror("glp_set_col_name: j = %d; column name too long\n"
+ , j);
+ if (iscntrl((unsigned char)name[k]))
+ xerror("glp_set_col_name: j = %d: column name contains i"
+ "nvalid character(s)\n", j);
+ }
+ col->name = dmp_get_atom(lp->pool, strlen(name)+1);
+ strcpy(col->name, name);
+ if (lp->c_tree != NULL && col->name != NULL)
+ { xassert(col->node == NULL);
+ col->node = avl_insert_node(lp->c_tree, col->name);
+ avl_set_node_link(col->node, col);
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_row_bnds - set (change) row bounds
+*
+* SYNOPSIS
+*
+* void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
+* double ub);
+*
+* DESCRIPTION
+*
+* The routine glp_set_row_bnds sets (changes) the type and bounds of
+* i-th row (auxiliary variable) of the specified problem object.
+*
+* Parameters type, lb, and ub specify the type, lower bound, and upper
+* bound, respectively, as follows:
+*
+* Type Bounds Comments
+* ------------------------------------------------------
+* GLP_FR -inf < x < +inf Free variable
+* GLP_LO lb <= x < +inf Variable with lower bound
+* GLP_UP -inf < x <= ub Variable with upper bound
+* GLP_DB lb <= x <= ub Double-bounded variable
+* GLP_FX x = lb Fixed variable
+*
+* where x is the auxiliary variable associated with i-th row.
+*
+* If the row has no lower bound, the parameter lb is ignored. If the
+* row has no upper bound, the parameter ub is ignored. If the row is
+* an equality constraint (i.e. the corresponding auxiliary variable is
+* of fixed type), only the parameter lb is used while the parameter ub
+* is ignored. */
+
+void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
+ double ub)
+{ GLPROW *row;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_set_row_bnds: i = %d; row number out of range\n",
+ i);
+ row = lp->row[i];
+ row->type = type;
+ switch (type)
+ { case GLP_FR:
+ row->lb = row->ub = 0.0;
+ if (row->stat != GLP_BS) row->stat = GLP_NF;
+ break;
+ case GLP_LO:
+ row->lb = lb, row->ub = 0.0;
+ if (row->stat != GLP_BS) row->stat = GLP_NL;
+ break;
+ case GLP_UP:
+ row->lb = 0.0, row->ub = ub;
+ if (row->stat != GLP_BS) row->stat = GLP_NU;
+ break;
+ case GLP_DB:
+ row->lb = lb, row->ub = ub;
+ if (!(row->stat == GLP_BS ||
+ row->stat == GLP_NL || row->stat == GLP_NU))
+ row->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
+ break;
+ case GLP_FX:
+ row->lb = row->ub = lb;
+ if (row->stat != GLP_BS) row->stat = GLP_NS;
+ break;
+ default:
+ xerror("glp_set_row_bnds: i = %d; type = %d; invalid row ty"
+ "pe\n", i, type);
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_col_bnds - set (change) column bounds
+*
+* SYNOPSIS
+*
+* void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
+* double ub);
+*
+* DESCRIPTION
+*
+* The routine glp_set_col_bnds sets (changes) the type and bounds of
+* j-th column (structural variable) of the specified problem object.
+*
+* Parameters type, lb, and ub specify the type, lower bound, and upper
+* bound, respectively, as follows:
+*
+* Type Bounds Comments
+* ------------------------------------------------------
+* GLP_FR -inf < x < +inf Free variable
+* GLP_LO lb <= x < +inf Variable with lower bound
+* GLP_UP -inf < x <= ub Variable with upper bound
+* GLP_DB lb <= x <= ub Double-bounded variable
+* GLP_FX x = lb Fixed variable
+*
+* where x is the structural variable associated with j-th column.
+*
+* If the column has no lower bound, the parameter lb is ignored. If the
+* column has no upper bound, the parameter ub is ignored. If the column
+* is of fixed type, only the parameter lb is used while the parameter
+* ub is ignored. */
+
+void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
+ double ub)
+{ GLPCOL *col;
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_set_col_bnds: j = %d; column number out of range\n"
+ , j);
+ col = lp->col[j];
+ col->type = type;
+ switch (type)
+ { case GLP_FR:
+ col->lb = col->ub = 0.0;
+ if (col->stat != GLP_BS) col->stat = GLP_NF;
+ break;
+ case GLP_LO:
+ col->lb = lb, col->ub = 0.0;
+ if (col->stat != GLP_BS) col->stat = GLP_NL;
+ break;
+ case GLP_UP:
+ col->lb = 0.0, col->ub = ub;
+ if (col->stat != GLP_BS) col->stat = GLP_NU;
+ break;
+ case GLP_DB:
+ col->lb = lb, col->ub = ub;
+ if (!(col->stat == GLP_BS ||
+ col->stat == GLP_NL || col->stat == GLP_NU))
+ col->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
+ break;
+ case GLP_FX:
+ col->lb = col->ub = lb;
+ if (col->stat != GLP_BS) col->stat = GLP_NS;
+ break;
+ default:
+ xerror("glp_set_col_bnds: j = %d; type = %d; invalid column"
+ " type\n", j, type);
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_obj_coef - set (change) obj. coefficient or constant term
+*
+* SYNOPSIS
+*
+* void glp_set_obj_coef(glp_prob *lp, int j, double coef);
+*
+* DESCRIPTION
+*
+* The routine glp_set_obj_coef sets (changes) objective coefficient at
+* j-th column (structural variable) of the specified problem object.
+*
+* If the parameter j is 0, the routine sets (changes) the constant term
+* ("shift") of the objective function. */
+
+void glp_set_obj_coef(glp_prob *lp, int j, double coef)
+{ glp_tree *tree = lp->tree;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_set_obj_coef: operation not allowed\n");
+ if (!(0 <= j && j <= lp->n))
+ xerror("glp_set_obj_coef: j = %d; column number out of range\n"
+ , j);
+ if (j == 0)
+ lp->c0 = coef;
+ else
+ lp->col[j]->coef = coef;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_mat_row - set (replace) row of the constraint matrix
+*
+* SYNOPSIS
+*
+* void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
+* const double val[]);
+*
+* DESCRIPTION
+*
+* The routine glp_set_mat_row stores (replaces) the contents of i-th
+* row of the constraint matrix of the specified problem object.
+*
+* Column indices and numeric values of new row elements must be placed
+* in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
+* 0 <= len <= n is the new length of i-th row, n is the current number
+* of columns in the problem object. Elements with identical column
+* indices are not allowed. Zero elements are allowed, but they are not
+* stored in the constraint matrix.
+*
+* If the parameter len is zero, the parameters ind and/or val can be
+* specified as NULL. */
+
+void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
+ const double val[])
+{ glp_tree *tree = lp->tree;
+ GLPROW *row;
+ GLPCOL *col;
+ GLPAIJ *aij, *next;
+ int j, k;
+ /* obtain pointer to i-th row */
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_set_mat_row: i = %d; row number out of range\n",
+ i);
+ row = lp->row[i];
+ if (tree != NULL && tree->reason != 0)
+ { xassert(tree->curr != NULL);
+ xassert(row->level == tree->curr->level);
+ }
+ /* remove all existing elements from i-th row */
+ while (row->ptr != NULL)
+ { /* take next element in the row */
+ aij = row->ptr;
+ /* remove the element from the row list */
+ row->ptr = aij->r_next;
+ /* obtain pointer to corresponding column */
+ col = aij->col;
+ /* remove the element from the column list */
+ if (aij->c_prev == NULL)
+ col->ptr = aij->c_next;
+ else
+ aij->c_prev->c_next = aij->c_next;
+ if (aij->c_next == NULL)
+ ;
+ else
+ aij->c_next->c_prev = aij->c_prev;
+ /* return the element to the memory pool */
+ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+ /* if the corresponding column is basic, invalidate the basis
+ factorization */
+ if (col->stat == GLP_BS) lp->valid = 0;
+ }
+ /* store new contents of i-th row */
+ if (!(0 <= len && len <= lp->n))
+ xerror("glp_set_mat_row: i = %d; len = %d; invalid row length "
+ "\n", i, len);
+ if (len > NNZ_MAX - lp->nnz)
+ xerror("glp_set_mat_row: i = %d; len = %d; too many constraint"
+ " coefficients\n", i, len);
+ for (k = 1; k <= len; k++)
+ { /* take number j of corresponding column */
+ j = ind[k];
+ /* obtain pointer to j-th column */
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_set_mat_row: i = %d; ind[%d] = %d; column index"
+ " out of range\n", i, k, j);
+ col = lp->col[j];
+ /* if there is element with the same column index, it can only
+ be found in the beginning of j-th column list */
+ if (col->ptr != NULL && col->ptr->row->i == i)
+ xerror("glp_set_mat_row: i = %d; ind[%d] = %d; duplicate co"
+ "lumn indices not allowed\n", i, k, j);
+ /* create new element */
+ aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
+ aij->row = row;
+ aij->col = col;
+ aij->val = val[k];
+ /* add the new element to the beginning of i-th row and j-th
+ column lists */
+ aij->r_prev = NULL;
+ aij->r_next = row->ptr;
+ aij->c_prev = NULL;
+ aij->c_next = col->ptr;
+ if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+ if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+ row->ptr = col->ptr = aij;
+ /* if the corresponding column is basic, invalidate the basis
+ factorization */
+ if (col->stat == GLP_BS && aij->val != 0.0) lp->valid = 0;
+ }
+ /* remove zero elements from i-th row */
+ for (aij = row->ptr; aij != NULL; aij = next)
+ { next = aij->r_next;
+ if (aij->val == 0.0)
+ { /* remove the element from the row list */
+ if (aij->r_prev == NULL)
+ row->ptr = next;
+ else
+ aij->r_prev->r_next = next;
+ if (next == NULL)
+ ;
+ else
+ next->r_prev = aij->r_prev;
+ /* remove the element from the column list */
+ xassert(aij->c_prev == NULL);
+ aij->col->ptr = aij->c_next;
+ if (aij->c_next != NULL) aij->c_next->c_prev = NULL;
+ /* return the element to the memory pool */
+ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_mat_col - set (replace) column of the constraint matrix
+*
+* SYNOPSIS
+*
+* void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
+* const double val[]);
+*
+* DESCRIPTION
+*
+* The routine glp_set_mat_col stores (replaces) the contents of j-th
+* column of the constraint matrix of the specified problem object.
+*
+* Row indices and numeric values of new column elements must be placed
+* in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
+* 0 <= len <= m is the new length of j-th column, m is the current
+* number of rows in the problem object. Elements with identical column
+* indices are not allowed. Zero elements are allowed, but they are not
+* stored in the constraint matrix.
+*
+* If the parameter len is zero, the parameters ind and/or val can be
+* specified as NULL. */
+
+void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
+ const double val[])
+{ glp_tree *tree = lp->tree;
+ GLPROW *row;
+ GLPCOL *col;
+ GLPAIJ *aij, *next;
+ int i, k;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_set_mat_col: operation not allowed\n");
+ /* obtain pointer to j-th column */
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_set_mat_col: j = %d; column number out of range\n",
+ j);
+ col = lp->col[j];
+ /* remove all existing elements from j-th column */
+ while (col->ptr != NULL)
+ { /* take next element in the column */
+ aij = col->ptr;
+ /* remove the element from the column list */
+ col->ptr = aij->c_next;
+ /* obtain pointer to corresponding row */
+ row = aij->row;
+ /* remove the element from the row list */
+ if (aij->r_prev == NULL)
+ row->ptr = aij->r_next;
+ else
+ aij->r_prev->r_next = aij->r_next;
+ if (aij->r_next == NULL)
+ ;
+ else
+ aij->r_next->r_prev = aij->r_prev;
+ /* return the element to the memory pool */
+ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+ }
+ /* store new contents of j-th column */
+ if (!(0 <= len && len <= lp->m))
+ xerror("glp_set_mat_col: j = %d; len = %d; invalid column leng"
+ "th\n", j, len);
+ if (len > NNZ_MAX - lp->nnz)
+ xerror("glp_set_mat_col: j = %d; len = %d; too many constraint"
+ " coefficients\n", j, len);
+ for (k = 1; k <= len; k++)
+ { /* take number i of corresponding row */
+ i = ind[k];
+ /* obtain pointer to i-th row */
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_set_mat_col: j = %d; ind[%d] = %d; row index ou"
+ "t of range\n", j, k, i);
+ row = lp->row[i];
+ /* if there is element with the same row index, it can only be
+ found in the beginning of i-th row list */
+ if (row->ptr != NULL && row->ptr->col->j == j)
+ xerror("glp_set_mat_col: j = %d; ind[%d] = %d; duplicate ro"
+ "w indices not allowed\n", j, k, i);
+ /* create new element */
+ aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
+ aij->row = row;
+ aij->col = col;
+ aij->val = val[k];
+ /* add the new element to the beginning of i-th row and j-th
+ column lists */
+ aij->r_prev = NULL;
+ aij->r_next = row->ptr;
+ aij->c_prev = NULL;
+ aij->c_next = col->ptr;
+ if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+ if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+ row->ptr = col->ptr = aij;
+ }
+ /* remove zero elements from j-th column */
+ for (aij = col->ptr; aij != NULL; aij = next)
+ { next = aij->c_next;
+ if (aij->val == 0.0)
+ { /* remove the element from the row list */
+ xassert(aij->r_prev == NULL);
+ aij->row->ptr = aij->r_next;
+ if (aij->r_next != NULL) aij->r_next->r_prev = NULL;
+ /* remove the element from the column list */
+ if (aij->c_prev == NULL)
+ col->ptr = next;
+ else
+ aij->c_prev->c_next = next;
+ if (next == NULL)
+ ;
+ else
+ next->c_prev = aij->c_prev;
+ /* return the element to the memory pool */
+ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+ }
+ }
+ /* if j-th column is basic, invalidate the basis factorization */
+ if (col->stat == GLP_BS) lp->valid = 0;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_load_matrix - load (replace) the whole constraint matrix
+*
+* SYNOPSIS
+*
+* void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
+* const int ja[], const double ar[]);
+*
+* DESCRIPTION
+*
+* The routine glp_load_matrix loads the constraint matrix passed in
+* the arrays ia, ja, and ar into the specified problem object. Before
+* loading the current contents of the constraint matrix is destroyed.
+*
+* Constraint coefficients (elements of the constraint matrix) must be
+* specified as triplets (ia[k], ja[k], ar[k]) for k = 1, ..., ne,
+* where ia[k] is the row index, ja[k] is the column index, ar[k] is a
+* numeric value of corresponding constraint coefficient. The parameter
+* ne specifies the total number of (non-zero) elements in the matrix
+* to be loaded. Coefficients with identical indices are not allowed.
+* Zero coefficients are allowed, however, they are not stored in the
+* constraint matrix.
+*
+* If the parameter ne is zero, the parameters ia, ja, and ar can be
+* specified as NULL. */
+
+void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
+ const int ja[], const double ar[])
+{ glp_tree *tree = lp->tree;
+ GLPROW *row;
+ GLPCOL *col;
+ GLPAIJ *aij, *next;
+ int i, j, k;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_load_matrix: operation not allowed\n");
+ /* clear the constraint matrix */
+ for (i = 1; i <= lp->m; i++)
+ { row = lp->row[i];
+ while (row->ptr != NULL)
+ { aij = row->ptr;
+ row->ptr = aij->r_next;
+ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+ }
+ }
+ xassert(lp->nnz == 0);
+ for (j = 1; j <= lp->n; j++) lp->col[j]->ptr = NULL;
+ /* load the new contents of the constraint matrix and build its
+ row lists */
+ if (ne < 0)
+ xerror("glp_load_matrix: ne = %d; invalid number of constraint"
+ " coefficients\n", ne);
+ if (ne > NNZ_MAX)
+ xerror("glp_load_matrix: ne = %d; too many constraint coeffici"
+ "ents\n", ne);
+ for (k = 1; k <= ne; k++)
+ { /* take indices of new element */
+ i = ia[k], j = ja[k];
+ /* obtain pointer to i-th row */
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_load_matrix: ia[%d] = %d; row index out of rang"
+ "e\n", k, i);
+ row = lp->row[i];
+ /* obtain pointer to j-th column */
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_load_matrix: ja[%d] = %d; column index out of r"
+ "ange\n", k, j);
+ col = lp->col[j];
+ /* create new element */
+ aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
+ aij->row = row;
+ aij->col = col;
+ aij->val = ar[k];
+ /* add the new element to the beginning of i-th row list */
+ aij->r_prev = NULL;
+ aij->r_next = row->ptr;
+ if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+ row->ptr = aij;
+ }
+ xassert(lp->nnz == ne);
+ /* build column lists of the constraint matrix and check elements
+ with identical indices */
+ for (i = 1; i <= lp->m; i++)
+ { for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ { /* obtain pointer to corresponding column */
+ col = aij->col;
+ /* if there is element with identical indices, it can only
+ be found in the beginning of j-th column list */
+ if (col->ptr != NULL && col->ptr->row->i == i)
+ { for (k = 1; k <= ne; k++)
+ if (ia[k] == i && ja[k] == col->j) break;
+ xerror("glp_load_mat: ia[%d] = %d; ja[%d] = %d; duplicat"
+ "e indices not allowed\n", k, i, k, col->j);
+ }
+ /* add the element to the beginning of j-th column list */
+ aij->c_prev = NULL;
+ aij->c_next = col->ptr;
+ if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+ col->ptr = aij;
+ }
+ }
+ /* remove zero elements from the constraint matrix */
+ for (i = 1; i <= lp->m; i++)
+ { row = lp->row[i];
+ for (aij = row->ptr; aij != NULL; aij = next)
+ { next = aij->r_next;
+ if (aij->val == 0.0)
+ { /* remove the element from the row list */
+ if (aij->r_prev == NULL)
+ row->ptr = next;
+ else
+ aij->r_prev->r_next = next;
+ if (next == NULL)
+ ;
+ else
+ next->r_prev = aij->r_prev;
+ /* remove the element from the column list */
+ if (aij->c_prev == NULL)
+ aij->col->ptr = aij->c_next;
+ else
+ aij->c_prev->c_next = aij->c_next;
+ if (aij->c_next == NULL)
+ ;
+ else
+ aij->c_next->c_prev = aij->c_prev;
+ /* return the element to the memory pool */
+ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+ }
+ }
+ }
+ /* invalidate the basis factorization */
+ lp->valid = 0;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_check_dup - check for duplicate elements in sparse matrix
+*
+* SYNOPSIS
+*
+* int glp_check_dup(int m, int n, int ne, const int ia[],
+* const int ja[]);
+*
+* DESCRIPTION
+*
+* The routine glp_check_dup checks for duplicate elements (that is,
+* elements with identical indices) in a sparse matrix specified in the
+* coordinate format.
+*
+* The parameters m and n specifies, respectively, the number of rows
+* and columns in the matrix, m >= 0, n >= 0.
+*
+* The parameter ne specifies the number of (structurally) non-zero
+* elements in the matrix, ne >= 0.
+*
+* Elements of the matrix are specified as doublets (ia[k],ja[k]) for
+* k = 1,...,ne, where ia[k] is a row index, ja[k] is a column index.
+*
+* The routine glp_check_dup can be used prior to a call to the routine
+* glp_load_matrix to check that the constraint matrix to be loaded has
+* no duplicate elements.
+*
+* RETURNS
+*
+* The routine glp_check_dup returns one of the following values:
+*
+* 0 - the matrix has no duplicate elements;
+*
+* -k - indices ia[k] or/and ja[k] are out of range;
+*
+* +k - element (ia[k],ja[k]) is duplicate. */
+
+int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[])
+{ int i, j, k, *ptr, *next, ret;
+ char *flag;
+ if (m < 0)
+ xerror("glp_check_dup: m = %d; invalid parameter\n");
+ if (n < 0)
+ xerror("glp_check_dup: n = %d; invalid parameter\n");
+ if (ne < 0)
+ xerror("glp_check_dup: ne = %d; invalid parameter\n");
+ if (ne > 0 && ia == NULL)
+ xerror("glp_check_dup: ia = %p; invalid parameter\n", ia);
+ if (ne > 0 && ja == NULL)
+ xerror("glp_check_dup: ja = %p; invalid parameter\n", ja);
+ for (k = 1; k <= ne; k++)
+ { i = ia[k], j = ja[k];
+ if (!(1 <= i && i <= m && 1 <= j && j <= n))
+ { ret = -k;
+ goto done;
+ }
+ }
+ if (m == 0 || n == 0)
+ { ret = 0;
+ goto done;
+ }
+ /* allocate working arrays */
+ ptr = xcalloc(1+m, sizeof(int));
+ next = xcalloc(1+ne, sizeof(int));
+ flag = xcalloc(1+n, sizeof(char));
+ /* build row lists */
+ for (i = 1; i <= m; i++)
+ ptr[i] = 0;
+ for (k = 1; k <= ne; k++)
+ { i = ia[k];
+ next[k] = ptr[i];
+ ptr[i] = k;
+ }
+ /* clear column flags */
+ for (j = 1; j <= n; j++)
+ flag[j] = 0;
+ /* check for duplicate elements */
+ for (i = 1; i <= m; i++)
+ { for (k = ptr[i]; k != 0; k = next[k])
+ { j = ja[k];
+ if (flag[j])
+ { /* find first element (i,j) */
+ for (k = 1; k <= ne; k++)
+ if (ia[k] == i && ja[k] == j) break;
+ xassert(k <= ne);
+ /* find next (duplicate) element (i,j) */
+ for (k++; k <= ne; k++)
+ if (ia[k] == i && ja[k] == j) break;
+ xassert(k <= ne);
+ ret = +k;
+ goto skip;
+ }
+ flag[j] = 1;
+ }
+ /* clear column flags */
+ for (k = ptr[i]; k != 0; k = next[k])
+ flag[ja[k]] = 0;
+ }
+ /* no duplicate element found */
+ ret = 0;
+skip: /* free working arrays */
+ xfree(ptr);
+ xfree(next);
+ xfree(flag);
+done: return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_sort_matrix - sort elements of the constraint matrix
+*
+* SYNOPSIS
+*
+* void glp_sort_matrix(glp_prob *P);
+*
+* DESCRIPTION
+*
+* The routine glp_sort_matrix sorts elements of the constraint matrix
+* rebuilding its row and column linked lists. On exit from the routine
+* the constraint matrix is not changed, however, elements in the row
+* linked lists become ordered by ascending column indices, and the
+* elements in the column linked lists become ordered by ascending row
+* indices. */
+
+void glp_sort_matrix(glp_prob *P)
+{ GLPAIJ *aij;
+ int i, j;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_sort_matrix: P = %p; invalid problem object\n",
+ P);
+#endif
+ /* rebuild row linked lists */
+ for (i = P->m; i >= 1; i--)
+ P->row[i]->ptr = NULL;
+ for (j = P->n; j >= 1; j--)
+ { for (aij = P->col[j]->ptr; aij != NULL; aij = aij->c_next)
+ { i = aij->row->i;
+ aij->r_prev = NULL;
+ aij->r_next = P->row[i]->ptr;
+ if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+ P->row[i]->ptr = aij;
+ }
+ }
+ /* rebuild column linked lists */
+ for (j = P->n; j >= 1; j--)
+ P->col[j]->ptr = NULL;
+ for (i = P->m; i >= 1; i--)
+ { for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ { j = aij->col->j;
+ aij->c_prev = NULL;
+ aij->c_next = P->col[j]->ptr;
+ if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+ P->col[j]->ptr = aij;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_del_rows - delete rows from problem object
+*
+* SYNOPSIS
+*
+* void glp_del_rows(glp_prob *lp, int nrs, const int num[]);
+*
+* DESCRIPTION
+*
+* The routine glp_del_rows deletes rows from the specified problem
+* object. Ordinal numbers of rows to be deleted should be placed in
+* locations num[1], ..., num[nrs], where nrs > 0.
+*
+* Note that deleting rows involves changing ordinal numbers of other
+* rows remaining in the problem object. New ordinal numbers of the
+* remaining rows are assigned under the assumption that the original
+* order of rows is not changed. */
+
+void glp_del_rows(glp_prob *lp, int nrs, const int num[])
+{ glp_tree *tree = lp->tree;
+ GLPROW *row;
+ int i, k, m_new;
+ /* mark rows to be deleted */
+ if (!(1 <= nrs && nrs <= lp->m))
+ xerror("glp_del_rows: nrs = %d; invalid number of rows\n",
+ nrs);
+ for (k = 1; k <= nrs; k++)
+ { /* take the number of row to be deleted */
+ i = num[k];
+ /* obtain pointer to i-th row */
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_del_rows: num[%d] = %d; row number out of range"
+ "\n", k, i);
+ row = lp->row[i];
+ if (tree != NULL && tree->reason != 0)
+ { if (!(tree->reason == GLP_IROWGEN ||
+ tree->reason == GLP_ICUTGEN))
+ xerror("glp_del_rows: operation not allowed\n");
+ xassert(tree->curr != NULL);
+ if (row->level != tree->curr->level)
+ xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
+ "elete row created not in current subproblem\n", k,i);
+ if (row->stat != GLP_BS)
+ xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
+ "elete active row (constraint)\n", k, i);
+ tree->reinv = 1;
+ }
+ /* check that the row is not marked yet */
+ if (row->i == 0)
+ xerror("glp_del_rows: num[%d] = %d; duplicate row numbers n"
+ "ot allowed\n", k, i);
+ /* erase symbolic name assigned to the row */
+ glp_set_row_name(lp, i, NULL);
+ xassert(row->node == NULL);
+ /* erase corresponding row of the constraint matrix */
+ glp_set_mat_row(lp, i, 0, NULL, NULL);
+ xassert(row->ptr == NULL);
+ /* mark the row to be deleted */
+ row->i = 0;
+ }
+ /* delete all marked rows from the row list */
+ m_new = 0;
+ for (i = 1; i <= lp->m; i++)
+ { /* obtain pointer to i-th row */
+ row = lp->row[i];
+ /* check if the row is marked */
+ if (row->i == 0)
+ { /* it is marked, delete it */
+ dmp_free_atom(lp->pool, row, sizeof(GLPROW));
+ }
+ else
+ { /* it is not marked; keep it */
+ row->i = ++m_new;
+ lp->row[row->i] = row;
+ }
+ }
+ /* set new number of rows */
+ lp->m = m_new;
+ /* invalidate the basis factorization */
+ lp->valid = 0;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_del_cols - delete columns from problem object
+*
+* SYNOPSIS
+*
+* void glp_del_cols(glp_prob *lp, int ncs, const int num[]);
+*
+* DESCRIPTION
+*
+* The routine glp_del_cols deletes columns from the specified problem
+* object. Ordinal numbers of columns to be deleted should be placed in
+* locations num[1], ..., num[ncs], where ncs > 0.
+*
+* Note that deleting columns involves changing ordinal numbers of
+* other columns remaining in the problem object. New ordinal numbers
+* of the remaining columns are assigned under the assumption that the
+* original order of columns is not changed. */
+
+void glp_del_cols(glp_prob *lp, int ncs, const int num[])
+{ glp_tree *tree = lp->tree;
+ GLPCOL *col;
+ int j, k, n_new;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_del_cols: operation not allowed\n");
+ /* mark columns to be deleted */
+ if (!(1 <= ncs && ncs <= lp->n))
+ xerror("glp_del_cols: ncs = %d; invalid number of columns\n",
+ ncs);
+ for (k = 1; k <= ncs; k++)
+ { /* take the number of column to be deleted */
+ j = num[k];
+ /* obtain pointer to j-th column */
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_del_cols: num[%d] = %d; column number out of ra"
+ "nge", k, j);
+ col = lp->col[j];
+ /* check that the column is not marked yet */
+ if (col->j == 0)
+ xerror("glp_del_cols: num[%d] = %d; duplicate column number"
+ "s not allowed\n", k, j);
+ /* erase symbolic name assigned to the column */
+ glp_set_col_name(lp, j, NULL);
+ xassert(col->node == NULL);
+ /* erase corresponding column of the constraint matrix */
+ glp_set_mat_col(lp, j, 0, NULL, NULL);
+ xassert(col->ptr == NULL);
+ /* mark the column to be deleted */
+ col->j = 0;
+ /* if it is basic, invalidate the basis factorization */
+ if (col->stat == GLP_BS) lp->valid = 0;
+ }
+ /* delete all marked columns from the column list */
+ n_new = 0;
+ for (j = 1; j <= lp->n; j++)
+ { /* obtain pointer to j-th column */
+ col = lp->col[j];
+ /* check if the column is marked */
+ if (col->j == 0)
+ { /* it is marked; delete it */
+ dmp_free_atom(lp->pool, col, sizeof(GLPCOL));
+ }
+ else
+ { /* it is not marked; keep it */
+ col->j = ++n_new;
+ lp->col[col->j] = col;
+ }
+ }
+ /* set new number of columns */
+ lp->n = n_new;
+ /* if the basis header is still valid, adjust it */
+ if (lp->valid)
+ { int m = lp->m;
+ int *head = lp->head;
+ for (j = 1; j <= n_new; j++)
+ { k = lp->col[j]->bind;
+ if (k != 0)
+ { xassert(1 <= k && k <= m);
+ head[k] = m + j;
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_copy_prob - copy problem object content
+*
+* SYNOPSIS
+*
+* void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
+*
+* DESCRIPTION
+*
+* The routine glp_copy_prob copies the content of the problem object
+* prob to the problem object dest.
+*
+* The parameter names is a flag. If it is non-zero, the routine also
+* copies all symbolic names; otherwise, if it is zero, symbolic names
+* are not copied. */
+
+void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names)
+{ glp_tree *tree = dest->tree;
+ glp_bfcp bfcp;
+ int i, j, len, *ind;
+ double *val;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_copy_prob: operation not allowed\n");
+ if (dest == prob)
+ xerror("glp_copy_prob: copying problem object to itself not al"
+ "lowed\n");
+ if (!(names == GLP_ON || names == GLP_OFF))
+ xerror("glp_copy_prob: names = %d; invalid parameter\n",
+ names);
+ glp_erase_prob(dest);
+ if (names && prob->name != NULL)
+ glp_set_prob_name(dest, prob->name);
+ if (names && prob->obj != NULL)
+ glp_set_obj_name(dest, prob->obj);
+ dest->dir = prob->dir;
+ dest->c0 = prob->c0;
+ if (prob->m > 0)
+ glp_add_rows(dest, prob->m);
+ if (prob->n > 0)
+ glp_add_cols(dest, prob->n);
+ glp_get_bfcp(prob, &bfcp);
+ glp_set_bfcp(dest, &bfcp);
+ dest->pbs_stat = prob->pbs_stat;
+ dest->dbs_stat = prob->dbs_stat;
+ dest->obj_val = prob->obj_val;
+ dest->some = prob->some;
+ dest->ipt_stat = prob->ipt_stat;
+ dest->ipt_obj = prob->ipt_obj;
+ dest->mip_stat = prob->mip_stat;
+ dest->mip_obj = prob->mip_obj;
+ for (i = 1; i <= prob->m; i++)
+ { GLPROW *to = dest->row[i];
+ GLPROW *from = prob->row[i];
+ if (names && from->name != NULL)
+ glp_set_row_name(dest, i, from->name);
+ to->type = from->type;
+ to->lb = from->lb;
+ to->ub = from->ub;
+ to->rii = from->rii;
+ to->stat = from->stat;
+ to->prim = from->prim;
+ to->dual = from->dual;
+ to->pval = from->pval;
+ to->dval = from->dval;
+ to->mipx = from->mipx;
+ }
+ ind = xcalloc(1+prob->m, sizeof(int));
+ val = xcalloc(1+prob->m, sizeof(double));
+ for (j = 1; j <= prob->n; j++)
+ { GLPCOL *to = dest->col[j];
+ GLPCOL *from = prob->col[j];
+ if (names && from->name != NULL)
+ glp_set_col_name(dest, j, from->name);
+ to->kind = from->kind;
+ to->type = from->type;
+ to->lb = from->lb;
+ to->ub = from->ub;
+ to->coef = from->coef;
+ len = glp_get_mat_col(prob, j, ind, val);
+ glp_set_mat_col(dest, j, len, ind, val);
+ to->sjj = from->sjj;
+ to->stat = from->stat;
+ to->prim = from->prim;
+ to->dual = from->dual;
+ to->pval = from->pval;
+ to->dval = from->dval;
+ to->mipx = from->mipx;
+ }
+ xfree(ind);
+ xfree(val);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_erase_prob - erase problem object content
+*
+* SYNOPSIS
+*
+* void glp_erase_prob(glp_prob *lp);
+*
+* DESCRIPTION
+*
+* The routine glp_erase_prob erases the content of the specified
+* problem object. The effect of this operation is the same as if the
+* problem object would be deleted with the routine glp_delete_prob and
+* then created anew with the routine glp_create_prob, with exception
+* that the handle (pointer) to the problem object remains valid. */
+
+static void delete_prob(glp_prob *lp);
+
+void glp_erase_prob(glp_prob *lp)
+{ glp_tree *tree = lp->tree;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_erase_prob: operation not allowed\n");
+ delete_prob(lp);
+ create_prob(lp);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_delete_prob - delete problem object
+*
+* SYNOPSIS
+*
+* void glp_delete_prob(glp_prob *lp);
+*
+* DESCRIPTION
+*
+* The routine glp_delete_prob deletes the specified problem object and
+* frees all the memory allocated to it. */
+
+static void delete_prob(glp_prob *lp)
+#if 0 /* 04/IV-2016 */
+{ lp->magic = 0x3F3F3F3F;
+#else
+{
+#endif
+ dmp_delete_pool(lp->pool);
+#if 0 /* 08/III-2014 */
+#if 0 /* 17/XI-2009 */
+ xfree(lp->cps);
+#else
+ if (lp->parms != NULL) xfree(lp->parms);
+#endif
+#endif
+ xassert(lp->tree == NULL);
+#if 0
+ if (lp->cwa != NULL) xfree(lp->cwa);
+#endif
+ xfree(lp->row);
+ xfree(lp->col);
+ if (lp->r_tree != NULL) avl_delete_tree(lp->r_tree);
+ if (lp->c_tree != NULL) avl_delete_tree(lp->c_tree);
+ xfree(lp->head);
+#if 0 /* 08/III-2014 */
+ if (lp->bfcp != NULL) xfree(lp->bfcp);
+#endif
+ if (lp->bfd != NULL) bfd_delete_it(lp->bfd);
+ return;
+}
+
+void glp_delete_prob(glp_prob *lp)
+{ glp_tree *tree = lp->tree;
+ if (tree != NULL && tree->reason != 0)
+ xerror("glp_delete_prob: operation not allowed\n");
+ delete_prob(lp);
+ xfree(lp);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/prob2.c b/test/monniaux/glpk-4.65/src/api/prob2.c
new file mode 100644
index 00000000..d352db12
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/prob2.c
@@ -0,0 +1,491 @@
+/* prob2.c (problem retrieving routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_get_prob_name - retrieve problem name
+*
+* SYNOPSIS
+*
+* const char *glp_get_prob_name(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_prob_name returns a pointer to an internal
+* buffer, which contains symbolic name of the problem. However, if the
+* problem has no assigned name, the routine returns NULL. */
+
+const char *glp_get_prob_name(glp_prob *lp)
+{ char *name;
+ name = lp->name;
+ return name;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_obj_name - retrieve objective function name
+*
+* SYNOPSIS
+*
+* const char *glp_get_obj_name(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_obj_name returns a pointer to an internal
+* buffer, which contains a symbolic name of the objective function.
+* However, if the objective function has no assigned name, the routine
+* returns NULL. */
+
+const char *glp_get_obj_name(glp_prob *lp)
+{ char *name;
+ name = lp->obj;
+ return name;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_obj_dir - retrieve optimization direction flag
+*
+* SYNOPSIS
+*
+* int glp_get_obj_dir(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_obj_dir returns the optimization direction flag
+* (i.e. "sense" of the objective function):
+*
+* GLP_MIN - minimization;
+* GLP_MAX - maximization. */
+
+int glp_get_obj_dir(glp_prob *lp)
+{ int dir = lp->dir;
+ return dir;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_num_rows - retrieve number of rows
+*
+* SYNOPSIS
+*
+* int glp_get_num_rows(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_num_rows returns the current number of rows in
+* the specified problem object. */
+
+int glp_get_num_rows(glp_prob *lp)
+{ int m = lp->m;
+ return m;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_num_cols - retrieve number of columns
+*
+* SYNOPSIS
+*
+* int glp_get_num_cols(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_num_cols returns the current number of columns
+* in the specified problem object. */
+
+int glp_get_num_cols(glp_prob *lp)
+{ int n = lp->n;
+ return n;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_row_name - retrieve row name
+*
+* SYNOPSIS
+*
+* const char *glp_get_row_name(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_get_row_name returns a pointer to an internal
+* buffer, which contains symbolic name of i-th row. However, if i-th
+* row has no assigned name, the routine returns NULL. */
+
+const char *glp_get_row_name(glp_prob *lp, int i)
+{ char *name;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_get_row_name: i = %d; row number out of range\n",
+ i);
+ name = lp->row[i]->name;
+ return name;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_col_name - retrieve column name
+*
+* SYNOPSIS
+*
+* const char *glp_get_col_name(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_get_col_name returns a pointer to an internal
+* buffer, which contains symbolic name of j-th column. However, if j-th
+* column has no assigned name, the routine returns NULL. */
+
+const char *glp_get_col_name(glp_prob *lp, int j)
+{ char *name;
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_get_col_name: j = %d; column number out of range\n"
+ , j);
+ name = lp->col[j]->name;
+ return name;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_row_type - retrieve row type
+*
+* SYNOPSIS
+*
+* int glp_get_row_type(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_get_row_type returns the type of i-th row, i.e. the
+* type of corresponding auxiliary variable, as follows:
+*
+* GLP_FR - free (unbounded) variable;
+* GLP_LO - variable with lower bound;
+* GLP_UP - variable with upper bound;
+* GLP_DB - double-bounded variable;
+* GLP_FX - fixed variable. */
+
+int glp_get_row_type(glp_prob *lp, int i)
+{ if (!(1 <= i && i <= lp->m))
+ xerror("glp_get_row_type: i = %d; row number out of range\n",
+ i);
+ return lp->row[i]->type;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_row_lb - retrieve row lower bound
+*
+* SYNOPSIS
+*
+* double glp_get_row_lb(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_get_row_lb returns the lower bound of i-th row, i.e.
+* the lower bound of corresponding auxiliary variable. However, if the
+* row has no lower bound, the routine returns -DBL_MAX. */
+
+double glp_get_row_lb(glp_prob *lp, int i)
+{ double lb;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_get_row_lb: i = %d; row number out of range\n", i);
+ switch (lp->row[i]->type)
+ { case GLP_FR:
+ case GLP_UP:
+ lb = -DBL_MAX; break;
+ case GLP_LO:
+ case GLP_DB:
+ case GLP_FX:
+ lb = lp->row[i]->lb; break;
+ default:
+ xassert(lp != lp);
+ }
+ return lb;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_row_ub - retrieve row upper bound
+*
+* SYNOPSIS
+*
+* double glp_get_row_ub(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_get_row_ub returns the upper bound of i-th row, i.e.
+* the upper bound of corresponding auxiliary variable. However, if the
+* row has no upper bound, the routine returns +DBL_MAX. */
+
+double glp_get_row_ub(glp_prob *lp, int i)
+{ double ub;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_get_row_ub: i = %d; row number out of range\n", i);
+ switch (lp->row[i]->type)
+ { case GLP_FR:
+ case GLP_LO:
+ ub = +DBL_MAX; break;
+ case GLP_UP:
+ case GLP_DB:
+ case GLP_FX:
+ ub = lp->row[i]->ub; break;
+ default:
+ xassert(lp != lp);
+ }
+ return ub;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_col_type - retrieve column type
+*
+* SYNOPSIS
+*
+* int glp_get_col_type(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_get_col_type returns the type of j-th column, i.e.
+* the type of corresponding structural variable, as follows:
+*
+* GLP_FR - free (unbounded) variable;
+* GLP_LO - variable with lower bound;
+* GLP_UP - variable with upper bound;
+* GLP_DB - double-bounded variable;
+* GLP_FX - fixed variable. */
+
+int glp_get_col_type(glp_prob *lp, int j)
+{ if (!(1 <= j && j <= lp->n))
+ xerror("glp_get_col_type: j = %d; column number out of range\n"
+ , j);
+ return lp->col[j]->type;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_col_lb - retrieve column lower bound
+*
+* SYNOPSIS
+*
+* double glp_get_col_lb(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_get_col_lb returns the lower bound of j-th column,
+* i.e. the lower bound of corresponding structural variable. However,
+* if the column has no lower bound, the routine returns -DBL_MAX. */
+
+double glp_get_col_lb(glp_prob *lp, int j)
+{ double lb;
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_get_col_lb: j = %d; column number out of range\n",
+ j);
+ switch (lp->col[j]->type)
+ { case GLP_FR:
+ case GLP_UP:
+ lb = -DBL_MAX; break;
+ case GLP_LO:
+ case GLP_DB:
+ case GLP_FX:
+ lb = lp->col[j]->lb; break;
+ default:
+ xassert(lp != lp);
+ }
+ return lb;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_col_ub - retrieve column upper bound
+*
+* SYNOPSIS
+*
+* double glp_get_col_ub(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_get_col_ub returns the upper bound of j-th column,
+* i.e. the upper bound of corresponding structural variable. However,
+* if the column has no upper bound, the routine returns +DBL_MAX. */
+
+double glp_get_col_ub(glp_prob *lp, int j)
+{ double ub;
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_get_col_ub: j = %d; column number out of range\n",
+ j);
+ switch (lp->col[j]->type)
+ { case GLP_FR:
+ case GLP_LO:
+ ub = +DBL_MAX; break;
+ case GLP_UP:
+ case GLP_DB:
+ case GLP_FX:
+ ub = lp->col[j]->ub; break;
+ default:
+ xassert(lp != lp);
+ }
+ return ub;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_obj_coef - retrieve obj. coefficient or constant term
+*
+* SYNOPSIS
+*
+* double glp_get_obj_coef(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_get_obj_coef returns the objective coefficient at
+* j-th structural variable (column) of the specified problem object.
+*
+* If the parameter j is zero, the routine returns the constant term
+* ("shift") of the objective function. */
+
+double glp_get_obj_coef(glp_prob *lp, int j)
+{ if (!(0 <= j && j <= lp->n))
+ xerror("glp_get_obj_coef: j = %d; column number out of range\n"
+ , j);
+ return j == 0 ? lp->c0 : lp->col[j]->coef;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_num_nz - retrieve number of constraint coefficients
+*
+* SYNOPSIS
+*
+* int glp_get_num_nz(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_num_nz returns the number of (non-zero) elements
+* in the constraint matrix of the specified problem object. */
+
+int glp_get_num_nz(glp_prob *lp)
+{ int nnz = lp->nnz;
+ return nnz;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_mat_row - retrieve row of the constraint matrix
+*
+* SYNOPSIS
+*
+* int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]);
+*
+* DESCRIPTION
+*
+* The routine glp_get_mat_row scans (non-zero) elements of i-th row
+* of the constraint matrix of the specified problem object and stores
+* their column indices and numeric values to locations ind[1], ...,
+* ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
+* is the number of elements in i-th row, n is the number of columns.
+*
+* The parameter ind and/or val can be specified as NULL, in which case
+* corresponding information is not stored.
+*
+* RETURNS
+*
+* The routine glp_get_mat_row returns the length len, i.e. the number
+* of (non-zero) elements in i-th row. */
+
+int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[])
+{ GLPAIJ *aij;
+ int len;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_get_mat_row: i = %d; row number out of range\n",
+ i);
+ len = 0;
+ for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ { len++;
+ if (ind != NULL) ind[len] = aij->col->j;
+ if (val != NULL) val[len] = aij->val;
+ }
+ xassert(len <= lp->n);
+ return len;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_mat_col - retrieve column of the constraint matrix
+*
+* SYNOPSIS
+*
+* int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]);
+*
+* DESCRIPTION
+*
+* The routine glp_get_mat_col scans (non-zero) elements of j-th column
+* of the constraint matrix of the specified problem object and stores
+* their row indices and numeric values to locations ind[1], ...,
+* ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= m
+* is the number of elements in j-th column, m is the number of rows.
+*
+* The parameter ind or/and val can be specified as NULL, in which case
+* corresponding information is not stored.
+*
+* RETURNS
+*
+* The routine glp_get_mat_col returns the length len, i.e. the number
+* of (non-zero) elements in j-th column. */
+
+int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[])
+{ GLPAIJ *aij;
+ int len;
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_get_mat_col: j = %d; column number out of range\n",
+ j);
+ len = 0;
+ for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+ { len++;
+ if (ind != NULL) ind[len] = aij->row->i;
+ if (val != NULL) val[len] = aij->val;
+ }
+ xassert(len <= lp->m);
+ return len;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/prob3.c b/test/monniaux/glpk-4.65/src/api/prob3.c
new file mode 100644
index 00000000..d7edbd33
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/prob3.c
@@ -0,0 +1,166 @@
+/* prob3.c (problem row/column searching routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_create_index - create the name index
+*
+* SYNOPSIS
+*
+* void glp_create_index(glp_prob *lp);
+*
+* DESCRIPTION
+*
+* The routine glp_create_index creates the name index for the
+* specified problem object. The name index is an auxiliary data
+* structure, which is intended to quickly (i.e. for logarithmic time)
+* find rows and columns by their names.
+*
+* This routine can be called at any time. If the name index already
+* exists, the routine does nothing. */
+
+void glp_create_index(glp_prob *lp)
+{ GLPROW *row;
+ GLPCOL *col;
+ int i, j;
+ /* create row name index */
+ if (lp->r_tree == NULL)
+ { lp->r_tree = avl_create_tree(avl_strcmp, NULL);
+ for (i = 1; i <= lp->m; i++)
+ { row = lp->row[i];
+ xassert(row->node == NULL);
+ if (row->name != NULL)
+ { row->node = avl_insert_node(lp->r_tree, row->name);
+ avl_set_node_link(row->node, row);
+ }
+ }
+ }
+ /* create column name index */
+ if (lp->c_tree == NULL)
+ { lp->c_tree = avl_create_tree(avl_strcmp, NULL);
+ for (j = 1; j <= lp->n; j++)
+ { col = lp->col[j];
+ xassert(col->node == NULL);
+ if (col->name != NULL)
+ { col->node = avl_insert_node(lp->c_tree, col->name);
+ avl_set_node_link(col->node, col);
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_find_row - find row by its name
+*
+* SYNOPSIS
+*
+* int glp_find_row(glp_prob *lp, const char *name);
+*
+* RETURNS
+*
+* The routine glp_find_row returns the ordinal number of a row,
+* which is assigned (by the routine glp_set_row_name) the specified
+* symbolic name. If no such row exists, the routine returns 0. */
+
+int glp_find_row(glp_prob *lp, const char *name)
+{ AVLNODE *node;
+ int i = 0;
+ if (lp->r_tree == NULL)
+ xerror("glp_find_row: row name index does not exist\n");
+ if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
+ { node = avl_find_node(lp->r_tree, name);
+ if (node != NULL)
+ i = ((GLPROW *)avl_get_node_link(node))->i;
+ }
+ return i;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_find_col - find column by its name
+*
+* SYNOPSIS
+*
+* int glp_find_col(glp_prob *lp, const char *name);
+*
+* RETURNS
+*
+* The routine glp_find_col returns the ordinal number of a column,
+* which is assigned (by the routine glp_set_col_name) the specified
+* symbolic name. If no such column exists, the routine returns 0. */
+
+int glp_find_col(glp_prob *lp, const char *name)
+{ AVLNODE *node;
+ int j = 0;
+ if (lp->c_tree == NULL)
+ xerror("glp_find_col: column name index does not exist\n");
+ if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
+ { node = avl_find_node(lp->c_tree, name);
+ if (node != NULL)
+ j = ((GLPCOL *)avl_get_node_link(node))->j;
+ }
+ return j;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_delete_index - delete the name index
+*
+* SYNOPSIS
+*
+* void glp_delete_index(glp_prob *lp);
+*
+* DESCRIPTION
+*
+* The routine glp_delete_index deletes the name index previously
+* created by the routine glp_create_index and frees the memory
+* allocated to this auxiliary data structure.
+*
+* This routine can be called at any time. If the name index does not
+* exist, the routine does nothing. */
+
+void glp_delete_index(glp_prob *lp)
+{ int i, j;
+ /* delete row name index */
+ if (lp->r_tree != NULL)
+ { for (i = 1; i <= lp->m; i++) lp->row[i]->node = NULL;
+ avl_delete_tree(lp->r_tree), lp->r_tree = NULL;
+ }
+ /* delete column name index */
+ if (lp->c_tree != NULL)
+ { for (j = 1; j <= lp->n; j++) lp->col[j]->node = NULL;
+ avl_delete_tree(lp->c_tree), lp->c_tree = NULL;
+ }
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/prob4.c b/test/monniaux/glpk-4.65/src/api/prob4.c
new file mode 100644
index 00000000..8c2b5ae5
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/prob4.c
@@ -0,0 +1,156 @@
+/* prob4.c (problem scaling routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_set_rii - set (change) row scale factor
+*
+* SYNOPSIS
+*
+* void glp_set_rii(glp_prob *lp, int i, double rii);
+*
+* DESCRIPTION
+*
+* The routine glp_set_rii sets (changes) the scale factor r[i,i] for
+* i-th row of the specified problem object. */
+
+void glp_set_rii(glp_prob *lp, int i, double rii)
+{ if (!(1 <= i && i <= lp->m))
+ xerror("glp_set_rii: i = %d; row number out of range\n", i);
+ if (rii <= 0.0)
+ xerror("glp_set_rii: i = %d; rii = %g; invalid scale factor\n",
+ i, rii);
+ if (lp->valid && lp->row[i]->rii != rii)
+ { GLPAIJ *aij;
+ for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->col->stat == GLP_BS)
+ { /* invalidate the basis factorization */
+ lp->valid = 0;
+ break;
+ }
+ }
+ }
+ lp->row[i]->rii = rii;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set sjj - set (change) column scale factor
+*
+* SYNOPSIS
+*
+* void glp_set_sjj(glp_prob *lp, int j, double sjj);
+*
+* DESCRIPTION
+*
+* The routine glp_set_sjj sets (changes) the scale factor s[j,j] for
+* j-th column of the specified problem object. */
+
+void glp_set_sjj(glp_prob *lp, int j, double sjj)
+{ if (!(1 <= j && j <= lp->n))
+ xerror("glp_set_sjj: j = %d; column number out of range\n", j);
+ if (sjj <= 0.0)
+ xerror("glp_set_sjj: j = %d; sjj = %g; invalid scale factor\n",
+ j, sjj);
+ if (lp->valid && lp->col[j]->sjj != sjj && lp->col[j]->stat ==
+ GLP_BS)
+ { /* invalidate the basis factorization */
+ lp->valid = 0;
+ }
+ lp->col[j]->sjj = sjj;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_rii - retrieve row scale factor
+*
+* SYNOPSIS
+*
+* double glp_get_rii(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_get_rii returns current scale factor r[i,i] for i-th
+* row of the specified problem object. */
+
+double glp_get_rii(glp_prob *lp, int i)
+{ if (!(1 <= i && i <= lp->m))
+ xerror("glp_get_rii: i = %d; row number out of range\n", i);
+ return lp->row[i]->rii;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_sjj - retrieve column scale factor
+*
+* SYNOPSIS
+*
+* double glp_get_sjj(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_get_sjj returns current scale factor s[j,j] for j-th
+* column of the specified problem object. */
+
+double glp_get_sjj(glp_prob *lp, int j)
+{ if (!(1 <= j && j <= lp->n))
+ xerror("glp_get_sjj: j = %d; column number out of range\n", j);
+ return lp->col[j]->sjj;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_unscale_prob - unscale problem data
+*
+* SYNOPSIS
+*
+* void glp_unscale_prob(glp_prob *lp);
+*
+* DESCRIPTION
+*
+* The routine glp_unscale_prob performs unscaling of problem data for
+* the specified problem object.
+*
+* "Unscaling" means replacing the current scaling matrices R and S by
+* unity matrices that cancels the scaling effect. */
+
+void glp_unscale_prob(glp_prob *lp)
+{ int m = glp_get_num_rows(lp);
+ int n = glp_get_num_cols(lp);
+ int i, j;
+ for (i = 1; i <= m; i++) glp_set_rii(lp, i, 1.0);
+ for (j = 1; j <= n; j++) glp_set_sjj(lp, j, 1.0);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/prob5.c b/test/monniaux/glpk-4.65/src/api/prob5.c
new file mode 100644
index 00000000..1c1d3160
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/prob5.c
@@ -0,0 +1,168 @@
+/* prob5.c (LP problem basis constructing routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_set_row_stat - set (change) row status
+*
+* SYNOPSIS
+*
+* void glp_set_row_stat(glp_prob *lp, int i, int stat);
+*
+* DESCRIPTION
+*
+* The routine glp_set_row_stat sets (changes) status of the auxiliary
+* variable associated with i-th row.
+*
+* The new status of the auxiliary variable should be specified by the
+* parameter stat as follows:
+*
+* GLP_BS - basic variable;
+* GLP_NL - non-basic variable;
+* GLP_NU - non-basic variable on its upper bound; if the variable is
+* not double-bounded, this means the same as GLP_NL (only in
+* case of this routine);
+* GLP_NF - the same as GLP_NL (only in case of this routine);
+* GLP_NS - the same as GLP_NL (only in case of this routine). */
+
+void glp_set_row_stat(glp_prob *lp, int i, int stat)
+{ GLPROW *row;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_set_row_stat: i = %d; row number out of range\n",
+ i);
+ if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU ||
+ stat == GLP_NF || stat == GLP_NS))
+ xerror("glp_set_row_stat: i = %d; stat = %d; invalid status\n",
+ i, stat);
+ row = lp->row[i];
+ if (stat != GLP_BS)
+ { switch (row->type)
+ { case GLP_FR: stat = GLP_NF; break;
+ case GLP_LO: stat = GLP_NL; break;
+ case GLP_UP: stat = GLP_NU; break;
+ case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break;
+ case GLP_FX: stat = GLP_NS; break;
+ default: xassert(row != row);
+ }
+ }
+ if (row->stat == GLP_BS && stat != GLP_BS ||
+ row->stat != GLP_BS && stat == GLP_BS)
+ { /* invalidate the basis factorization */
+ lp->valid = 0;
+ }
+ row->stat = stat;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_set_col_stat - set (change) column status
+*
+* SYNOPSIS
+*
+* void glp_set_col_stat(glp_prob *lp, int j, int stat);
+*
+* DESCRIPTION
+*
+* The routine glp_set_col_stat sets (changes) status of the structural
+* variable associated with j-th column.
+*
+* The new status of the structural variable should be specified by the
+* parameter stat as follows:
+*
+* GLP_BS - basic variable;
+* GLP_NL - non-basic variable;
+* GLP_NU - non-basic variable on its upper bound; if the variable is
+* not double-bounded, this means the same as GLP_NL (only in
+* case of this routine);
+* GLP_NF - the same as GLP_NL (only in case of this routine);
+* GLP_NS - the same as GLP_NL (only in case of this routine). */
+
+void glp_set_col_stat(glp_prob *lp, int j, int stat)
+{ GLPCOL *col;
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_set_col_stat: j = %d; column number out of range\n"
+ , j);
+ if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU ||
+ stat == GLP_NF || stat == GLP_NS))
+ xerror("glp_set_col_stat: j = %d; stat = %d; invalid status\n",
+ j, stat);
+ col = lp->col[j];
+ if (stat != GLP_BS)
+ { switch (col->type)
+ { case GLP_FR: stat = GLP_NF; break;
+ case GLP_LO: stat = GLP_NL; break;
+ case GLP_UP: stat = GLP_NU; break;
+ case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break;
+ case GLP_FX: stat = GLP_NS; break;
+ default: xassert(col != col);
+ }
+ }
+ if (col->stat == GLP_BS && stat != GLP_BS ||
+ col->stat != GLP_BS && stat == GLP_BS)
+ { /* invalidate the basis factorization */
+ lp->valid = 0;
+ }
+ col->stat = stat;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_std_basis - construct standard initial LP basis
+*
+* SYNOPSIS
+*
+* void glp_std_basis(glp_prob *lp);
+*
+* DESCRIPTION
+*
+* The routine glp_std_basis builds the "standard" (trivial) initial
+* basis for the specified problem object.
+*
+* In the "standard" basis all auxiliary variables are basic, and all
+* structural variables are non-basic. */
+
+void glp_std_basis(glp_prob *lp)
+{ int i, j;
+ /* make all auxiliary variables basic */
+ for (i = 1; i <= lp->m; i++)
+ glp_set_row_stat(lp, i, GLP_BS);
+ /* make all structural variables non-basic */
+ for (j = 1; j <= lp->n; j++)
+ { GLPCOL *col = lp->col[j];
+ if (col->type == GLP_DB && fabs(col->lb) > fabs(col->ub))
+ glp_set_col_stat(lp, j, GLP_NU);
+ else
+ glp_set_col_stat(lp, j, GLP_NL);
+ }
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/prrngs.c b/test/monniaux/glpk-4.65/src/api/prrngs.c
new file mode 100644
index 00000000..41a141ff
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/prrngs.c
@@ -0,0 +1,302 @@
+/* prrngs.c (print sensitivity analysis report) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+#define xfprintf glp_format
+
+static char *format(char buf[13+1], double x)
+{ /* format floating-point number in MPS/360-like style */
+ if (x == -DBL_MAX)
+ strcpy(buf, " -Inf");
+ else if (x == +DBL_MAX)
+ strcpy(buf, " +Inf");
+ else if (fabs(x) <= 999999.99998)
+ { sprintf(buf, "%13.5f", x);
+#if 1
+ if (strcmp(buf, " 0.00000") == 0 ||
+ strcmp(buf, " -0.00000") == 0)
+ strcpy(buf, " . ");
+ else if (memcmp(buf, " 0.", 8) == 0)
+ memcpy(buf, " .", 8);
+ else if (memcmp(buf, " -0.", 8) == 0)
+ memcpy(buf, " -.", 8);
+#endif
+ }
+ else
+ sprintf(buf, "%13.6g", x);
+ return buf;
+}
+
+int glp_print_ranges(glp_prob *P, int len, const int list[],
+ int flags, const char *fname)
+{ /* print sensitivity analysis report */
+ glp_file *fp = NULL;
+ GLPROW *row;
+ GLPCOL *col;
+ int m, n, pass, k, t, numb, type, stat, var1, var2, count, page,
+ ret;
+ double lb, ub, slack, coef, prim, dual, value1, value2, coef1,
+ coef2, obj1, obj2;
+ const char *name, *limit;
+ char buf[13+1];
+ /* sanity checks */
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_print_ranges: P = %p; invalid problem object\n",
+ P);
+#endif
+ m = P->m, n = P->n;
+ if (len < 0)
+ xerror("glp_print_ranges: len = %d; invalid list length\n",
+ len);
+ if (len > 0)
+ { if (list == NULL)
+ xerror("glp_print_ranges: list = %p: invalid parameter\n",
+ list);
+ for (t = 1; t <= len; t++)
+ { k = list[t];
+ if (!(1 <= k && k <= m+n))
+ xerror("glp_print_ranges: list[%d] = %d; row/column numb"
+ "er out of range\n", t, k);
+ }
+ }
+ if (flags != 0)
+ xerror("glp_print_ranges: flags = %d; invalid parameter\n",
+ flags);
+ if (fname == NULL)
+ xerror("glp_print_ranges: fname = %p; invalid parameter\n",
+ fname);
+ if (glp_get_status(P) != GLP_OPT)
+ { xprintf("glp_print_ranges: optimal basic solution required\n");
+ ret = 1;
+ goto done;
+ }
+ if (!glp_bf_exists(P))
+ { xprintf("glp_print_ranges: basis factorization required\n");
+ ret = 2;
+ goto done;
+ }
+ /* start reporting */
+ xprintf("Write sensitivity analysis report to '%s'...\n", fname);
+ fp = glp_open(fname, "w");
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 3;
+ goto done;
+ }
+ page = count = 0;
+ for (pass = 1; pass <= 2; pass++)
+ for (t = 1; t <= (len == 0 ? m+n : len); t++)
+ { if (t == 1) count = 0;
+ k = (len == 0 ? t : list[t]);
+ if (pass == 1 && k > m || pass == 2 && k <= m)
+ continue;
+ if (count == 0)
+ { xfprintf(fp, "GLPK %-4s - SENSITIVITY ANALYSIS REPORT%73sPa"
+ "ge%4d\n", glp_version(), "", ++page);
+ xfprintf(fp, "\n");
+ xfprintf(fp, "%-12s%s\n", "Problem:",
+ P->name == NULL ? "" : P->name);
+ xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+ P->obj == NULL ? "" : P->obj,
+ P->obj == NULL ? "" : " = ", P->obj_val,
+ P->dir == GLP_MIN ? "MINimum" :
+ P->dir == GLP_MAX ? "MAXimum" : "???");
+ xfprintf(fp, "\n");
+ xfprintf(fp, "%6s %-12s %2s %13s %13s %13s %13s %13s %13s "
+ "%s\n", "No.", pass == 1 ? "Row name" : "Column name",
+ "St", "Activity", pass == 1 ? "Slack" : "Obj coef",
+ "Lower bound", "Activity", "Obj coef", "Obj value at",
+ "Limiting");
+ xfprintf(fp, "%6s %-12s %2s %13s %13s %13s %13s %13s %13s "
+ "%s\n", "", "", "", "", "Marginal", "Upper bound",
+ "range", "range", "break point", "variable");
+ xfprintf(fp, "------ ------------ -- ------------- --------"
+ "----- ------------- ------------- ------------- ------"
+ "------- ------------\n");
+ }
+ if (pass == 1)
+ { numb = k;
+ xassert(1 <= numb && numb <= m);
+ row = P->row[numb];
+ name = row->name;
+ type = row->type;
+ lb = glp_get_row_lb(P, numb);
+ ub = glp_get_row_ub(P, numb);
+ coef = 0.0;
+ stat = row->stat;
+ prim = row->prim;
+ if (type == GLP_FR)
+ slack = - prim;
+ else if (type == GLP_LO)
+ slack = lb - prim;
+ else if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+ slack = ub - prim;
+ dual = row->dual;
+ }
+ else
+ { numb = k - m;
+ xassert(1 <= numb && numb <= n);
+ col = P->col[numb];
+ name = col->name;
+ lb = glp_get_col_lb(P, numb);
+ ub = glp_get_col_ub(P, numb);
+ coef = col->coef;
+ stat = col->stat;
+ prim = col->prim;
+ slack = 0.0;
+ dual = col->dual;
+ }
+ if (stat != GLP_BS)
+ { glp_analyze_bound(P, k, &value1, &var1, &value2, &var2);
+ if (stat == GLP_NF)
+ coef1 = coef2 = coef;
+ else if (stat == GLP_NS)
+ coef1 = -DBL_MAX, coef2 = +DBL_MAX;
+ else if (stat == GLP_NL && P->dir == GLP_MIN ||
+ stat == GLP_NU && P->dir == GLP_MAX)
+ coef1 = coef - dual, coef2 = +DBL_MAX;
+ else
+ coef1 = -DBL_MAX, coef2 = coef - dual;
+ if (value1 == -DBL_MAX)
+ { if (dual < -1e-9)
+ obj1 = +DBL_MAX;
+ else if (dual > +1e-9)
+ obj1 = -DBL_MAX;
+ else
+ obj1 = P->obj_val;
+ }
+ else
+ obj1 = P->obj_val + dual * (value1 - prim);
+ if (value2 == +DBL_MAX)
+ { if (dual < -1e-9)
+ obj2 = -DBL_MAX;
+ else if (dual > +1e-9)
+ obj2 = +DBL_MAX;
+ else
+ obj2 = P->obj_val;
+ }
+ else
+ obj2 = P->obj_val + dual * (value2 - prim);
+ }
+ else
+ { glp_analyze_coef(P, k, &coef1, &var1, &value1, &coef2,
+ &var2, &value2);
+ if (coef1 == -DBL_MAX)
+ { if (prim < -1e-9)
+ obj1 = +DBL_MAX;
+ else if (prim > +1e-9)
+ obj1 = -DBL_MAX;
+ else
+ obj1 = P->obj_val;
+ }
+ else
+ obj1 = P->obj_val + (coef1 - coef) * prim;
+ if (coef2 == +DBL_MAX)
+ { if (prim < -1e-9)
+ obj2 = -DBL_MAX;
+ else if (prim > +1e-9)
+ obj2 = +DBL_MAX;
+ else
+ obj2 = P->obj_val;
+ }
+ else
+ obj2 = P->obj_val + (coef2 - coef) * prim;
+ }
+ /*** first line ***/
+ /* row/column number */
+ xfprintf(fp, "%6d", numb);
+ /* row/column name */
+ xfprintf(fp, " %-12.12s", name == NULL ? "" : name);
+ if (name != NULL && strlen(name) > 12)
+ xfprintf(fp, "%s\n%6s %12s", name+12, "", "");
+ /* row/column status */
+ xfprintf(fp, " %2s",
+ stat == GLP_BS ? "BS" : stat == GLP_NL ? "NL" :
+ stat == GLP_NU ? "NU" : stat == GLP_NF ? "NF" :
+ stat == GLP_NS ? "NS" : "??");
+ /* row/column activity */
+ xfprintf(fp, " %s", format(buf, prim));
+ /* row slack, column objective coefficient */
+ xfprintf(fp, " %s", format(buf, k <= m ? slack : coef));
+ /* row/column lower bound */
+ xfprintf(fp, " %s", format(buf, lb));
+ /* row/column activity range */
+ xfprintf(fp, " %s", format(buf, value1));
+ /* row/column objective coefficient range */
+ xfprintf(fp, " %s", format(buf, coef1));
+ /* objective value at break point */
+ xfprintf(fp, " %s", format(buf, obj1));
+ /* limiting variable name */
+ if (var1 != 0)
+ { if (var1 <= m)
+ limit = glp_get_row_name(P, var1);
+ else
+ limit = glp_get_col_name(P, var1 - m);
+ if (limit != NULL)
+ xfprintf(fp, " %s", limit);
+ }
+ xfprintf(fp, "\n");
+ /*** second line ***/
+ xfprintf(fp, "%6s %-12s %2s %13s", "", "", "", "");
+ /* row/column reduced cost */
+ xfprintf(fp, " %s", format(buf, dual));
+ /* row/column upper bound */
+ xfprintf(fp, " %s", format(buf, ub));
+ /* row/column activity range */
+ xfprintf(fp, " %s", format(buf, value2));
+ /* row/column objective coefficient range */
+ xfprintf(fp, " %s", format(buf, coef2));
+ /* objective value at break point */
+ xfprintf(fp, " %s", format(buf, obj2));
+ /* limiting variable name */
+ if (var2 != 0)
+ { if (var2 <= m)
+ limit = glp_get_row_name(P, var2);
+ else
+ limit = glp_get_col_name(P, var2 - m);
+ if (limit != NULL)
+ xfprintf(fp, " %s", limit);
+ }
+ xfprintf(fp, "\n");
+ xfprintf(fp, "\n");
+ /* print 10 items per page */
+ count = (count + 1) % 10;
+ }
+ xfprintf(fp, "End of report\n");
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 4;
+ goto done;
+ }
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/prsol.c b/test/monniaux/glpk-4.65/src/api/prsol.c
new file mode 100644
index 00000000..d785dc2e
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/prsol.c
@@ -0,0 +1,202 @@
+/* prsol.c (write basic solution in printable format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+#define xfprintf glp_format
+
+int glp_print_sol(glp_prob *P, const char *fname)
+{ /* write basic solution in printable format */
+ glp_file *fp;
+ GLPROW *row;
+ GLPCOL *col;
+ int i, j, t, ae_ind, re_ind, ret;
+ double ae_max, re_max;
+ xprintf("Writing basic solution to '%s'...\n", fname);
+ fp = glp_open(fname, "w");
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xfprintf(fp, "%-12s%s\n", "Problem:",
+ P->name == NULL ? "" : P->name);
+ xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
+ xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
+ xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
+ t = glp_get_status(P);
+ xfprintf(fp, "%-12s%s\n", "Status:",
+ t == GLP_OPT ? "OPTIMAL" :
+ t == GLP_FEAS ? "FEASIBLE" :
+ t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
+ t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" :
+ t == GLP_UNBND ? "UNBOUNDED" :
+ t == GLP_UNDEF ? "UNDEFINED" : "???");
+ xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+ P->obj == NULL ? "" : P->obj,
+ P->obj == NULL ? "" : " = ", P->obj_val,
+ P->dir == GLP_MIN ? "MINimum" :
+ P->dir == GLP_MAX ? "MAXimum" : "???");
+ xfprintf(fp, "\n");
+ xfprintf(fp, " No. Row name St Activity Lower bound "
+ " Upper bound Marginal\n");
+ xfprintf(fp, "------ ------------ -- ------------- ------------- "
+ "------------- -------------\n");
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ xfprintf(fp, "%6d ", i);
+ if (row->name == NULL || strlen(row->name) <= 12)
+ xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
+ else
+ xfprintf(fp, "%s\n%20s", row->name, "");
+ xfprintf(fp, "%s ",
+ row->stat == GLP_BS ? "B " :
+ row->stat == GLP_NL ? "NL" :
+ row->stat == GLP_NU ? "NU" :
+ row->stat == GLP_NF ? "NF" :
+ row->stat == GLP_NS ? "NS" : "??");
+ xfprintf(fp, "%13.6g ",
+ fabs(row->prim) <= 1e-9 ? 0.0 : row->prim);
+ if (row->type == GLP_LO || row->type == GLP_DB ||
+ row->type == GLP_FX)
+ xfprintf(fp, "%13.6g ", row->lb);
+ else
+ xfprintf(fp, "%13s ", "");
+ if (row->type == GLP_UP || row->type == GLP_DB)
+ xfprintf(fp, "%13.6g ", row->ub);
+ else
+ xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
+ if (row->stat != GLP_BS)
+ { if (fabs(row->dual) <= 1e-9)
+ xfprintf(fp, "%13s", "< eps");
+ else
+ xfprintf(fp, "%13.6g ", row->dual);
+ }
+ xfprintf(fp, "\n");
+ }
+ xfprintf(fp, "\n");
+ xfprintf(fp, " No. Column name St Activity Lower bound "
+ " Upper bound Marginal\n");
+ xfprintf(fp, "------ ------------ -- ------------- ------------- "
+ "------------- -------------\n");
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ xfprintf(fp, "%6d ", j);
+ if (col->name == NULL || strlen(col->name) <= 12)
+ xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
+ else
+ xfprintf(fp, "%s\n%20s", col->name, "");
+ xfprintf(fp, "%s ",
+ col->stat == GLP_BS ? "B " :
+ col->stat == GLP_NL ? "NL" :
+ col->stat == GLP_NU ? "NU" :
+ col->stat == GLP_NF ? "NF" :
+ col->stat == GLP_NS ? "NS" : "??");
+ xfprintf(fp, "%13.6g ",
+ fabs(col->prim) <= 1e-9 ? 0.0 : col->prim);
+ if (col->type == GLP_LO || col->type == GLP_DB ||
+ col->type == GLP_FX)
+ xfprintf(fp, "%13.6g ", col->lb);
+ else
+ xfprintf(fp, "%13s ", "");
+ if (col->type == GLP_UP || col->type == GLP_DB)
+ xfprintf(fp, "%13.6g ", col->ub);
+ else
+ xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
+ if (col->stat != GLP_BS)
+ { if (fabs(col->dual) <= 1e-9)
+ xfprintf(fp, "%13s", "< eps");
+ else
+ xfprintf(fp, "%13.6g ", col->dual);
+ }
+ xfprintf(fp, "\n");
+ }
+ xfprintf(fp, "\n");
+ xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
+ xfprintf(fp, "\n");
+ glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+ &re_ind);
+ xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
+ ae_max, ae_ind);
+ xfprintf(fp, " max.rel.err = %.2e on row %d\n",
+ re_max, re_ind);
+ xfprintf(fp, "%8s%s\n", "",
+ re_max <= 1e-9 ? "High quality" :
+ re_max <= 1e-6 ? "Medium quality" :
+ re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
+ xfprintf(fp, "\n");
+ glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+ &re_ind);
+ xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
+ ae_max, ae_ind <= P->m ? "row" : "column",
+ ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+ xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
+ re_max, re_ind <= P->m ? "row" : "column",
+ re_ind <= P->m ? re_ind : re_ind - P->m);
+ xfprintf(fp, "%8s%s\n", "",
+ re_max <= 1e-9 ? "High quality" :
+ re_max <= 1e-6 ? "Medium quality" :
+ re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
+ "E");
+ xfprintf(fp, "\n");
+ glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
+ &re_ind);
+ xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
+ ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
+ xfprintf(fp, " max.rel.err = %.2e on column %d\n",
+ re_max, re_ind == 0 ? 0 : re_ind - P->m);
+ xfprintf(fp, "%8s%s\n", "",
+ re_max <= 1e-9 ? "High quality" :
+ re_max <= 1e-6 ? "Medium quality" :
+ re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
+ xfprintf(fp, "\n");
+ glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
+ &re_ind);
+ xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
+ ae_max, ae_ind <= P->m ? "row" : "column",
+ ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+ xfprintf(fp, " max.rel.err = %.2e on %s %d\n",
+ re_max, re_ind <= P->m ? "row" : "column",
+ re_ind <= P->m ? re_ind : re_ind - P->m);
+ xfprintf(fp, "%8s%s\n", "",
+ re_max <= 1e-9 ? "High quality" :
+ re_max <= 1e-6 ? "Medium quality" :
+ re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
+ ;
+ xfprintf(fp, "\n");
+ xfprintf(fp, "End of output\n");
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/rdasn.c b/test/monniaux/glpk-4.65/src/api/rdasn.c
new file mode 100644
index 00000000..05dcb9fc
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/rdasn.c
@@ -0,0 +1,164 @@
+/* rdasn.c (read assignment problem data in DIMACS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "dimacs.h"
+#include "glpk.h"
+#include "misc.h"
+
+#define error dmx_error
+#define warning dmx_warning
+#define read_char dmx_read_char
+#define read_designator dmx_read_designator
+#define read_field dmx_read_field
+#define end_of_line dmx_end_of_line
+#define check_int dmx_check_int
+
+/***********************************************************************
+* NAME
+*
+* glp_read_asnprob - read assignment problem data in DIMACS format
+*
+* SYNOPSIS
+*
+* int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
+* const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_read_asnprob reads assignment problem data in DIMACS
+* format from a text file.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
+ *fname)
+{ DMX _csa, *csa = &_csa;
+ glp_vertex *v;
+ glp_arc *a;
+ int nv, na, n1, i, j, k, ret = 0;
+ double cost;
+ char *flag = NULL;
+ if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+ xerror("glp_read_asnprob: v_set = %d; invalid offset\n",
+ v_set);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_read_asnprob: a_cost = %d; invalid offset\n",
+ a_cost);
+ glp_erase_graph(G, G->v_size, G->a_size);
+ if (setjmp(csa->jump))
+ { ret = 1;
+ goto done;
+ }
+ csa->fname = fname;
+ csa->fp = NULL;
+ csa->count = 0;
+ csa->c = '\n';
+ csa->field[0] = '\0';
+ csa->empty = csa->nonint = 0;
+ xprintf("Reading assignment problem data from '%s'...\n", fname);
+ csa->fp = glp_open(fname, "r");
+ if (csa->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ longjmp(csa->jump, 1);
+ }
+ /* read problem line */
+ read_designator(csa);
+ if (strcmp(csa->field, "p") != 0)
+ error(csa, "problem line missing or invalid");
+ read_field(csa);
+ if (strcmp(csa->field, "asn") != 0)
+ error(csa, "wrong problem designator; 'asn' expected");
+ read_field(csa);
+ if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
+ error(csa, "number of nodes missing or invalid");
+ read_field(csa);
+ if (!(str2int(csa->field, &na) == 0 && na >= 0))
+ error(csa, "number of arcs missing or invalid");
+ if (nv > 0) glp_add_vertices(G, nv);
+ end_of_line(csa);
+ /* read node descriptor lines */
+ flag = xcalloc(1+nv, sizeof(char));
+ memset(&flag[1], 0, nv * sizeof(char));
+ n1 = 0;
+ for (;;)
+ { read_designator(csa);
+ if (strcmp(csa->field, "n") != 0) break;
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "node number missing or invalid");
+ if (!(1 <= i && i <= nv))
+ error(csa, "node number %d out of range", i);
+ if (flag[i])
+ error(csa, "duplicate descriptor of node %d", i);
+ flag[i] = 1, n1++;
+ end_of_line(csa);
+ }
+ xprintf(
+ "Assignment problem has %d + %d = %d node%s and %d arc%s\n",
+ n1, nv - n1, nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
+ if (v_set >= 0)
+ { for (i = 1; i <= nv; i++)
+ { v = G->v[i];
+ k = (flag[i] ? 0 : 1);
+ memcpy((char *)v->data + v_set, &k, sizeof(int));
+ }
+ }
+ /* read arc descriptor lines */
+ for (k = 1; k <= na; k++)
+ { if (k > 1) read_designator(csa);
+ if (strcmp(csa->field, "a") != 0)
+ error(csa, "wrong line designator; 'a' expected");
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "starting node number missing or invalid");
+ if (!(1 <= i && i <= nv))
+ error(csa, "starting node number %d out of range", i);
+ if (!flag[i])
+ error(csa, "node %d cannot be a starting node", i);
+ read_field(csa);
+ if (str2int(csa->field, &j) != 0)
+ error(csa, "ending node number missing or invalid");
+ if (!(1 <= j && j <= nv))
+ error(csa, "ending node number %d out of range", j);
+ if (flag[j])
+ error(csa, "node %d cannot be an ending node", j);
+ read_field(csa);
+ if (str2num(csa->field, &cost) != 0)
+ error(csa, "arc cost missing or invalid");
+ check_int(csa, cost);
+ a = glp_add_arc(G, i, j);
+ if (a_cost >= 0)
+ memcpy((char *)a->data + a_cost, &cost, sizeof(double));
+ end_of_line(csa);
+ }
+ xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+ if (csa->fp != NULL) glp_close(csa->fp);
+ if (flag != NULL) xfree(flag);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/rdcc.c b/test/monniaux/glpk-4.65/src/api/rdcc.c
new file mode 100644
index 00000000..c63d60d8
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/rdcc.c
@@ -0,0 +1,162 @@
+/* rdcc.c (read graph in DIMACS clique/coloring format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "dimacs.h"
+#include "glpk.h"
+#include "misc.h"
+
+#define error dmx_error
+#define warning dmx_warning
+#define read_char dmx_read_char
+#define read_designator dmx_read_designator
+#define read_field dmx_read_field
+#define end_of_line dmx_end_of_line
+#define check_int dmx_check_int
+
+/***********************************************************************
+* NAME
+*
+* glp_read_ccdata - read graph in DIMACS clique/coloring format
+*
+* SYNOPSIS
+*
+* int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_read_ccdata reads an (undirected) graph in DIMACS
+* clique/coloring format from a text file.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname)
+{ DMX _csa, *csa = &_csa;
+ glp_vertex *v;
+ int i, j, k, nv, ne, ret = 0;
+ double w;
+ char *flag = NULL;
+ if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
+ xerror("glp_read_ccdata: v_wgt = %d; invalid offset\n",
+ v_wgt);
+ glp_erase_graph(G, G->v_size, G->a_size);
+ if (setjmp(csa->jump))
+ { ret = 1;
+ goto done;
+ }
+ csa->fname = fname;
+ csa->fp = NULL;
+ csa->count = 0;
+ csa->c = '\n';
+ csa->field[0] = '\0';
+ csa->empty = csa->nonint = 0;
+ xprintf("Reading graph from '%s'...\n", fname);
+ csa->fp = glp_open(fname, "r");
+ if (csa->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ longjmp(csa->jump, 1);
+ }
+ /* read problem line */
+ read_designator(csa);
+ if (strcmp(csa->field, "p") != 0)
+ error(csa, "problem line missing or invalid");
+ read_field(csa);
+ if (strcmp(csa->field, "edge") != 0)
+ error(csa, "wrong problem designator; 'edge' expected");
+ read_field(csa);
+ if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
+ error(csa, "number of vertices missing or invalid");
+ read_field(csa);
+ if (!(str2int(csa->field, &ne) == 0 && ne >= 0))
+ error(csa, "number of edges missing or invalid");
+ xprintf("Graph has %d vert%s and %d edge%s\n",
+ nv, nv == 1 ? "ex" : "ices", ne, ne == 1 ? "" : "s");
+ if (nv > 0) glp_add_vertices(G, nv);
+ end_of_line(csa);
+ /* read node descriptor lines */
+ flag = xcalloc(1+nv, sizeof(char));
+ memset(&flag[1], 0, nv * sizeof(char));
+ if (v_wgt >= 0)
+ { w = 1.0;
+ for (i = 1; i <= nv; i++)
+ { v = G->v[i];
+ memcpy((char *)v->data + v_wgt, &w, sizeof(double));
+ }
+ }
+ for (;;)
+ { read_designator(csa);
+ if (strcmp(csa->field, "n") != 0) break;
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "vertex number missing or invalid");
+ if (!(1 <= i && i <= nv))
+ error(csa, "vertex number %d out of range", i);
+ if (flag[i])
+ error(csa, "duplicate descriptor of vertex %d", i);
+ read_field(csa);
+ if (str2num(csa->field, &w) != 0)
+ error(csa, "vertex weight missing or invalid");
+ check_int(csa, w);
+ if (v_wgt >= 0)
+ { v = G->v[i];
+ memcpy((char *)v->data + v_wgt, &w, sizeof(double));
+ }
+ flag[i] = 1;
+ end_of_line(csa);
+ }
+ xfree(flag), flag = NULL;
+ /* read edge descriptor lines */
+ for (k = 1; k <= ne; k++)
+ { if (k > 1) read_designator(csa);
+ if (strcmp(csa->field, "e") != 0)
+ error(csa, "wrong line designator; 'e' expected");
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "first vertex number missing or invalid");
+ if (!(1 <= i && i <= nv))
+ error(csa, "first vertex number %d out of range", i);
+ read_field(csa);
+ if (str2int(csa->field, &j) != 0)
+ error(csa, "second vertex number missing or invalid");
+ if (!(1 <= j && j <= nv))
+ error(csa, "second vertex number %d out of range", j);
+ glp_add_arc(G, i, j);
+ end_of_line(csa);
+ }
+ xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+ if (csa->fp != NULL) glp_close(csa->fp);
+ if (flag != NULL) xfree(flag);
+ return ret;
+}
+
+/**********************************************************************/
+
+int glp_read_graph(glp_graph *G, const char *fname)
+{ return
+ glp_read_ccdata(G, -1, fname);
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/rdcnf.c b/test/monniaux/glpk-4.65/src/api/rdcnf.c
new file mode 100644
index 00000000..acab50fe
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/rdcnf.c
@@ -0,0 +1,136 @@
+/* rdcnf.c (read CNF-SAT problem data in DIMACS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "dimacs.h"
+#include "misc.h"
+#include "prob.h"
+
+#define xfprintf glp_format
+#define error dmx_error
+#define warning dmx_warning
+#define read_char dmx_read_char
+#define read_designator dmx_read_designator
+#define read_field dmx_read_field
+#define end_of_line dmx_end_of_line
+#define check_int dmx_check_int
+
+int glp_read_cnfsat(glp_prob *P, const char *fname)
+{ /* read CNF-SAT problem data in DIMACS format */
+ DMX _csa, *csa = &_csa;
+ int m, n, i, j, len, neg, rhs, ret = 0, *ind = NULL;
+ double *val = NULL;
+ char *map = NULL;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_read_cnfsat: P = %p; invalid problem object\n",
+ P);
+#endif
+ if (fname == NULL)
+ xerror("glp_read_cnfsat: fname = %p; invalid parameter\n",
+ fname);
+ glp_erase_prob(P);
+ if (setjmp(csa->jump))
+ { ret = 1;
+ goto done;
+ }
+ csa->fname = fname;
+ csa->fp = NULL;
+ csa->count = 0;
+ csa->c = '\n';
+ csa->field[0] = '\0';
+ csa->empty = csa->nonint = 0;
+ xprintf("Reading CNF-SAT problem data from '%s'...\n", fname);
+ csa->fp = glp_open(fname, "r");
+ if (csa->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ longjmp(csa->jump, 1);
+ }
+ /* read problem line */
+ read_designator(csa);
+ if (strcmp(csa->field, "p") != 0)
+ error(csa, "problem line missing or invalid");
+ read_field(csa);
+ if (strcmp(csa->field, "cnf") != 0)
+ error(csa, "wrong problem designator; 'cnf' expected\n");
+ read_field(csa);
+ if (!(str2int(csa->field, &n) == 0 && n >= 0))
+ error(csa, "number of variables missing or invalid\n");
+ read_field(csa);
+ if (!(str2int(csa->field, &m) == 0 && m >= 0))
+ error(csa, "number of clauses missing or invalid\n");
+ xprintf("Instance has %d variable%s and %d clause%s\n",
+ n, n == 1 ? "" : "s", m, m == 1 ? "" : "s");
+ end_of_line(csa);
+ if (m > 0)
+ glp_add_rows(P, m);
+ if (n > 0)
+ { glp_add_cols(P, n);
+ for (j = 1; j <= n; j++)
+ glp_set_col_kind(P, j, GLP_BV);
+ }
+ /* allocate working arrays */
+ ind = xcalloc(1+n, sizeof(int));
+ val = xcalloc(1+n, sizeof(double));
+ map = xcalloc(1+n, sizeof(char));
+ for (j = 1; j <= n; j++) map[j] = 0;
+ /* read clauses */
+ for (i = 1; i <= m; i++)
+ { /* read i-th clause */
+ len = 0, rhs = 1;
+ for (;;)
+ { /* skip white-space characters */
+ while (csa->c == ' ' || csa->c == '\n')
+ read_char(csa);
+ /* read term */
+ read_field(csa);
+ if (str2int(csa->field, &j) != 0)
+ error(csa, "variable number missing or invalid\n");
+ if (j > 0)
+ neg = 0;
+ else if (j < 0)
+ neg = 1, j = -j, rhs--;
+ else
+ break;
+ if (!(1 <= j && j <= n))
+ error(csa, "variable number out of range\n");
+ if (map[j])
+ error(csa, "duplicate variable number\n");
+ len++, ind[len] = j, val[len] = (neg ? -1.0 : +1.0);
+ map[j] = 1;
+ }
+ glp_set_row_bnds(P, i, GLP_LO, (double)rhs, 0.0);
+ glp_set_mat_row(P, i, len, ind, val);
+ while (len > 0) map[ind[len--]] = 0;
+ }
+ xprintf("%d lines were read\n", csa->count);
+ /* problem data has been successfully read */
+ glp_sort_matrix(P);
+done: if (csa->fp != NULL) glp_close(csa->fp);
+ if (ind != NULL) xfree(ind);
+ if (val != NULL) xfree(val);
+ if (map != NULL) xfree(map);
+ if (ret) glp_erase_prob(P);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/rdipt.c b/test/monniaux/glpk-4.65/src/api/rdipt.c
new file mode 100644
index 00000000..aaf8e9d4
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/rdipt.c
@@ -0,0 +1,185 @@
+/* rdipt.c (read interior-point solution in GLPK format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "dimacs.h"
+#include "env.h"
+#include "misc.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_read_ipt - read interior-point solution in GLPK format
+*
+* SYNOPSIS
+*
+* int glp_read_ipt(glp_prob *P, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_read_ipt reads interior-point solution from a text
+* file in GLPK format.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_read_ipt(glp_prob *P, const char *fname)
+{ DMX dmx_, *dmx = &dmx_;
+ int i, j, k, m, n, sst, ret = 1;
+ char *stat = NULL;
+ double obj, *prim = NULL, *dual = NULL;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_read_ipt: P = %p; invalid problem object\n", P);
+#endif
+ if (fname == NULL)
+ xerror("glp_read_ipt: fname = %d; invalid parameter\n", fname);
+ if (setjmp(dmx->jump))
+ goto done;
+ dmx->fname = fname;
+ dmx->fp = NULL;
+ dmx->count = 0;
+ dmx->c = '\n';
+ dmx->field[0] = '\0';
+ dmx->empty = dmx->nonint = 0;
+ xprintf("Reading interior-point solution from '%s'...\n", fname);
+ dmx->fp = glp_open(fname, "r");
+ if (dmx->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ goto done;
+ }
+ /* read solution line */
+ dmx_read_designator(dmx);
+ if (strcmp(dmx->field, "s") != 0)
+ dmx_error(dmx, "solution line missing or invalid");
+ dmx_read_field(dmx);
+ if (strcmp(dmx->field, "ipt") != 0)
+ dmx_error(dmx, "wrong solution designator; 'ipt' expected");
+ dmx_read_field(dmx);
+ if (!(str2int(dmx->field, &m) == 0 && m >= 0))
+ dmx_error(dmx, "number of rows missing or invalid");
+ if (m != P->m)
+ dmx_error(dmx, "number of rows mismatch");
+ dmx_read_field(dmx);
+ if (!(str2int(dmx->field, &n) == 0 && n >= 0))
+ dmx_error(dmx, "number of columns missing or invalid");
+ if (n != P->n)
+ dmx_error(dmx, "number of columns mismatch");
+ dmx_read_field(dmx);
+ if (strcmp(dmx->field, "o") == 0)
+ sst = GLP_OPT;
+ else if (strcmp(dmx->field, "i") == 0)
+ sst = GLP_INFEAS;
+ else if (strcmp(dmx->field, "n") == 0)
+ sst = GLP_NOFEAS;
+ else if (strcmp(dmx->field, "u") == 0)
+ sst = GLP_UNDEF;
+ else
+ dmx_error(dmx, "solution status missing or invalid");
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &obj) != 0)
+ dmx_error(dmx, "objective value missing or invalid");
+ dmx_end_of_line(dmx);
+ /* allocate working arrays */
+ stat = xalloc(1+m+n, sizeof(stat[0]));
+ for (k = 1; k <= m+n; k++)
+ stat[k] = '?';
+ prim = xalloc(1+m+n, sizeof(prim[0]));
+ dual = xalloc(1+m+n, sizeof(dual[0]));
+ /* read solution descriptor lines */
+ for (;;)
+ { dmx_read_designator(dmx);
+ if (strcmp(dmx->field, "i") == 0)
+ { /* row solution descriptor */
+ dmx_read_field(dmx);
+ if (str2int(dmx->field, &i) != 0)
+ dmx_error(dmx, "row number missing or invalid");
+ if (!(1 <= i && i <= m))
+ dmx_error(dmx, "row number out of range");
+ if (stat[i] != '?')
+ dmx_error(dmx, "duplicate row solution descriptor");
+ stat[i] = GLP_BS;
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &prim[i]) != 0)
+ dmx_error(dmx, "row primal value missing or invalid");
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &dual[i]) != 0)
+ dmx_error(dmx, "row dual value missing or invalid");
+ dmx_end_of_line(dmx);
+ }
+ else if (strcmp(dmx->field, "j") == 0)
+ { /* column solution descriptor */
+ dmx_read_field(dmx);
+ if (str2int(dmx->field, &j) != 0)
+ dmx_error(dmx, "column number missing or invalid");
+ if (!(1 <= j && j <= n))
+ dmx_error(dmx, "column number out of range");
+ if (stat[m+j] != '?')
+ dmx_error(dmx, "duplicate column solution descriptor");
+ stat[m+j] = GLP_BS;
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &prim[m+j]) != 0)
+ dmx_error(dmx, "column primal value missing or invalid");
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &dual[m+j]) != 0)
+ dmx_error(dmx, "column dual value missing or invalid");
+ dmx_end_of_line(dmx);
+ }
+ else if (strcmp(dmx->field, "e") == 0)
+ break;
+ else
+ dmx_error(dmx, "line designator missing or invalid");
+ dmx_end_of_line(dmx);
+ }
+ /* store solution components into problem object */
+ for (k = 1; k <= m+n; k++)
+ { if (stat[k] == '?')
+ dmx_error(dmx, "incomplete interior-point solution");
+ }
+ P->ipt_stat = sst;
+ P->ipt_obj = obj;
+ for (i = 1; i <= m; i++)
+ { P->row[i]->pval = prim[i];
+ P->row[i]->dval = dual[i];
+ }
+ for (j = 1; j <= n; j++)
+ { P->col[j]->pval = prim[m+j];
+ P->col[j]->dval = dual[m+j];
+ }
+ /* interior-point solution has been successfully read */
+ xprintf("%d lines were read\n", dmx->count);
+ ret = 0;
+done: if (dmx->fp != NULL)
+ glp_close(dmx->fp);
+ if (stat != NULL)
+ xfree(stat);
+ if (prim != NULL)
+ xfree(prim);
+ if (dual != NULL)
+ xfree(dual);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/rdmaxf.c b/test/monniaux/glpk-4.65/src/api/rdmaxf.c
new file mode 100644
index 00000000..a45405c9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/rdmaxf.c
@@ -0,0 +1,163 @@
+/* rdmaxf.c (read maximum flow problem data in DIMACS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "dimacs.h"
+#include "glpk.h"
+#include "misc.h"
+
+#define error dmx_error
+#define warning dmx_warning
+#define read_char dmx_read_char
+#define read_designator dmx_read_designator
+#define read_field dmx_read_field
+#define end_of_line dmx_end_of_line
+#define check_int dmx_check_int
+
+/***********************************************************************
+* NAME
+*
+* glp_read_maxflow - read maximum flow problem data in DIMACS format
+*
+* SYNOPSIS
+*
+* int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
+* const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_read_maxflow reads maximum flow problem data in
+* DIMACS format from a text file.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_read_maxflow(glp_graph *G, int *_s, int *_t, int a_cap,
+ const char *fname)
+{ DMX _csa, *csa = &_csa;
+ glp_arc *a;
+ int i, j, k, s, t, nv, na, ret = 0;
+ double cap;
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_read_maxflow: a_cap = %d; invalid offset\n",
+ a_cap);
+ glp_erase_graph(G, G->v_size, G->a_size);
+ if (setjmp(csa->jump))
+ { ret = 1;
+ goto done;
+ }
+ csa->fname = fname;
+ csa->fp = NULL;
+ csa->count = 0;
+ csa->c = '\n';
+ csa->field[0] = '\0';
+ csa->empty = csa->nonint = 0;
+ xprintf("Reading maximum flow problem data from '%s'...\n",
+ fname);
+ csa->fp = glp_open(fname, "r");
+ if (csa->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ longjmp(csa->jump, 1);
+ }
+ /* read problem line */
+ read_designator(csa);
+ if (strcmp(csa->field, "p") != 0)
+ error(csa, "problem line missing or invalid");
+ read_field(csa);
+ if (strcmp(csa->field, "max") != 0)
+ error(csa, "wrong problem designator; 'max' expected");
+ read_field(csa);
+ if (!(str2int(csa->field, &nv) == 0 && nv >= 2))
+ error(csa, "number of nodes missing or invalid");
+ read_field(csa);
+ if (!(str2int(csa->field, &na) == 0 && na >= 0))
+ error(csa, "number of arcs missing or invalid");
+ xprintf("Flow network has %d node%s and %d arc%s\n",
+ nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
+ if (nv > 0) glp_add_vertices(G, nv);
+ end_of_line(csa);
+ /* read node descriptor lines */
+ s = t = 0;
+ for (;;)
+ { read_designator(csa);
+ if (strcmp(csa->field, "n") != 0) break;
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "node number missing or invalid");
+ if (!(1 <= i && i <= nv))
+ error(csa, "node number %d out of range", i);
+ read_field(csa);
+ if (strcmp(csa->field, "s") == 0)
+ { if (s > 0)
+ error(csa, "only one source node allowed");
+ s = i;
+ }
+ else if (strcmp(csa->field, "t") == 0)
+ { if (t > 0)
+ error(csa, "only one sink node allowed");
+ t = i;
+ }
+ else
+ error(csa, "wrong node designator; 's' or 't' expected");
+ if (s > 0 && s == t)
+ error(csa, "source and sink nodes must be distinct");
+ end_of_line(csa);
+ }
+ if (s == 0)
+ error(csa, "source node descriptor missing\n");
+ if (t == 0)
+ error(csa, "sink node descriptor missing\n");
+ if (_s != NULL) *_s = s;
+ if (_t != NULL) *_t = t;
+ /* read arc descriptor lines */
+ for (k = 1; k <= na; k++)
+ { if (k > 1) read_designator(csa);
+ if (strcmp(csa->field, "a") != 0)
+ error(csa, "wrong line designator; 'a' expected");
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "starting node number missing or invalid");
+ if (!(1 <= i && i <= nv))
+ error(csa, "starting node number %d out of range", i);
+ read_field(csa);
+ if (str2int(csa->field, &j) != 0)
+ error(csa, "ending node number missing or invalid");
+ if (!(1 <= j && j <= nv))
+ error(csa, "ending node number %d out of range", j);
+ read_field(csa);
+ if (!(str2num(csa->field, &cap) == 0 && cap >= 0.0))
+ error(csa, "arc capacity missing or invalid");
+ check_int(csa, cap);
+ a = glp_add_arc(G, i, j);
+ if (a_cap >= 0)
+ memcpy((char *)a->data + a_cap, &cap, sizeof(double));
+ end_of_line(csa);
+ }
+ xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+ if (csa->fp != NULL) glp_close(csa->fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/rdmcf.c b/test/monniaux/glpk-4.65/src/api/rdmcf.c
new file mode 100644
index 00000000..bab1ec79
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/rdmcf.c
@@ -0,0 +1,186 @@
+/* rdmcf.c (read min-cost flow problem data in DIMACS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "dimacs.h"
+#include "glpk.h"
+#include "misc.h"
+
+#define error dmx_error
+#define warning dmx_warning
+#define read_char dmx_read_char
+#define read_designator dmx_read_designator
+#define read_field dmx_read_field
+#define end_of_line dmx_end_of_line
+#define check_int dmx_check_int
+
+/***********************************************************************
+* NAME
+*
+* glp_read_mincost - read min-cost flow problem data in DIMACS format
+*
+* SYNOPSIS
+*
+* int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+* int a_cost, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_read_mincost reads minimum cost flow problem data in
+* DIMACS format from a text file.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+ int a_cost, const char *fname)
+{ DMX _csa, *csa = &_csa;
+ glp_vertex *v;
+ glp_arc *a;
+ int i, j, k, nv, na, ret = 0;
+ double rhs, low, cap, cost;
+ char *flag = NULL;
+ if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+ xerror("glp_read_mincost: v_rhs = %d; invalid offset\n",
+ v_rhs);
+ if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+ xerror("glp_read_mincost: a_low = %d; invalid offset\n",
+ a_low);
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_read_mincost: a_cap = %d; invalid offset\n",
+ a_cap);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_read_mincost: a_cost = %d; invalid offset\n",
+ a_cost);
+ glp_erase_graph(G, G->v_size, G->a_size);
+ if (setjmp(csa->jump))
+ { ret = 1;
+ goto done;
+ }
+ csa->fname = fname;
+ csa->fp = NULL;
+ csa->count = 0;
+ csa->c = '\n';
+ csa->field[0] = '\0';
+ csa->empty = csa->nonint = 0;
+ xprintf("Reading min-cost flow problem data from '%s'...\n",
+ fname);
+ csa->fp = glp_open(fname, "r");
+ if (csa->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ longjmp(csa->jump, 1);
+ }
+ /* read problem line */
+ read_designator(csa);
+ if (strcmp(csa->field, "p") != 0)
+ error(csa, "problem line missing or invalid");
+ read_field(csa);
+ if (strcmp(csa->field, "min") != 0)
+ error(csa, "wrong problem designator; 'min' expected");
+ read_field(csa);
+ if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
+ error(csa, "number of nodes missing or invalid");
+ read_field(csa);
+ if (!(str2int(csa->field, &na) == 0 && na >= 0))
+ error(csa, "number of arcs missing or invalid");
+ xprintf("Flow network has %d node%s and %d arc%s\n",
+ nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
+ if (nv > 0) glp_add_vertices(G, nv);
+ end_of_line(csa);
+ /* read node descriptor lines */
+ flag = xcalloc(1+nv, sizeof(char));
+ memset(&flag[1], 0, nv * sizeof(char));
+ if (v_rhs >= 0)
+ { rhs = 0.0;
+ for (i = 1; i <= nv; i++)
+ { v = G->v[i];
+ memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
+ }
+ }
+ for (;;)
+ { read_designator(csa);
+ if (strcmp(csa->field, "n") != 0) break;
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "node number missing or invalid");
+ if (!(1 <= i && i <= nv))
+ error(csa, "node number %d out of range", i);
+ if (flag[i])
+ error(csa, "duplicate descriptor of node %d", i);
+ read_field(csa);
+ if (str2num(csa->field, &rhs) != 0)
+ error(csa, "node supply/demand missing or invalid");
+ check_int(csa, rhs);
+ if (v_rhs >= 0)
+ { v = G->v[i];
+ memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
+ }
+ flag[i] = 1;
+ end_of_line(csa);
+ }
+ xfree(flag), flag = NULL;
+ /* read arc descriptor lines */
+ for (k = 1; k <= na; k++)
+ { if (k > 1) read_designator(csa);
+ if (strcmp(csa->field, "a") != 0)
+ error(csa, "wrong line designator; 'a' expected");
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "starting node number missing or invalid");
+ if (!(1 <= i && i <= nv))
+ error(csa, "starting node number %d out of range", i);
+ read_field(csa);
+ if (str2int(csa->field, &j) != 0)
+ error(csa, "ending node number missing or invalid");
+ if (!(1 <= j && j <= nv))
+ error(csa, "ending node number %d out of range", j);
+ read_field(csa);
+ if (!(str2num(csa->field, &low) == 0 && low >= 0.0))
+ error(csa, "lower bound of arc flow missing or invalid");
+ check_int(csa, low);
+ read_field(csa);
+ if (!(str2num(csa->field, &cap) == 0 && cap >= low))
+ error(csa, "upper bound of arc flow missing or invalid");
+ check_int(csa, cap);
+ read_field(csa);
+ if (str2num(csa->field, &cost) != 0)
+ error(csa, "per-unit cost of arc flow missing or invalid");
+ check_int(csa, cost);
+ a = glp_add_arc(G, i, j);
+ if (a_low >= 0)
+ memcpy((char *)a->data + a_low, &low, sizeof(double));
+ if (a_cap >= 0)
+ memcpy((char *)a->data + a_cap, &cap, sizeof(double));
+ if (a_cost >= 0)
+ memcpy((char *)a->data + a_cost, &cost, sizeof(double));
+ end_of_line(csa);
+ }
+ xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+ if (csa->fp != NULL) glp_close(csa->fp);
+ if (flag != NULL) xfree(flag);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/rdmip.c b/test/monniaux/glpk-4.65/src/api/rdmip.c
new file mode 100644
index 00000000..7aec26b3
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/rdmip.c
@@ -0,0 +1,172 @@
+/* rdmip.c (read MIP solution in GLPK format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "dimacs.h"
+#include "env.h"
+#include "misc.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_read_mip - read MIP solution in GLPK format
+*
+* SYNOPSIS
+*
+* int glp_read_mip(glp_prob *P, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_read_mip reads MIP solution from a text file in GLPK
+* format.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_read_mip(glp_prob *P, const char *fname)
+{ DMX dmx_, *dmx = &dmx_;
+ int i, j, k, m, n, sst, ret = 1;
+ char *stat = NULL;
+ double obj, *prim = NULL;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_read_mip: P = %p; invalid problem object\n", P);
+#endif
+ if (fname == NULL)
+ xerror("glp_read_mip: fname = %d; invalid parameter\n", fname);
+ if (setjmp(dmx->jump))
+ goto done;
+ dmx->fname = fname;
+ dmx->fp = NULL;
+ dmx->count = 0;
+ dmx->c = '\n';
+ dmx->field[0] = '\0';
+ dmx->empty = dmx->nonint = 0;
+ xprintf("Reading MIP solution from '%s'...\n", fname);
+ dmx->fp = glp_open(fname, "r");
+ if (dmx->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ goto done;
+ }
+ /* read solution line */
+ dmx_read_designator(dmx);
+ if (strcmp(dmx->field, "s") != 0)
+ dmx_error(dmx, "solution line missing or invalid");
+ dmx_read_field(dmx);
+ if (strcmp(dmx->field, "mip") != 0)
+ dmx_error(dmx, "wrong solution designator; 'mip' expected");
+ dmx_read_field(dmx);
+ if (!(str2int(dmx->field, &m) == 0 && m >= 0))
+ dmx_error(dmx, "number of rows missing or invalid");
+ if (m != P->m)
+ dmx_error(dmx, "number of rows mismatch");
+ dmx_read_field(dmx);
+ if (!(str2int(dmx->field, &n) == 0 && n >= 0))
+ dmx_error(dmx, "number of columns missing or invalid");
+ if (n != P->n)
+ dmx_error(dmx, "number of columns mismatch");
+ dmx_read_field(dmx);
+ if (strcmp(dmx->field, "o") == 0)
+ sst = GLP_OPT;
+ else if (strcmp(dmx->field, "f") == 0)
+ sst = GLP_FEAS;
+ else if (strcmp(dmx->field, "n") == 0)
+ sst = GLP_NOFEAS;
+ else if (strcmp(dmx->field, "u") == 0)
+ sst = GLP_UNDEF;
+ else
+ dmx_error(dmx, "solution status missing or invalid");
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &obj) != 0)
+ dmx_error(dmx, "objective value missing or invalid");
+ dmx_end_of_line(dmx);
+ /* allocate working arrays */
+ stat = xalloc(1+m+n, sizeof(stat[0]));
+ for (k = 1; k <= m+n; k++)
+ stat[k] = '?';
+ prim = xalloc(1+m+n, sizeof(prim[0]));
+ /* read solution descriptor lines */
+ for (;;)
+ { dmx_read_designator(dmx);
+ if (strcmp(dmx->field, "i") == 0)
+ { /* row solution descriptor */
+ dmx_read_field(dmx);
+ if (str2int(dmx->field, &i) != 0)
+ dmx_error(dmx, "row number missing or invalid");
+ if (!(1 <= i && i <= m))
+ dmx_error(dmx, "row number out of range");
+ if (stat[i] != '?')
+ dmx_error(dmx, "duplicate row solution descriptor");
+ stat[i] = GLP_BS;
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &prim[i]) != 0)
+ dmx_error(dmx, "row value missing or invalid");
+ dmx_end_of_line(dmx);
+ }
+ else if (strcmp(dmx->field, "j") == 0)
+ { /* column solution descriptor */
+ dmx_read_field(dmx);
+ if (str2int(dmx->field, &j) != 0)
+ dmx_error(dmx, "column number missing or invalid");
+ if (!(1 <= j && j <= n))
+ dmx_error(dmx, "column number out of range");
+ if (stat[m+j] != '?')
+ dmx_error(dmx, "duplicate column solution descriptor");
+ stat[m+j] = GLP_BS;
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &prim[m+j]) != 0)
+ dmx_error(dmx, "column value missing or invalid");
+ dmx_end_of_line(dmx);
+ }
+ else if (strcmp(dmx->field, "e") == 0)
+ break;
+ else
+ dmx_error(dmx, "line designator missing or invalid");
+ dmx_end_of_line(dmx);
+ }
+ /* store solution components into problem object */
+ for (k = 1; k <= m+n; k++)
+ { if (stat[k] == '?')
+ dmx_error(dmx, "incomplete MIP solution");
+ }
+ P->mip_stat = sst;
+ P->mip_obj = obj;
+ for (i = 1; i <= m; i++)
+ P->row[i]->mipx = prim[i];
+ for (j = 1; j <= n; j++)
+ P->col[j]->mipx = prim[m+j];
+ /* MIP solution has been successfully read */
+ xprintf("%d lines were read\n", dmx->count);
+ ret = 0;
+done: if (dmx->fp != NULL)
+ glp_close(dmx->fp);
+ if (stat != NULL)
+ xfree(stat);
+ if (prim != NULL)
+ xfree(prim);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/rdprob.c b/test/monniaux/glpk-4.65/src/api/rdprob.c
new file mode 100644
index 00000000..1ad544a5
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/rdprob.c
@@ -0,0 +1,377 @@
+/* rdprob.c (read problem data in GLPK format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "dimacs.h"
+#include "misc.h"
+#include "prob.h"
+
+#define xfprintf glp_format
+#define error dmx_error
+#define warning dmx_warning
+#define read_char dmx_read_char
+#define read_designator dmx_read_designator
+#define read_field dmx_read_field
+#define end_of_line dmx_end_of_line
+#define check_int dmx_check_int
+
+/***********************************************************************
+* NAME
+*
+* glp_read_prob - read problem data in GLPK format
+*
+* SYNOPSIS
+*
+* int glp_read_prob(glp_prob *P, int flags, const char *fname);
+*
+* The routine glp_read_prob reads problem data in GLPK LP/MIP format
+* from a text file.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_read_prob(glp_prob *P, int flags, const char *fname)
+{ DMX _csa, *csa = &_csa;
+ int mip, m, n, nnz, ne, i, j, k, type, kind, ret, *ln = NULL,
+ *ia = NULL, *ja = NULL;
+ double lb, ub, temp, *ar = NULL;
+ char *rf = NULL, *cf = NULL;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_read_prob: P = %p; invalid problem object\n",
+ P);
+#endif
+ if (flags != 0)
+ xerror("glp_read_prob: flags = %d; invalid parameter\n",
+ flags);
+ if (fname == NULL)
+ xerror("glp_read_prob: fname = %d; invalid parameter\n",
+ fname);
+ glp_erase_prob(P);
+ if (setjmp(csa->jump))
+ { ret = 1;
+ goto done;
+ }
+ csa->fname = fname;
+ csa->fp = NULL;
+ csa->count = 0;
+ csa->c = '\n';
+ csa->field[0] = '\0';
+ csa->empty = csa->nonint = 0;
+ xprintf("Reading problem data from '%s'...\n", fname);
+ csa->fp = glp_open(fname, "r");
+ if (csa->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ longjmp(csa->jump, 1);
+ }
+ /* read problem line */
+ read_designator(csa);
+ if (strcmp(csa->field, "p") != 0)
+ error(csa, "problem line missing or invalid");
+ read_field(csa);
+ if (strcmp(csa->field, "lp") == 0)
+ mip = 0;
+ else if (strcmp(csa->field, "mip") == 0)
+ mip = 1;
+ else
+ error(csa, "wrong problem designator; 'lp' or 'mip' expected");
+ read_field(csa);
+ if (strcmp(csa->field, "min") == 0)
+ glp_set_obj_dir(P, GLP_MIN);
+ else if (strcmp(csa->field, "max") == 0)
+ glp_set_obj_dir(P, GLP_MAX);
+ else
+ error(csa, "objective sense missing or invalid");
+ read_field(csa);
+ if (!(str2int(csa->field, &m) == 0 && m >= 0))
+ error(csa, "number of rows missing or invalid");
+ read_field(csa);
+ if (!(str2int(csa->field, &n) == 0 && n >= 0))
+ error(csa, "number of columns missing or invalid");
+ read_field(csa);
+ if (!(str2int(csa->field, &nnz) == 0 && nnz >= 0))
+ error(csa, "number of constraint coefficients missing or inval"
+ "id");
+ if (m > 0)
+ { glp_add_rows(P, m);
+ for (i = 1; i <= m; i++)
+ glp_set_row_bnds(P, i, GLP_FX, 0.0, 0.0);
+ }
+ if (n > 0)
+ { glp_add_cols(P, n);
+ for (j = 1; j <= n; j++)
+ { if (!mip)
+ glp_set_col_bnds(P, j, GLP_LO, 0.0, 0.0);
+ else
+ glp_set_col_kind(P, j, GLP_BV);
+ }
+ }
+ end_of_line(csa);
+ /* allocate working arrays */
+ rf = xcalloc(1+m, sizeof(char));
+ memset(rf, 0, 1+m);
+ cf = xcalloc(1+n, sizeof(char));
+ memset(cf, 0, 1+n);
+ ln = xcalloc(1+nnz, sizeof(int));
+ ia = xcalloc(1+nnz, sizeof(int));
+ ja = xcalloc(1+nnz, sizeof(int));
+ ar = xcalloc(1+nnz, sizeof(double));
+ /* read descriptor lines */
+ ne = 0;
+ for (;;)
+ { read_designator(csa);
+ if (strcmp(csa->field, "i") == 0)
+ { /* row descriptor */
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "row number missing or invalid");
+ if (!(1 <= i && i <= m))
+ error(csa, "row number out of range");
+ read_field(csa);
+ if (strcmp(csa->field, "f") == 0)
+ type = GLP_FR;
+ else if (strcmp(csa->field, "l") == 0)
+ type = GLP_LO;
+ else if (strcmp(csa->field, "u") == 0)
+ type = GLP_UP;
+ else if (strcmp(csa->field, "d") == 0)
+ type = GLP_DB;
+ else if (strcmp(csa->field, "s") == 0)
+ type = GLP_FX;
+ else
+ error(csa, "row type missing or invalid");
+ if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+ { read_field(csa);
+ if (str2num(csa->field, &lb) != 0)
+ error(csa, "row lower bound/fixed value missing or in"
+ "valid");
+ }
+ else
+ lb = 0.0;
+ if (type == GLP_UP || type == GLP_DB)
+ { read_field(csa);
+ if (str2num(csa->field, &ub) != 0)
+ error(csa, "row upper bound missing or invalid");
+ }
+ else
+ ub = 0.0;
+ if (rf[i] & 0x01)
+ error(csa, "duplicate row descriptor");
+ glp_set_row_bnds(P, i, type, lb, ub), rf[i] |= 0x01;
+ }
+ else if (strcmp(csa->field, "j") == 0)
+ { /* column descriptor */
+ read_field(csa);
+ if (str2int(csa->field, &j) != 0)
+ error(csa, "column number missing or invalid");
+ if (!(1 <= j && j <= n))
+ error(csa, "column number out of range");
+ if (!mip)
+ kind = GLP_CV;
+ else
+ { read_field(csa);
+ if (strcmp(csa->field, "c") == 0)
+ kind = GLP_CV;
+ else if (strcmp(csa->field, "i") == 0)
+ kind = GLP_IV;
+ else if (strcmp(csa->field, "b") == 0)
+ { kind = GLP_IV;
+ type = GLP_DB, lb = 0.0, ub = 1.0;
+ goto skip;
+ }
+ else
+ error(csa, "column kind missing or invalid");
+ }
+ read_field(csa);
+ if (strcmp(csa->field, "f") == 0)
+ type = GLP_FR;
+ else if (strcmp(csa->field, "l") == 0)
+ type = GLP_LO;
+ else if (strcmp(csa->field, "u") == 0)
+ type = GLP_UP;
+ else if (strcmp(csa->field, "d") == 0)
+ type = GLP_DB;
+ else if (strcmp(csa->field, "s") == 0)
+ type = GLP_FX;
+ else
+ error(csa, "column type missing or invalid");
+ if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+ { read_field(csa);
+ if (str2num(csa->field, &lb) != 0)
+ error(csa, "column lower bound/fixed value missing or"
+ " invalid");
+ }
+ else
+ lb = 0.0;
+ if (type == GLP_UP || type == GLP_DB)
+ { read_field(csa);
+ if (str2num(csa->field, &ub) != 0)
+ error(csa, "column upper bound missing or invalid");
+ }
+ else
+ ub = 0.0;
+skip: if (cf[j] & 0x01)
+ error(csa, "duplicate column descriptor");
+ glp_set_col_kind(P, j, kind);
+ glp_set_col_bnds(P, j, type, lb, ub), cf[j] |= 0x01;
+ }
+ else if (strcmp(csa->field, "a") == 0)
+ { /* coefficient descriptor */
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "row number missing or invalid");
+ if (!(0 <= i && i <= m))
+ error(csa, "row number out of range");
+ read_field(csa);
+ if (str2int(csa->field, &j) != 0)
+ error(csa, "column number missing or invalid");
+ if (!((i == 0 ? 0 : 1) <= j && j <= n))
+ error(csa, "column number out of range");
+ read_field(csa);
+ if (i == 0)
+ { if (str2num(csa->field, &temp) != 0)
+ error(csa, "objective %s missing or invalid",
+ j == 0 ? "constant term" : "coefficient");
+ if (cf[j] & 0x10)
+ error(csa, "duplicate objective %s",
+ j == 0 ? "constant term" : "coefficient");
+ glp_set_obj_coef(P, j, temp), cf[j] |= 0x10;
+ }
+ else
+ { if (str2num(csa->field, &temp) != 0)
+ error(csa, "constraint coefficient missing or invalid"
+ );
+ if (ne == nnz)
+ error(csa, "too many constraint coefficient descripto"
+ "rs");
+ ln[++ne] = csa->count;
+ ia[ne] = i, ja[ne] = j, ar[ne] = temp;
+ }
+ }
+ else if (strcmp(csa->field, "n") == 0)
+ { /* symbolic name descriptor */
+ read_field(csa);
+ if (strcmp(csa->field, "p") == 0)
+ { /* problem name */
+ read_field(csa);
+ if (P->name != NULL)
+ error(csa, "duplicate problem name");
+ glp_set_prob_name(P, csa->field);
+ }
+ else if (strcmp(csa->field, "z") == 0)
+ { /* objective name */
+ read_field(csa);
+ if (P->obj != NULL)
+ error(csa, "duplicate objective name");
+ glp_set_obj_name(P, csa->field);
+ }
+ else if (strcmp(csa->field, "i") == 0)
+ { /* row name */
+ read_field(csa);
+ if (str2int(csa->field, &i) != 0)
+ error(csa, "row number missing or invalid");
+ if (!(1 <= i && i <= m))
+ error(csa, "row number out of range");
+ read_field(csa);
+ if (P->row[i]->name != NULL)
+ error(csa, "duplicate row name");
+ glp_set_row_name(P, i, csa->field);
+ }
+ else if (strcmp(csa->field, "j") == 0)
+ { /* column name */
+ read_field(csa);
+ if (str2int(csa->field, &j) != 0)
+ error(csa, "column number missing or invalid");
+ if (!(1 <= j && j <= n))
+ error(csa, "column number out of range");
+ read_field(csa);
+ if (P->col[j]->name != NULL)
+ error(csa, "duplicate column name");
+ glp_set_col_name(P, j, csa->field);
+ }
+ else
+ error(csa, "object designator missing or invalid");
+ }
+ else if (strcmp(csa->field, "e") == 0)
+ break;
+ else
+ error(csa, "line designator missing or invalid");
+ end_of_line(csa);
+ }
+ if (ne < nnz)
+ error(csa, "too few constraint coefficient descriptors");
+ xassert(ne == nnz);
+ k = glp_check_dup(m, n, ne, ia, ja);
+ xassert(0 <= k && k <= nnz);
+ if (k > 0)
+ { csa->count = ln[k];
+ error(csa, "duplicate constraint coefficient");
+ }
+ glp_load_matrix(P, ne, ia, ja, ar);
+ /* print some statistics */
+ if (P->name != NULL)
+ xprintf("Problem: %s\n", P->name);
+ if (P->obj != NULL)
+ xprintf("Objective: %s\n", P->obj);
+ xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+ m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ?
+ "" : "s");
+ if (glp_get_num_int(P) > 0)
+ { int ni = glp_get_num_int(P);
+ int nb = glp_get_num_bin(P);
+ if (ni == 1)
+ { if (nb == 0)
+ xprintf("One variable is integer\n");
+ else
+ xprintf("One variable is binary\n");
+ }
+ else
+ { xprintf("%d integer variables, ", ni);
+ if (nb == 0)
+ xprintf("none");
+ else if (nb == 1)
+ xprintf("one");
+ else if (nb == ni)
+ xprintf("all");
+ else
+ xprintf("%d", nb);
+ xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
+ }
+ }
+ xprintf("%d lines were read\n", csa->count);
+ /* problem data has been successfully read */
+ glp_sort_matrix(P);
+ ret = 0;
+done: if (csa->fp != NULL) glp_close(csa->fp);
+ if (rf != NULL) xfree(rf);
+ if (cf != NULL) xfree(cf);
+ if (ln != NULL) xfree(ln);
+ if (ia != NULL) xfree(ia);
+ if (ja != NULL) xfree(ja);
+ if (ar != NULL) xfree(ar);
+ if (ret) glp_erase_prob(P);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/rdsol.c b/test/monniaux/glpk-4.65/src/api/rdsol.c
new file mode 100644
index 00000000..d85a2562
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/rdsol.c
@@ -0,0 +1,225 @@
+/* rdsol.c (read basic solution in GLPK format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "dimacs.h"
+#include "env.h"
+#include "misc.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_read_sol - read basic solution in GLPK format
+*
+* SYNOPSIS
+*
+* int glp_read_sol(glp_prob *P, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_read_sol reads basic solution from a text file in
+* GLPK format.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_read_sol(glp_prob *P, const char *fname)
+{ DMX dmx_, *dmx = &dmx_;
+ int i, j, k, m, n, pst, dst, ret = 1;
+ char *stat = NULL;
+ double obj, *prim = NULL, *dual = NULL;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_read_sol: P = %p; invalid problem object\n", P);
+#endif
+ if (fname == NULL)
+ xerror("glp_read_sol: fname = %d; invalid parameter\n", fname);
+ if (setjmp(dmx->jump))
+ goto done;
+ dmx->fname = fname;
+ dmx->fp = NULL;
+ dmx->count = 0;
+ dmx->c = '\n';
+ dmx->field[0] = '\0';
+ dmx->empty = dmx->nonint = 0;
+ xprintf("Reading basic solution from '%s'...\n", fname);
+ dmx->fp = glp_open(fname, "r");
+ if (dmx->fp == NULL)
+ { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg());
+ goto done;
+ }
+ /* read solution line */
+ dmx_read_designator(dmx);
+ if (strcmp(dmx->field, "s") != 0)
+ dmx_error(dmx, "solution line missing or invalid");
+ dmx_read_field(dmx);
+ if (strcmp(dmx->field, "bas") != 0)
+ dmx_error(dmx, "wrong solution designator; 'bas' expected");
+ dmx_read_field(dmx);
+ if (!(str2int(dmx->field, &m) == 0 && m >= 0))
+ dmx_error(dmx, "number of rows missing or invalid");
+ if (m != P->m)
+ dmx_error(dmx, "number of rows mismatch");
+ dmx_read_field(dmx);
+ if (!(str2int(dmx->field, &n) == 0 && n >= 0))
+ dmx_error(dmx, "number of columns missing or invalid");
+ if (n != P->n)
+ dmx_error(dmx, "number of columns mismatch");
+ dmx_read_field(dmx);
+ if (strcmp(dmx->field, "u") == 0)
+ pst = GLP_UNDEF;
+ else if (strcmp(dmx->field, "f") == 0)
+ pst = GLP_FEAS;
+ else if (strcmp(dmx->field, "i") == 0)
+ pst = GLP_INFEAS;
+ else if (strcmp(dmx->field, "n") == 0)
+ pst = GLP_NOFEAS;
+ else
+ dmx_error(dmx, "primal solution status missing or invalid");
+ dmx_read_field(dmx);
+ if (strcmp(dmx->field, "u") == 0)
+ dst = GLP_UNDEF;
+ else if (strcmp(dmx->field, "f") == 0)
+ dst = GLP_FEAS;
+ else if (strcmp(dmx->field, "i") == 0)
+ dst = GLP_INFEAS;
+ else if (strcmp(dmx->field, "n") == 0)
+ dst = GLP_NOFEAS;
+ else
+ dmx_error(dmx, "dual solution status missing or invalid");
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &obj) != 0)
+ dmx_error(dmx, "objective value missing or invalid");
+ dmx_end_of_line(dmx);
+ /* allocate working arrays */
+ stat = xalloc(1+m+n, sizeof(stat[0]));
+ for (k = 1; k <= m+n; k++)
+ stat[k] = '?';
+ prim = xalloc(1+m+n, sizeof(prim[0]));
+ dual = xalloc(1+m+n, sizeof(dual[0]));
+ /* read solution descriptor lines */
+ for (;;)
+ { dmx_read_designator(dmx);
+ if (strcmp(dmx->field, "i") == 0)
+ { /* row solution descriptor */
+ dmx_read_field(dmx);
+ if (str2int(dmx->field, &i) != 0)
+ dmx_error(dmx, "row number missing or invalid");
+ if (!(1 <= i && i <= m))
+ dmx_error(dmx, "row number out of range");
+ if (stat[i] != '?')
+ dmx_error(dmx, "duplicate row solution descriptor");
+ dmx_read_field(dmx);
+ if (strcmp(dmx->field, "b") == 0)
+ stat[i] = GLP_BS;
+ else if (strcmp(dmx->field, "l") == 0)
+ stat[i] = GLP_NL;
+ else if (strcmp(dmx->field, "u") == 0)
+ stat[i] = GLP_NU;
+ else if (strcmp(dmx->field, "f") == 0)
+ stat[i] = GLP_NF;
+ else if (strcmp(dmx->field, "s") == 0)
+ stat[i] = GLP_NS;
+ else
+ dmx_error(dmx, "row status missing or invalid");
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &prim[i]) != 0)
+ dmx_error(dmx, "row primal value missing or invalid");
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &dual[i]) != 0)
+ dmx_error(dmx, "row dual value missing or invalid");
+ dmx_end_of_line(dmx);
+ }
+ else if (strcmp(dmx->field, "j") == 0)
+ { /* column solution descriptor */
+ dmx_read_field(dmx);
+ if (str2int(dmx->field, &j) != 0)
+ dmx_error(dmx, "column number missing or invalid");
+ if (!(1 <= j && j <= n))
+ dmx_error(dmx, "column number out of range");
+ if (stat[m+j] != '?')
+ dmx_error(dmx, "duplicate column solution descriptor");
+ dmx_read_field(dmx);
+ if (strcmp(dmx->field, "b") == 0)
+ stat[m+j] = GLP_BS;
+ else if (strcmp(dmx->field, "l") == 0)
+ stat[m+j] = GLP_NL;
+ else if (strcmp(dmx->field, "u") == 0)
+ stat[m+j] = GLP_NU;
+ else if (strcmp(dmx->field, "f") == 0)
+ stat[m+j] = GLP_NF;
+ else if (strcmp(dmx->field, "s") == 0)
+ stat[m+j] = GLP_NS;
+ else
+ dmx_error(dmx, "column status missing or invalid");
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &prim[m+j]) != 0)
+ dmx_error(dmx, "column primal value missing or invalid");
+ dmx_read_field(dmx);
+ if (str2num(dmx->field, &dual[m+j]) != 0)
+ dmx_error(dmx, "column dual value missing or invalid");
+ dmx_end_of_line(dmx);
+ }
+ else if (strcmp(dmx->field, "e") == 0)
+ break;
+ else
+ dmx_error(dmx, "line designator missing or invalid");
+ dmx_end_of_line(dmx);
+ }
+ /* store solution components into problem object */
+ for (k = 1; k <= m+n; k++)
+ { if (stat[k] == '?')
+ dmx_error(dmx, "incomplete basic solution");
+ }
+ P->pbs_stat = pst;
+ P->dbs_stat = dst;
+ P->obj_val = obj;
+ P->it_cnt = 0;
+ P->some = 0;
+ for (i = 1; i <= m; i++)
+ { glp_set_row_stat(P, i, stat[i]);
+ P->row[i]->prim = prim[i];
+ P->row[i]->dual = dual[i];
+ }
+ for (j = 1; j <= n; j++)
+ { glp_set_col_stat(P, j, stat[m+j]);
+ P->col[j]->prim = prim[m+j];
+ P->col[j]->dual = dual[m+j];
+ }
+ /* basic solution has been successfully read */
+ xprintf("%d lines were read\n", dmx->count);
+ ret = 0;
+done: if (dmx->fp != NULL)
+ glp_close(dmx->fp);
+ if (stat != NULL)
+ xfree(stat);
+ if (prim != NULL)
+ xfree(prim);
+ if (dual != NULL)
+ xfree(dual);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/rmfgen.c b/test/monniaux/glpk-4.65/src/api/rmfgen.c
new file mode 100644
index 00000000..a1ba27bb
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/rmfgen.c
@@ -0,0 +1,368 @@
+/* rmfgen.c (Goldfarb's maximum flow problem generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* This code is a modified version of the program RMFGEN, a maxflow
+* problem generator developed by D.Goldfarb and M.Grigoriadis, and
+* originally implemented by Tamas Badics <badics@rutcor.rutgers.edu>.
+* The original code is publically available on the DIMACS ftp site at:
+* <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf>.
+*
+* All changes concern only the program interface, so this modified
+* version produces exactly the same instances as the original version.
+*
+* Changes were made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+#include "rng.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_rmfgen - Goldfarb's maximum flow problem generator
+*
+* SYNOPSIS
+*
+* int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
+* const int parm[1+5]);
+*
+* DESCRIPTION
+*
+* The routine glp_rmfgen is a maximum flow problem generator developed
+* by D.Goldfarb and M.Grigoriadis.
+*
+* The parameter G specifies the graph object, to which the generated
+* problem data have to be stored. Note that on entry the graph object
+* is erased with the routine glp_erase_graph.
+*
+* The pointer s specifies a location, to which the routine stores the
+* source node number. If s is NULL, the node number is not stored.
+*
+* The pointer t specifies a location, to which the routine stores the
+* sink node number. If t is NULL, the node number is not stored.
+*
+* The parameter a_cap specifies an offset of the field of type double
+* in the arc data block, to which the routine stores the arc capacity.
+* If a_cap < 0, the capacity is not stored.
+*
+* The array parm contains description of the network to be generated:
+*
+* parm[0] not used
+* parm[1] (seed) random number seed (a positive integer)
+* parm[2] (a) frame size
+* parm[3] (b) depth
+* parm[4] (c1) minimal arc capacity
+* parm[5] (c2) maximal arc capacity
+*
+* RETURNS
+*
+* If the instance was successfully generated, the routine glp_netgen
+* returns zero; otherwise, if specified parameters are inconsistent,
+* the routine returns a non-zero error code.
+*
+* COMMENTS
+*
+* The generated network is as follows. It has b pieces of frames of
+* size a * a. (So alltogether the number of vertices is a * a * b)
+*
+* In each frame all the vertices are connected with their neighbours
+* (forth and back). In addition the vertices of a frame are connected
+* one to one with the vertices of next frame using a random permutation
+* of those vertices.
+*
+* The source is the lower left vertex of the first frame, the sink is
+* the upper right vertex of the b'th frame.
+*
+* t
+* +-------+
+* | .|
+* | . |
+* / | / |
+* +-------+/ -+ b
+* | | |/.
+* a | -v- |/
+* | | |/
+* +-------+ 1
+* s a
+*
+* The capacities are randomly chosen integers from the range of [c1,c2]
+* in the case of interconnecting edges, and c2 * a * a for the in-frame
+* edges.
+*
+* REFERENCES
+*
+* D.Goldfarb and M.D.Grigoriadis, "A computational comparison of the
+* Dinic and network simplex methods for maximum flow." Annals of Op.
+* Res. 13 (1988), pp. 83-123.
+*
+* U.Derigs and W.Meier, "Implementing Goldberg's max-flow algorithm:
+* A computational investigation." Zeitschrift fuer Operations Research
+* 33 (1989), pp. 383-403. */
+
+typedef struct VERTEX
+{ struct EDGE **edgelist;
+ /* Pointer to the list of pointers to the adjacent edges.
+ (No matter that to or from edges) */
+ struct EDGE **current;
+ /* Pointer to the current edge */
+ int degree;
+ /* Number of adjacent edges (both direction) */
+ int index;
+} vertex;
+
+typedef struct EDGE
+{ int from;
+ int to;
+ int cap;
+ /* Capacity */
+} edge;
+
+typedef struct NETWORK
+{ struct NETWORK *next, *prev;
+ int vertnum;
+ int edgenum;
+ vertex *verts;
+ /* Vertex array[1..vertnum] */
+ edge *edges;
+ /* Edge array[1..edgenum] */
+ int source;
+ /* Pointer to the source */
+ int sink;
+ /* Pointer to the sink */
+} network;
+
+struct csa
+{ /* common storage area */
+ glp_graph *G;
+ int *s, *t, a_cap;
+ RNG *rand;
+ network *N;
+ int *Parr;
+ int A, AA, C2AA, Ec;
+};
+
+#define G (csa->G)
+#define s (csa->s)
+#define t (csa->t)
+#define a_cap (csa->a_cap)
+#define N (csa->N)
+#define Parr (csa->Parr)
+#define A (csa->A)
+#define AA (csa->AA)
+#define C2AA (csa->C2AA)
+#define Ec (csa->Ec)
+
+#undef random
+#define random(A) (int)(rng_unif_01(csa->rand) * (double)(A))
+#define RANDOM(A, B) (int)(random((B) - (A) + 1) + (A))
+#define sgn(A) (((A) > 0) ? 1 : ((A) == 0) ? 0 : -1)
+
+static void make_edge(struct csa *csa, int from, int to, int c1, int c2)
+{ Ec++;
+ N->edges[Ec].from = from;
+ N->edges[Ec].to = to;
+ N->edges[Ec].cap = RANDOM(c1, c2);
+ return;
+}
+
+static void permute(struct csa *csa)
+{ int i, j, tmp;
+ for (i = 1; i < AA; i++)
+ { j = RANDOM(i, AA);
+ tmp = Parr[i];
+ Parr[i] = Parr[j];
+ Parr[j] = tmp;
+ }
+ return;
+}
+
+static void connect(struct csa *csa, int offset, int cv, int x1, int y1)
+{ int cv1;
+ cv1 = offset + (x1 - 1) * A + y1;
+ Ec++;
+ N->edges[Ec].from = cv;
+ N->edges[Ec].to = cv1;
+ N->edges[Ec].cap = C2AA;
+ return;
+}
+
+static network *gen_rmf(struct csa *csa, int a, int b, int c1, int c2)
+{ /* generates a network with a*a*b nodes and 6a*a*b-4ab-2a*a edges
+ random_frame network:
+ Derigs & Meier, Methods & Models of OR (1989), 33:383-403 */
+ int x, y, z, offset, cv;
+ A = a;
+ AA = a * a;
+ C2AA = c2 * AA;
+ Ec = 0;
+ N = (network *)xmalloc(sizeof(network));
+ N->vertnum = AA * b;
+ N->edgenum = 5 * AA * b - 4 * A * b - AA;
+ N->edges = (edge *)xcalloc(N->edgenum + 1, sizeof(edge));
+ N->source = 1;
+ N->sink = N->vertnum;
+ Parr = (int *)xcalloc(AA + 1, sizeof(int));
+ for (x = 1; x <= AA; x++)
+ Parr[x] = x;
+ for (z = 1; z <= b; z++)
+ { offset = AA * (z - 1);
+ if (z != b)
+ permute(csa);
+ for (x = 1; x <= A; x++)
+ { for (y = 1; y <= A; y++)
+ { cv = offset + (x - 1) * A + y;
+ if (z != b)
+ make_edge(csa, cv, offset + AA + Parr[cv - offset],
+ c1, c2); /* the intermediate edges */
+ if (y < A)
+ connect(csa, offset, cv, x, y + 1);
+ if (y > 1)
+ connect(csa, offset, cv, x, y - 1);
+ if (x < A)
+ connect(csa, offset, cv, x + 1, y);
+ if (x > 1)
+ connect(csa, offset, cv, x - 1, y);
+ }
+ }
+ }
+ xfree(Parr);
+ return N;
+}
+
+static void print_max_format(struct csa *csa, network *n, char *comm[],
+ int dim)
+{ /* prints a network heading with dim lines of comments (no \n
+ needs at the ends) */
+ int i, vnum, e_num;
+ edge *e;
+ vnum = n->vertnum;
+ e_num = n->edgenum;
+ if (G == NULL)
+ { for (i = 0; i < dim; i++)
+ xprintf("c %s\n", comm[i]);
+ xprintf("p max %7d %10d\n", vnum, e_num);
+ xprintf("n %7d s\n", n->source);
+ xprintf("n %7d t\n", n->sink);
+ }
+ else
+ { glp_add_vertices(G, vnum);
+ if (s != NULL) *s = n->source;
+ if (t != NULL) *t = n->sink;
+ }
+ for (i = 1; i <= e_num; i++)
+ { e = &n->edges[i];
+ if (G == NULL)
+ xprintf("a %7d %7d %10d\n", e->from, e->to, (int)e->cap);
+ else
+ { glp_arc *a = glp_add_arc(G, e->from, e->to);
+ if (a_cap >= 0)
+ { double temp = (double)e->cap;
+ memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+ }
+ }
+ }
+ return;
+}
+
+static void gen_free_net(network *n)
+{ xfree(n->edges);
+ xfree(n);
+ return;
+}
+
+int glp_rmfgen(glp_graph *G_, int *_s, int *_t, int _a_cap,
+ const int parm[1+5])
+{ struct csa _csa, *csa = &_csa;
+ network *n;
+ char comm[10][80], *com1[10];
+ int seed, a, b, c1, c2, ret;
+ G = G_;
+ s = _s;
+ t = _t;
+ a_cap = _a_cap;
+ if (G != NULL)
+ { if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_rmfgen: a_cap = %d; invalid offset\n", a_cap);
+ }
+ seed = parm[1];
+ a = parm[2];
+ b = parm[3];
+ c1 = parm[4];
+ c2 = parm[5];
+ if (!(seed > 0 && 1 <= a && a <= 1000 && 1 <= b && b <= 1000 &&
+ 0 <= c1 && c1 <= c2 && c2 <= 1000))
+ { ret = 1;
+ goto done;
+ }
+ if (G != NULL)
+ { glp_erase_graph(G, G->v_size, G->a_size);
+ glp_set_graph_name(G, "RMFGEN");
+ }
+ csa->rand = rng_create_rand();
+ rng_init_rand(csa->rand, seed);
+ n = gen_rmf(csa, a, b, c1, c2);
+ sprintf(comm[0], "This file was generated by genrmf.");
+ sprintf(comm[1], "The parameters are: a: %d b: %d c1: %d c2: %d",
+ a, b, c1, c2);
+ com1[0] = comm[0];
+ com1[1] = comm[1];
+ print_max_format(csa, n, com1, 2);
+ gen_free_net(n);
+ rng_delete_rand(csa->rand);
+ ret = 0;
+done: return ret;
+}
+
+/**********************************************************************/
+
+#if 0
+int main(int argc, char *argv[])
+{ int seed, a, b, c1, c2, i, parm[1+5];
+ seed = 123;
+ a = b = c1 = c2 = -1;
+ for (i = 1; i < argc; i++)
+ { if (strcmp(argv[i], "-seed") == 0)
+ seed = atoi(argv[++i]);
+ else if (strcmp(argv[i], "-a") == 0)
+ a = atoi(argv[++i]);
+ else if (strcmp(argv[i], "-b") == 0)
+ b = atoi(argv[++i]);
+ else if (strcmp(argv[i], "-c1") == 0)
+ c1 = atoi(argv[++i]);
+ else if (strcmp(argv[i], "-c2") == 0)
+ c2 = atoi(argv[++i]);
+ }
+ if (a < 0 || b < 0 || c1 < 0 || c2 < 0)
+ { xprintf("Usage:\n");
+ xprintf("genrmf [-seed seed] -a frame_size -b depth\n");
+ xprintf(" -c1 cap_range1 -c2 cap_range2\n");
+ }
+ else
+ { parm[1] = seed;
+ parm[2] = a;
+ parm[3] = b;
+ parm[4] = c1;
+ parm[5] = c2;
+ glp_rmfgen(NULL, NULL, NULL, 0, parm);
+ }
+ return 0;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/strong.c b/test/monniaux/glpk-4.65/src/api/strong.c
new file mode 100644
index 00000000..9ddcacfb
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/strong.c
@@ -0,0 +1,110 @@
+/* strong.c (find all strongly connected components of graph) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+#include "mc13d.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_strong_comp - find all strongly connected components of graph
+*
+* SYNOPSIS
+*
+* int glp_strong_comp(glp_graph *G, int v_num);
+*
+* DESCRIPTION
+*
+* The routine glp_strong_comp finds all strongly connected components
+* of the specified graph.
+*
+* The parameter v_num specifies an offset of the field of type int
+* in the vertex data block, to which the routine stores the number of
+* a strongly connected component containing that vertex. If v_num < 0,
+* no component numbers are stored.
+*
+* The components are numbered in arbitrary order from 1 to nc, where
+* nc is the total number of components found, 0 <= nc <= |V|. However,
+* the component numbering has the property that for every arc (i->j)
+* in the graph the condition num(i) >= num(j) holds.
+*
+* RETURNS
+*
+* The routine returns nc, the total number of components found. */
+
+int glp_strong_comp(glp_graph *G, int v_num)
+{ glp_vertex *v;
+ glp_arc *a;
+ int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl,
+ *numb, *prev;
+ if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
+ xerror("glp_strong_comp: v_num = %d; invalid offset\n",
+ v_num);
+ n = G->nv;
+ if (n == 0)
+ { nc = 0;
+ goto done;
+ }
+ na = G->na;
+ icn = xcalloc(1+na, sizeof(int));
+ ip = xcalloc(1+n, sizeof(int));
+ lenr = xcalloc(1+n, sizeof(int));
+ ior = xcalloc(1+n, sizeof(int));
+ ib = xcalloc(1+n, sizeof(int));
+ lowl = xcalloc(1+n, sizeof(int));
+ numb = xcalloc(1+n, sizeof(int));
+ prev = xcalloc(1+n, sizeof(int));
+ k = 1;
+ for (i = 1; i <= n; i++)
+ { v = G->v[i];
+ ip[i] = k;
+ for (a = v->out; a != NULL; a = a->t_next)
+ icn[k++] = a->head->i;
+ lenr[i] = k - ip[i];
+ }
+ xassert(na == k-1);
+ nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev);
+ if (v_num >= 0)
+ { xassert(ib[1] == 1);
+ for (k = 1; k <= nc; k++)
+ { last = (k < nc ? ib[k+1] : n+1);
+ xassert(ib[k] < last);
+ for (i = ib[k]; i < last; i++)
+ { v = G->v[ior[i]];
+ memcpy((char *)v->data + v_num, &k, sizeof(int));
+ }
+ }
+ }
+ xfree(icn);
+ xfree(ip);
+ xfree(lenr);
+ xfree(ior);
+ xfree(ib);
+ xfree(lowl);
+ xfree(numb);
+ xfree(prev);
+done: return nc;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/topsort.c b/test/monniaux/glpk-4.65/src/api/topsort.c
new file mode 100644
index 00000000..971937f2
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/topsort.c
@@ -0,0 +1,123 @@
+/* topsort.c (topological sorting of acyclic digraph) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_top_sort - topological sorting of acyclic digraph
+*
+* SYNOPSIS
+*
+* int glp_top_sort(glp_graph *G, int v_num);
+*
+* DESCRIPTION
+*
+* The routine glp_top_sort performs topological sorting of vertices of
+* the specified acyclic digraph.
+*
+* The parameter v_num specifies an offset of the field of type int in
+* the vertex data block, to which the routine stores the vertex number
+* assigned. If v_num < 0, vertex numbers are not stored.
+*
+* The vertices are numbered from 1 to n, where n is the total number
+* of vertices in the graph. The vertex numbering has the property that
+* for every arc (i->j) in the graph the condition num(i) < num(j)
+* holds. Special case num(i) = 0 means that vertex i is not assigned a
+* number, because the graph is *not* acyclic.
+*
+* RETURNS
+*
+* If the graph is acyclic and therefore all the vertices have been
+* assigned numbers, the routine glp_top_sort returns zero. Otherwise,
+* if the graph is not acyclic, the routine returns the number of
+* vertices which have not been numbered, i.e. for which num(i) = 0. */
+
+static int top_sort(glp_graph *G, int num[])
+{ glp_arc *a;
+ int i, j, cnt, top, *stack, *indeg;
+ /* allocate working arrays */
+ indeg = xcalloc(1+G->nv, sizeof(int));
+ stack = xcalloc(1+G->nv, sizeof(int));
+ /* determine initial indegree of each vertex; push into the stack
+ the vertices having zero indegree */
+ top = 0;
+ for (i = 1; i <= G->nv; i++)
+ { num[i] = indeg[i] = 0;
+ for (a = G->v[i]->in; a != NULL; a = a->h_next)
+ indeg[i]++;
+ if (indeg[i] == 0)
+ stack[++top] = i;
+ }
+ /* assign numbers to vertices in the sorted order */
+ cnt = 0;
+ while (top > 0)
+ { /* pull vertex i from the stack */
+ i = stack[top--];
+ /* it has zero indegree in the current graph */
+ xassert(indeg[i] == 0);
+ /* so assign it a next number */
+ xassert(num[i] == 0);
+ num[i] = ++cnt;
+ /* remove vertex i from the current graph, update indegree of
+ its adjacent vertices, and push into the stack new vertices
+ whose indegree becomes zero */
+ for (a = G->v[i]->out; a != NULL; a = a->t_next)
+ { j = a->head->i;
+ /* there exists arc (i->j) in the graph */
+ xassert(indeg[j] > 0);
+ indeg[j]--;
+ if (indeg[j] == 0)
+ stack[++top] = j;
+ }
+ }
+ /* free working arrays */
+ xfree(indeg);
+ xfree(stack);
+ return G->nv - cnt;
+}
+
+int glp_top_sort(glp_graph *G, int v_num)
+{ glp_vertex *v;
+ int i, cnt, *num;
+ if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
+ xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num);
+ if (G->nv == 0)
+ { cnt = 0;
+ goto done;
+ }
+ num = xcalloc(1+G->nv, sizeof(int));
+ cnt = top_sort(G, num);
+ if (v_num >= 0)
+ { for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ memcpy((char *)v->data + v_num, &num[i], sizeof(int));
+ }
+ }
+ xfree(num);
+done: return cnt;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/wcliqex.c b/test/monniaux/glpk-4.65/src/api/wcliqex.c
new file mode 100644
index 00000000..53c2d521
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/wcliqex.c
@@ -0,0 +1,122 @@
+/* wcliqex.c (find maximum weight clique with exact algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+#include "wclique.h"
+
+static void set_edge(int nv, unsigned char a[], int i, int j)
+{ int k;
+ xassert(1 <= j && j < i && i <= nv);
+ k = ((i - 1) * (i - 2)) / 2 + (j - 1);
+ a[k / CHAR_BIT] |=
+ (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
+ return;
+}
+
+int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set)
+{ /* find maximum weight clique with exact algorithm */
+ glp_arc *e;
+ int i, j, k, len, x, *w, *ind, ret = 0;
+ unsigned char *a;
+ double s, t;
+ if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
+ xerror("glp_wclique_exact: v_wgt = %d; invalid parameter\n",
+ v_wgt);
+ if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+ xerror("glp_wclique_exact: v_set = %d; invalid parameter\n",
+ v_set);
+ if (G->nv == 0)
+ { /* empty graph has only empty clique */
+ if (sol != NULL) *sol = 0.0;
+ return 0;
+ }
+ /* allocate working arrays */
+ w = xcalloc(1+G->nv, sizeof(int));
+ ind = xcalloc(1+G->nv, sizeof(int));
+ len = G->nv; /* # vertices */
+ len = len * (len - 1) / 2; /* # entries in lower triangle */
+ len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* # bytes needed */
+ a = xcalloc(len, sizeof(char));
+ memset(a, 0, len * sizeof(char));
+ /* determine vertex weights */
+ s = 0.0;
+ for (i = 1; i <= G->nv; i++)
+ { if (v_wgt >= 0)
+ { memcpy(&t, (char *)G->v[i]->data + v_wgt, sizeof(double));
+ if (!(0.0 <= t && t <= (double)INT_MAX && t == floor(t)))
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ w[i] = (int)t;
+ }
+ else
+ w[i] = 1;
+ s += (double)w[i];
+ }
+ if (s > (double)INT_MAX)
+ { ret = GLP_EDATA;
+ goto done;
+ }
+ /* build the adjacency matrix */
+ for (i = 1; i <= G->nv; i++)
+ { for (e = G->v[i]->in; e != NULL; e = e->h_next)
+ { j = e->tail->i;
+ /* there exists edge (j,i) in the graph */
+ if (i > j) set_edge(G->nv, a, i, j);
+ }
+ for (e = G->v[i]->out; e != NULL; e = e->t_next)
+ { j = e->head->i;
+ /* there exists edge (i,j) in the graph */
+ if (i > j) set_edge(G->nv, a, i, j);
+ }
+ }
+ /* find maximum weight clique in the graph */
+ len = wclique(G->nv, w, a, ind);
+ /* compute the clique weight */
+ s = 0.0;
+ for (k = 1; k <= len; k++)
+ { i = ind[k];
+ xassert(1 <= i && i <= G->nv);
+ s += (double)w[i];
+ }
+ if (sol != NULL) *sol = s;
+ /* mark vertices included in the clique */
+ if (v_set >= 0)
+ { x = 0;
+ for (i = 1; i <= G->nv; i++)
+ memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int));
+ x = 1;
+ for (k = 1; k <= len; k++)
+ { i = ind[k];
+ memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int));
+ }
+ }
+done: /* free working arrays */
+ xfree(w);
+ xfree(ind);
+ xfree(a);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/weak.c b/test/monniaux/glpk-4.65/src/api/weak.c
new file mode 100644
index 00000000..027c09c1
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/weak.c
@@ -0,0 +1,150 @@
+/* weak.c (find all weakly connected components of graph) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_weak_comp - find all weakly connected components of graph
+*
+* SYNOPSIS
+*
+* int glp_weak_comp(glp_graph *G, int v_num);
+*
+* DESCRIPTION
+*
+* The routine glp_weak_comp finds all weakly connected components of
+* the specified graph.
+*
+* The parameter v_num specifies an offset of the field of type int
+* in the vertex data block, to which the routine stores the number of
+* a (weakly) connected component containing that vertex. If v_num < 0,
+* no component numbers are stored.
+*
+* The components are numbered in arbitrary order from 1 to nc, where
+* nc is the total number of components found, 0 <= nc <= |V|.
+*
+* RETURNS
+*
+* The routine returns nc, the total number of components found. */
+
+int glp_weak_comp(glp_graph *G, int v_num)
+{ glp_vertex *v;
+ glp_arc *a;
+ int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list;
+ if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
+ xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num);
+ nv = G->nv;
+ if (nv == 0)
+ { nc = 0;
+ goto done;
+ }
+ /* allocate working arrays */
+ prev = xcalloc(1+nv, sizeof(int));
+ next = xcalloc(1+nv, sizeof(int));
+ list = xcalloc(1+nv, sizeof(int));
+ /* if vertex i is unlabelled, prev[i] is the index of previous
+ unlabelled vertex, and next[i] is the index of next unlabelled
+ vertex; if vertex i is labelled, then prev[i] < 0, and next[i]
+ is the connected component number */
+ /* initially all vertices are unlabelled */
+ f = 1;
+ for (i = 1; i <= nv; i++)
+ prev[i] = i - 1, next[i] = i + 1;
+ next[nv] = 0;
+ /* main loop (until all vertices have been labelled) */
+ nc = 0;
+ while (f != 0)
+ { /* take an unlabelled vertex */
+ i = f;
+ /* and remove it from the list of unlabelled vertices */
+ f = next[i];
+ if (f != 0) prev[f] = 0;
+ /* label the vertex; it begins a new component */
+ prev[i] = -1, next[i] = ++nc;
+ /* breadth first search */
+ list[1] = i, pos1 = pos2 = 1;
+ while (pos1 <= pos2)
+ { /* dequeue vertex i */
+ i = list[pos1++];
+ /* consider all arcs incoming to vertex i */
+ for (a = G->v[i]->in; a != NULL; a = a->h_next)
+ { /* vertex j is adjacent to vertex i */
+ j = a->tail->i;
+ if (prev[j] >= 0)
+ { /* vertex j is unlabelled */
+ /* remove it from the list of unlabelled vertices */
+ if (prev[j] == 0)
+ f = next[j];
+ else
+ next[prev[j]] = next[j];
+ if (next[j] == 0)
+ ;
+ else
+ prev[next[j]] = prev[j];
+ /* label the vertex */
+ prev[j] = -1, next[j] = nc;
+ /* and enqueue it for further consideration */
+ list[++pos2] = j;
+ }
+ }
+ /* consider all arcs outgoing from vertex i */
+ for (a = G->v[i]->out; a != NULL; a = a->t_next)
+ { /* vertex j is adjacent to vertex i */
+ j = a->head->i;
+ if (prev[j] >= 0)
+ { /* vertex j is unlabelled */
+ /* remove it from the list of unlabelled vertices */
+ if (prev[j] == 0)
+ f = next[j];
+ else
+ next[prev[j]] = next[j];
+ if (next[j] == 0)
+ ;
+ else
+ prev[next[j]] = prev[j];
+ /* label the vertex */
+ prev[j] = -1, next[j] = nc;
+ /* and enqueue it for further consideration */
+ list[++pos2] = j;
+ }
+ }
+ }
+ }
+ /* store component numbers */
+ if (v_num >= 0)
+ { for (i = 1; i <= nv; i++)
+ { v = G->v[i];
+ memcpy((char *)v->data + v_num, &next[i], sizeof(int));
+ }
+ }
+ /* free working arrays */
+ xfree(prev);
+ xfree(next);
+ xfree(list);
+done: return nc;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/wrasn.c b/test/monniaux/glpk-4.65/src/api/wrasn.c
new file mode 100644
index 00000000..81433da8
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/wrasn.c
@@ -0,0 +1,107 @@
+/* wrasn.c (write assignment problem data in DIMACS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+#define xfprintf glp_format
+
+/***********************************************************************
+* NAME
+*
+* glp_write_asnprob - write assignment problem data in DIMACS format
+*
+* SYNOPSIS
+*
+* int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
+* const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_write_asnprob writes assignment problem data in
+* DIMACS format to a text file.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
+ *fname)
+{ glp_file *fp;
+ glp_vertex *v;
+ glp_arc *a;
+ int i, k, count = 0, ret;
+ double cost;
+ if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+ xerror("glp_write_asnprob: v_set = %d; invalid offset\n",
+ v_set);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_write_asnprob: a_cost = %d; invalid offset\n",
+ a_cost);
+ xprintf("Writing assignment problem data to '%s'...\n", fname);
+ fp = glp_open(fname, "w");
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xfprintf(fp, "c %s\n",
+ G->name == NULL ? "unknown" : G->name), count++;
+ xfprintf(fp, "p asn %d %d\n", G->nv, G->na), count++;
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ if (v_set >= 0)
+ memcpy(&k, (char *)v->data + v_set, sizeof(int));
+ else
+ k = (v->out != NULL ? 0 : 1);
+ if (k == 0)
+ xfprintf(fp, "n %d\n", i), count++;
+ }
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { if (a_cost >= 0)
+ memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+ else
+ cost = 1.0;
+ xfprintf(fp, "a %d %d %.*g\n",
+ a->tail->i, a->head->i, DBL_DIG, cost), count++;
+ }
+ }
+ xfprintf(fp, "c eof\n"), count++;
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xprintf("%d lines were written\n", count);
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/wrcc.c b/test/monniaux/glpk-4.65/src/api/wrcc.c
new file mode 100644
index 00000000..2069c8ac
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/wrcc.c
@@ -0,0 +1,102 @@
+/* wrcc.c (write graph in DIMACS clique/coloring format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+#define xfprintf glp_format
+
+/***********************************************************************
+* NAME
+*
+* glp_write_ccdata - write graph in DIMACS clique/coloring format
+*
+* SYNOPSIS
+*
+* int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_write_ccdata writes the specified graph in DIMACS
+* clique/coloring format to a text file.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname)
+{ glp_file *fp;
+ glp_vertex *v;
+ glp_arc *e;
+ int i, count = 0, ret;
+ double w;
+ if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
+ xerror("glp_write_ccdata: v_wgt = %d; invalid offset\n",
+ v_wgt);
+ xprintf("Writing graph to '%s'\n", fname);
+ fp = glp_open(fname, "w");
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xfprintf(fp, "c %s\n",
+ G->name == NULL ? "unknown" : G->name), count++;
+ xfprintf(fp, "p edge %d %d\n", G->nv, G->na), count++;
+ if (v_wgt >= 0)
+ { for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ memcpy(&w, (char *)v->data + v_wgt, sizeof(double));
+ if (w != 1.0)
+ xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, w), count++;
+ }
+ }
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ for (e = v->out; e != NULL; e = e->t_next)
+ xfprintf(fp, "e %d %d\n", e->tail->i, e->head->i), count++;
+ }
+ xfprintf(fp, "c eof\n"), count++;
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xprintf("%d lines were written\n", count);
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/**********************************************************************/
+
+int glp_write_graph(glp_graph *G, const char *fname)
+{ return
+ glp_write_ccdata(G, -1, fname);
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/wrcnf.c b/test/monniaux/glpk-4.65/src/api/wrcnf.c
new file mode 100644
index 00000000..c7974386
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/wrcnf.c
@@ -0,0 +1,87 @@
+/* wrcnf.c (write CNF-SAT problem data in DIMACS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+#define xfprintf glp_format
+
+int glp_write_cnfsat(glp_prob *P, const char *fname)
+{ /* write CNF-SAT problem data in DIMACS format */
+ glp_file *fp = NULL;
+ GLPAIJ *aij;
+ int i, j, len, count = 0, ret;
+ char s[50];
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_write_cnfsat: P = %p; invalid problem object\n",
+ P);
+#endif
+ if (glp_check_cnfsat(P) != 0)
+ { xprintf("glp_write_cnfsat: problem object does not encode CNF-"
+ "SAT instance\n");
+ ret = 1;
+ goto done;
+ }
+ xprintf("Writing CNF-SAT problem data to '%s'...\n", fname);
+ fp = glp_open(fname, "w");
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xfprintf(fp, "c %s\n",
+ P->name == NULL ? "unknown" : P->name), count++;
+ xfprintf(fp, "p cnf %d %d\n", P->n, P->m), count++;
+ for (i = 1; i <= P->m; i++)
+ { len = 0;
+ for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ { j = aij->col->j;
+ if (aij->val < 0.0) j = -j;
+ sprintf(s, "%d", j);
+ if (len > 0 && len + 1 + strlen(s) > 72)
+ xfprintf(fp, "\n"), count++, len = 0;
+ xfprintf(fp, "%s%s", len == 0 ? "" : " ", s);
+ if (len > 0) len++;
+ len += strlen(s);
+ }
+ if (len > 0 && len + 1 + 1 > 72)
+ xfprintf(fp, "\n"), count++, len = 0;
+ xfprintf(fp, "%s0\n", len == 0 ? "" : " "), count++;
+ }
+ xfprintf(fp, "c eof\n"), count++;
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xprintf("%d lines were written\n", count);
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/wript.c b/test/monniaux/glpk-4.65/src/api/wript.c
new file mode 100644
index 00000000..f2ca802c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/wript.c
@@ -0,0 +1,124 @@
+/* wript.c (write interior-point solution in GLPK format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_write_ipt - write interior-point solution in GLPK format
+*
+* SYNOPSIS
+*
+* int glp_write_ipt(glp_prob *P, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_write_ipt writes interior-point solution to a text
+* file in GLPK format.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_write_ipt(glp_prob *P, const char *fname)
+{ glp_file *fp;
+ GLPROW *row;
+ GLPCOL *col;
+ int i, j, count, ret = 1;
+ char *s;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_write_ipt: P = %p; invalid problem object\n", P);
+#endif
+ if (fname == NULL)
+ xerror("glp_write_ipt: fname = %d; invalid parameter\n", fname)
+ ;
+ xprintf("Writing interior-point solution to '%s'...\n", fname);
+ fp = glp_open(fname, "w"), count = 0;
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ goto done;
+ }
+ /* write comment lines */
+ glp_format(fp, "c %-12s%s\n", "Problem:",
+ P->name == NULL ? "" : P->name), count++;
+ glp_format(fp, "c %-12s%d\n", "Rows:", P->m), count++;
+ glp_format(fp, "c %-12s%d\n", "Columns:", P->n), count++;
+ glp_format(fp, "c %-12s%d\n", "Non-zeros:", P->nnz), count++;
+ switch (P->ipt_stat)
+ { case GLP_OPT: s = "OPTIMAL"; break;
+ case GLP_INFEAS: s = "INFEASIBLE (INTERMEDIATE)"; break;
+ case GLP_NOFEAS: s = "INFEASIBLE (FINAL)"; break;
+ case GLP_UNDEF: s = "UNDEFINED"; break;
+ default: s = "???"; break;
+ }
+ glp_format(fp, "c %-12s%s\n", "Status:", s), count++;
+ switch (P->dir)
+ { case GLP_MIN: s = "MINimum"; break;
+ case GLP_MAX: s = "MAXimum"; break;
+ default: s = "???"; break;
+ }
+ glp_format(fp, "c %-12s%s%s%.10g (%s)\n", "Objective:",
+ P->obj == NULL ? "" : P->obj,
+ P->obj == NULL ? "" : " = ", P->ipt_obj, s), count++;
+ glp_format(fp, "c\n"), count++;
+ /* write solution line */
+ glp_format(fp, "s ipt %d %d ", P->m, P->n), count++;
+ switch (P->ipt_stat)
+ { case GLP_OPT: glp_format(fp, "o"); break;
+ case GLP_INFEAS: glp_format(fp, "i"); break;
+ case GLP_NOFEAS: glp_format(fp, "n"); break;
+ case GLP_UNDEF: glp_format(fp, "u"); break;
+ default: glp_format(fp, "?"); break;
+ }
+ glp_format(fp, " %.*g\n", DBL_DIG, P->ipt_obj);
+ /* write row solution descriptor lines */
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ glp_format(fp, "i %d %.*g %.*g\n", i, DBL_DIG, row->pval,
+ DBL_DIG, row->dval), count++;
+ }
+ /* write column solution descriptor lines */
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ glp_format(fp, "j %d %.*g %.*g\n", j, DBL_DIG, col->pval,
+ DBL_DIG, col->dval), count++;
+ }
+ /* write end line */
+ glp_format(fp, "e o f\n"), count++;
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ goto done;
+ }
+ /* interior-point solution has been successfully written */
+ xprintf("%d lines were written\n", count);
+ ret = 0;
+done: if (fp != NULL)
+ glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/wrmaxf.c b/test/monniaux/glpk-4.65/src/api/wrmaxf.c
new file mode 100644
index 00000000..d3101ca8
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/wrmaxf.c
@@ -0,0 +1,104 @@
+/* wrmaxf.c (write maximum flow problem data in DIMACS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+#define xfprintf glp_format
+
+/***********************************************************************
+* NAME
+*
+* glp_write_maxflow - write maximum flow problem data in DIMACS format
+*
+* SYNOPSIS
+*
+* int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
+* const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_write_maxflow writes maximum flow problem data in
+* DIMACS format to a text file.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
+ const char *fname)
+{ glp_file *fp;
+ glp_vertex *v;
+ glp_arc *a;
+ int i, count = 0, ret;
+ double cap;
+ if (!(1 <= s && s <= G->nv))
+ xerror("glp_write_maxflow: s = %d; source node number out of r"
+ "ange\n", s);
+ if (!(1 <= t && t <= G->nv))
+ xerror("glp_write_maxflow: t = %d: sink node number out of ran"
+ "ge\n", t);
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
+ a_cap);
+ xprintf("Writing maximum flow problem data to '%s'...\n",
+ fname);
+ fp = glp_open(fname, "w");
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xfprintf(fp, "c %s\n",
+ G->name == NULL ? "unknown" : G->name), count++;
+ xfprintf(fp, "p max %d %d\n", G->nv, G->na), count++;
+ xfprintf(fp, "n %d s\n", s), count++;
+ xfprintf(fp, "n %d t\n", t), count++;
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { if (a_cap >= 0)
+ memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+ else
+ cap = 1.0;
+ xfprintf(fp, "a %d %d %.*g\n",
+ a->tail->i, a->head->i, DBL_DIG, cap), count++;
+ }
+ }
+ xfprintf(fp, "c eof\n"), count++;
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xprintf("%d lines were written\n", count);
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/wrmcf.c b/test/monniaux/glpk-4.65/src/api/wrmcf.c
new file mode 100644
index 00000000..0da37f42
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/wrmcf.c
@@ -0,0 +1,122 @@
+/* wrmcf.c (write min-cost flow problem data in DIMACS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpk.h"
+
+#define xfprintf glp_format
+
+/***********************************************************************
+* NAME
+*
+* glp_write_mincost - write min-cost flow probl. data in DIMACS format
+*
+* SYNOPSIS
+*
+* int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+* int a_cost, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_write_mincost writes minimum cost flow problem data
+* in DIMACS format to a text file.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+ int a_cost, const char *fname)
+{ glp_file *fp;
+ glp_vertex *v;
+ glp_arc *a;
+ int i, count = 0, ret;
+ double rhs, low, cap, cost;
+ if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+ xerror("glp_write_mincost: v_rhs = %d; invalid offset\n",
+ v_rhs);
+ if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+ xerror("glp_write_mincost: a_low = %d; invalid offset\n",
+ a_low);
+ if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+ xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
+ a_cap);
+ if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+ xerror("glp_write_mincost: a_cost = %d; invalid offset\n",
+ a_cost);
+ xprintf("Writing min-cost flow problem data to '%s'...\n",
+ fname);
+ fp = glp_open(fname, "w");
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xfprintf(fp, "c %s\n",
+ G->name == NULL ? "unknown" : G->name), count++;
+ xfprintf(fp, "p min %d %d\n", G->nv, G->na), count++;
+ if (v_rhs >= 0)
+ { for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
+ if (rhs != 0.0)
+ xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, rhs), count++;
+ }
+ }
+ for (i = 1; i <= G->nv; i++)
+ { v = G->v[i];
+ for (a = v->out; a != NULL; a = a->t_next)
+ { if (a_low >= 0)
+ memcpy(&low, (char *)a->data + a_low, sizeof(double));
+ else
+ low = 0.0;
+ if (a_cap >= 0)
+ memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+ else
+ cap = 1.0;
+ if (a_cost >= 0)
+ memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+ else
+ cost = 0.0;
+ xfprintf(fp, "a %d %d %.*g %.*g %.*g\n",
+ a->tail->i, a->head->i, DBL_DIG, low, DBL_DIG, cap,
+ DBL_DIG, cost), count++;
+ }
+ }
+ xfprintf(fp, "c eof\n"), count++;
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xprintf("%d lines were written\n", count);
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/wrmip.c b/test/monniaux/glpk-4.65/src/api/wrmip.c
new file mode 100644
index 00000000..407a5fec
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/wrmip.c
@@ -0,0 +1,122 @@
+/* wrmip.c (write MIP solution in GLPK format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_write_mip - write MIP solution in GLPK format
+*
+* SYNOPSIS
+*
+* int glp_write_mip(glp_prob *P, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_write_mip writes MIP solution to a text file in GLPK
+* format.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_write_mip(glp_prob *P, const char *fname)
+{ glp_file *fp;
+ GLPROW *row;
+ GLPCOL *col;
+ int i, j, count, ret = 1;
+ char *s;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_write_mip: P = %p; invalid problem object\n", P);
+#endif
+ if (fname == NULL)
+ xerror("glp_write_mip: fname = %d; invalid parameter\n", fname)
+ ;
+ xprintf("Writing MIP solution to '%s'...\n", fname);
+ fp = glp_open(fname, "w"), count = 0;
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ goto done;
+ }
+ /* write comment lines */
+ glp_format(fp, "c %-12s%s\n", "Problem:",
+ P->name == NULL ? "" : P->name), count++;
+ glp_format(fp, "c %-12s%d\n", "Rows:", P->m), count++;
+ glp_format(fp, "c %-12s%d\n", "Columns:", P->n), count++;
+ glp_format(fp, "c %-12s%d\n", "Non-zeros:", P->nnz), count++;
+ switch (P->mip_stat)
+ { case GLP_OPT: s = "INTEGER OPTIMAL"; break;
+ case GLP_FEAS: s = "INTEGER NON-OPTIMAL"; break;
+ case GLP_NOFEAS: s = "INTEGER EMPTY"; break;
+ case GLP_UNDEF: s = "INTEGER UNDEFINED"; break;
+ default: s = "???"; break;
+ }
+ glp_format(fp, "c %-12s%s\n", "Status:", s), count++;
+ switch (P->dir)
+ { case GLP_MIN: s = "MINimum"; break;
+ case GLP_MAX: s = "MAXimum"; break;
+ default: s = "???"; break;
+ }
+ glp_format(fp, "c %-12s%s%s%.10g (%s)\n", "Objective:",
+ P->obj == NULL ? "" : P->obj,
+ P->obj == NULL ? "" : " = ", P->mip_obj, s), count++;
+ glp_format(fp, "c\n"), count++;
+ /* write solution line */
+ glp_format(fp, "s mip %d %d ", P->m, P->n), count++;
+ switch (P->mip_stat)
+ { case GLP_OPT: glp_format(fp, "o"); break;
+ case GLP_FEAS: glp_format(fp, "f"); break;
+ case GLP_NOFEAS: glp_format(fp, "n"); break;
+ case GLP_UNDEF: glp_format(fp, "u"); break;
+ default: glp_format(fp, "?"); break;
+ }
+ glp_format(fp, " %.*g\n", DBL_DIG, P->mip_obj);
+ /* write row solution descriptor lines */
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ glp_format(fp, "i %d %.*g\n", i, DBL_DIG, row->mipx), count++;
+ }
+ /* write column solution descriptor lines */
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ glp_format(fp, "j %d %.*g\n", j, DBL_DIG, col->mipx), count++;
+ }
+ /* write end line */
+ glp_format(fp, "e o f\n"), count++;
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ goto done;
+ }
+ /* MIP solution has been successfully written */
+ xprintf("%d lines were written\n", count);
+ ret = 0;
+done: if (fp != NULL)
+ glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/wrprob.c b/test/monniaux/glpk-4.65/src/api/wrprob.c
new file mode 100644
index 00000000..99983d35
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/wrprob.c
@@ -0,0 +1,166 @@
+/* wrprob.c (write problem data in GLPK format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+#define xfprintf glp_format
+
+/***********************************************************************
+* NAME
+*
+* glp_write_prob - write problem data in GLPK format
+*
+* SYNOPSIS
+*
+* int glp_write_prob(glp_prob *P, int flags, const char *fname);
+*
+* The routine glp_write_prob writes problem data in GLPK LP/MIP format
+* to a text file.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_write_prob(glp_prob *P, int flags, const char *fname)
+{ glp_file *fp;
+ GLPROW *row;
+ GLPCOL *col;
+ GLPAIJ *aij;
+ int mip, i, j, count, ret;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_write_prob: P = %p; invalid problem object\n",
+ P);
+#endif
+ if (flags != 0)
+ xerror("glp_write_prob: flags = %d; invalid parameter\n",
+ flags);
+ if (fname == NULL)
+ xerror("glp_write_prob: fname = %d; invalid parameter\n",
+ fname);
+ xprintf("Writing problem data to '%s'...\n", fname);
+ fp = glp_open(fname, "w"), count = 0;
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ /* write problem line */
+ mip = (glp_get_num_int(P) > 0);
+ xfprintf(fp, "p %s %s %d %d %d\n", !mip ? "lp" : "mip",
+ P->dir == GLP_MIN ? "min" : P->dir == GLP_MAX ? "max" : "???",
+ P->m, P->n, P->nnz), count++;
+ if (P->name != NULL)
+ xfprintf(fp, "n p %s\n", P->name), count++;
+ if (P->obj != NULL)
+ xfprintf(fp, "n z %s\n", P->obj), count++;
+ /* write row descriptors */
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ if (row->type == GLP_FX && row->lb == 0.0)
+ goto skip1;
+ xfprintf(fp, "i %d ", i), count++;
+ if (row->type == GLP_FR)
+ xfprintf(fp, "f\n");
+ else if (row->type == GLP_LO)
+ xfprintf(fp, "l %.*g\n", DBL_DIG, row->lb);
+ else if (row->type == GLP_UP)
+ xfprintf(fp, "u %.*g\n", DBL_DIG, row->ub);
+ else if (row->type == GLP_DB)
+ xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, row->lb, DBL_DIG,
+ row->ub);
+ else if (row->type == GLP_FX)
+ xfprintf(fp, "s %.*g\n", DBL_DIG, row->lb);
+ else
+ xassert(row != row);
+skip1: if (row->name != NULL)
+ xfprintf(fp, "n i %d %s\n", i, row->name), count++;
+ }
+ /* write column descriptors */
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (!mip && col->type == GLP_LO && col->lb == 0.0)
+ goto skip2;
+ if (mip && col->kind == GLP_IV && col->type == GLP_DB &&
+ col->lb == 0.0 && col->ub == 1.0)
+ goto skip2;
+ xfprintf(fp, "j %d ", j), count++;
+ if (mip)
+ { if (col->kind == GLP_CV)
+ xfprintf(fp, "c ");
+ else if (col->kind == GLP_IV)
+ xfprintf(fp, "i ");
+ else
+ xassert(col != col);
+ }
+ if (col->type == GLP_FR)
+ xfprintf(fp, "f\n");
+ else if (col->type == GLP_LO)
+ xfprintf(fp, "l %.*g\n", DBL_DIG, col->lb);
+ else if (col->type == GLP_UP)
+ xfprintf(fp, "u %.*g\n", DBL_DIG, col->ub);
+ else if (col->type == GLP_DB)
+ xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, col->lb, DBL_DIG,
+ col->ub);
+ else if (col->type == GLP_FX)
+ xfprintf(fp, "s %.*g\n", DBL_DIG, col->lb);
+ else
+ xassert(col != col);
+skip2: if (col->name != NULL)
+ xfprintf(fp, "n j %d %s\n", j, col->name), count++;
+ }
+ /* write objective coefficient descriptors */
+ if (P->c0 != 0.0)
+ xfprintf(fp, "a 0 0 %.*g\n", DBL_DIG, P->c0), count++;
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (col->coef != 0.0)
+ xfprintf(fp, "a 0 %d %.*g\n", j, DBL_DIG, col->coef),
+ count++;
+ }
+ /* write constraint coefficient descriptors */
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ xfprintf(fp, "a %d %d %.*g\n", i, aij->col->j, DBL_DIG,
+ aij->val), count++;
+ }
+ /* write end line */
+ xfprintf(fp, "e o f\n"), count++;
+#if 0 /* FIXME */
+ xfflush(fp);
+#endif
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ ret = 1;
+ goto done;
+ }
+ xprintf("%d lines were written\n", count);
+ ret = 0;
+done: if (fp != NULL) glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/api/wrsol.c b/test/monniaux/glpk-4.65/src/api/wrsol.c
new file mode 100644
index 00000000..66c69233
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/api/wrsol.c
@@ -0,0 +1,174 @@
+/* wrsol.c (write basic solution in GLPK format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2010-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_write_sol - write basic solution in GLPK format
+*
+* SYNOPSIS
+*
+* int glp_write_sol(glp_prob *P, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine glp_write_sol writes basic solution to a text file in
+* GLPK format.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero. Otherwise
+* it prints an error message and returns non-zero. */
+
+int glp_write_sol(glp_prob *P, const char *fname)
+{ glp_file *fp;
+ GLPROW *row;
+ GLPCOL *col;
+ int i, j, count, ret = 1;
+ char *s;
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_write_sol: P = %p; invalid problem object\n", P);
+#endif
+ if (fname == NULL)
+ xerror("glp_write_sol: fname = %d; invalid parameter\n", fname)
+ ;
+ xprintf("Writing basic solution to '%s'...\n", fname);
+ fp = glp_open(fname, "w"), count = 0;
+ if (fp == NULL)
+ { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg());
+ goto done;
+ }
+ /* write comment lines */
+ glp_format(fp, "c %-12s%s\n", "Problem:",
+ P->name == NULL ? "" : P->name), count++;
+ glp_format(fp, "c %-12s%d\n", "Rows:", P->m), count++;
+ glp_format(fp, "c %-12s%d\n", "Columns:", P->n), count++;
+ glp_format(fp, "c %-12s%d\n", "Non-zeros:", P->nnz), count++;
+ switch (glp_get_status(P))
+ { case GLP_OPT: s = "OPTIMAL"; break;
+ case GLP_FEAS: s = "FEASIBLE"; break;
+ case GLP_INFEAS: s = "INFEASIBLE (INTERMEDIATE)"; break;
+ case GLP_NOFEAS: s = "INFEASIBLE (FINAL)"; break;
+ case GLP_UNBND: s = "UNBOUNDED"; break;
+ case GLP_UNDEF: s = "UNDEFINED"; break;
+ default: s = "???"; break;
+ }
+ glp_format(fp, "c %-12s%s\n", "Status:", s), count++;
+ switch (P->dir)
+ { case GLP_MIN: s = "MINimum"; break;
+ case GLP_MAX: s = "MAXimum"; break;
+ default: s = "???"; break;
+ }
+ glp_format(fp, "c %-12s%s%s%.10g (%s)\n", "Objective:",
+ P->obj == NULL ? "" : P->obj,
+ P->obj == NULL ? "" : " = ", P->obj_val, s), count++;
+ glp_format(fp, "c\n"), count++;
+ /* write solution line */
+ glp_format(fp, "s bas %d %d ", P->m, P->n), count++;
+ switch (P->pbs_stat)
+ { case GLP_UNDEF: glp_format(fp, "u"); break;
+ case GLP_FEAS: glp_format(fp, "f"); break;
+ case GLP_INFEAS: glp_format(fp, "i"); break;
+ case GLP_NOFEAS: glp_format(fp, "n"); break;
+ default: glp_format(fp, "?"); break;
+ }
+ glp_format(fp, " ");
+ switch (P->dbs_stat)
+ { case GLP_UNDEF: glp_format(fp, "u"); break;
+ case GLP_FEAS: glp_format(fp, "f"); break;
+ case GLP_INFEAS: glp_format(fp, "i"); break;
+ case GLP_NOFEAS: glp_format(fp, "n"); break;
+ default: glp_format(fp, "?"); break;
+ }
+ glp_format(fp, " %.*g\n", DBL_DIG, P->obj_val);
+ /* write row solution descriptor lines */
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ glp_format(fp, "i %d ", i), count++;
+ switch (row->stat)
+ { case GLP_BS:
+ glp_format(fp, "b");
+ break;
+ case GLP_NL:
+ glp_format(fp, "l");
+ break;
+ case GLP_NU:
+ glp_format(fp, "u");
+ break;
+ case GLP_NF:
+ glp_format(fp, "f");
+ break;
+ case GLP_NS:
+ glp_format(fp, "s");
+ break;
+ default:
+ xassert(row != row);
+ }
+ glp_format(fp, " %.*g %.*g\n", DBL_DIG, row->prim, DBL_DIG,
+ row->dual);
+ }
+ /* write column solution descriptor lines */
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ glp_format(fp, "j %d ", j), count++;
+ switch (col->stat)
+ { case GLP_BS:
+ glp_format(fp, "b");
+ break;
+ case GLP_NL:
+ glp_format(fp, "l");
+ break;
+ case GLP_NU:
+ glp_format(fp, "u");
+ break;
+ case GLP_NF:
+ glp_format(fp, "f");
+ break;
+ case GLP_NS:
+ glp_format(fp, "s");
+ break;
+ default:
+ xassert(col != col);
+ }
+ glp_format(fp, " %.*g %.*g\n", DBL_DIG, col->prim, DBL_DIG,
+ col->dual);
+ }
+ /* write end line */
+ glp_format(fp, "e o f\n"), count++;
+ if (glp_ioerr(fp))
+ { xprintf("Write error on '%s' - %s\n", fname, get_err_msg());
+ goto done;
+ }
+ /* basic solution has been successfully written */
+ xprintf("%d lines were written\n", count);
+ ret = 0;
+done: if (fp != NULL)
+ glp_close(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/btf.c b/test/monniaux/glpk-4.65/src/bflib/btf.c
new file mode 100644
index 00000000..993c9ca1
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/btf.c
@@ -0,0 +1,569 @@
+/* btf.c (sparse block triangular LU-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2013-2014 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/>.
+***********************************************************************/
+
+#include "btf.h"
+#include "env.h"
+#include "luf.h"
+#include "mc13d.h"
+#include "mc21a.h"
+
+/***********************************************************************
+* btf_store_a_cols - store pattern of matrix A in column-wise format
+*
+* This routine stores the pattern (that is, only indices of non-zero
+* elements) of the original matrix A in column-wise format.
+*
+* On exit the routine returns the number of non-zeros in matrix A. */
+
+int btf_store_a_cols(BTF *btf, int (*col)(void *info, int j, int ind[],
+ double val[]), void *info, int ind[], double val[])
+{ int n = btf->n;
+ SVA *sva = btf->sva;
+ int *sv_ind = sva->ind;
+ int ac_ref = btf->ac_ref;
+ int *ac_ptr = &sva->ptr[ac_ref-1];
+ int *ac_len = &sva->len[ac_ref-1];
+ int j, len, ptr, nnz;
+ nnz = 0;
+ for (j = 1; j <= n; j++)
+ { /* get j-th column */
+ len = col(info, j, ind, val);
+ xassert(0 <= len && len <= n);
+ /* reserve locations for j-th column */
+ if (len > 0)
+ { if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ }
+ sva_reserve_cap(sva, ac_ref+(j-1), len);
+ }
+ /* store pattern of j-th column */
+ ptr = ac_ptr[j];
+ memcpy(&sv_ind[ptr], &ind[1], len * sizeof(int));
+ ac_len[j] = len;
+ nnz += len;
+ }
+ return nnz;
+}
+
+/***********************************************************************
+* btf_make_blocks - permutations to block triangular form
+*
+* This routine analyzes the pattern of the original matrix A and
+* determines permutation matrices P and Q such that A = P * A~* Q,
+* where A~ is an upper block triangular matrix.
+*
+* On exit the routine returns symbolic rank of matrix A. */
+
+int btf_make_blocks(BTF *btf)
+{ int n = btf->n;
+ SVA *sva = btf->sva;
+ int *sv_ind = sva->ind;
+ int *pp_ind = btf->pp_ind;
+ int *pp_inv = btf->pp_inv;
+ int *qq_ind = btf->qq_ind;
+ int *qq_inv = btf->qq_inv;
+ int *beg = btf->beg;
+ int ac_ref = btf->ac_ref;
+ int *ac_ptr = &sva->ptr[ac_ref-1];
+ int *ac_len = &sva->len[ac_ref-1];
+ int i, j, rank, *iperm, *pr, *arp, *cv, *out, *ip, *lenr, *lowl,
+ *numb, *prev;
+ /* determine column permutation matrix M such that matrix A * M
+ * has zero-free diagonal */
+ iperm = qq_inv; /* matrix M */
+ pr = btf->p1_ind; /* working array */
+ arp = btf->p1_inv; /* working array */
+ cv = btf->q1_ind; /* working array */
+ out = btf->q1_inv; /* working array */
+ rank = mc21a(n, sv_ind, ac_ptr, ac_len, iperm, pr, arp, cv, out);
+ xassert(0 <= rank && rank <= n);
+ if (rank < n)
+ { /* A is structurally singular (rank is its symbolic rank) */
+ goto done;
+ }
+ /* build pattern of matrix A * M */
+ ip = pp_ind; /* working array */
+ lenr = qq_ind; /* working array */
+ for (j = 1; j <= n; j++)
+ { ip[j] = ac_ptr[iperm[j]];
+ lenr[j] = ac_len[iperm[j]];
+ }
+ /* determine symmetric permutation matrix S such that matrix
+ * S * (A * M) * S' = A~ is upper block triangular */
+ lowl = btf->p1_ind; /* working array */
+ numb = btf->p1_inv; /* working array */
+ prev = btf->q1_ind; /* working array */
+ btf->num =
+ mc13d(n, sv_ind, ip, lenr, pp_inv, beg, lowl, numb, prev);
+ xassert(beg[1] == 1);
+ beg[btf->num+1] = n+1;
+ /* A * M = S' * A~ * S ==> A = S' * A~ * (S * M') */
+ /* determine permutation matrix P = S' */
+ for (j = 1; j <= n; j++)
+ pp_ind[pp_inv[j]] = j;
+ /* determine permutation matrix Q = S * M' = P' * M' */
+ for (i = 1; i <= n; i++)
+ qq_ind[i] = iperm[pp_inv[i]];
+ for (i = 1; i <= n; i++)
+ qq_inv[qq_ind[i]] = i;
+done: return rank;
+}
+
+/***********************************************************************
+* btf_check_blocks - check structure of matrix A~
+*
+* This routine checks that structure of upper block triangular matrix
+* A~ is correct.
+*
+* NOTE: For testing/debugging only. */
+
+void btf_check_blocks(BTF *btf)
+{ int n = btf->n;
+ SVA *sva = btf->sva;
+ int *sv_ind = sva->ind;
+ int *pp_ind = btf->pp_ind;
+ int *pp_inv = btf->pp_inv;
+ int *qq_ind = btf->qq_ind;
+ int *qq_inv = btf->qq_inv;
+ int num = btf->num;
+ int *beg = btf->beg;
+ int ac_ref = btf->ac_ref;
+ int *ac_ptr = &sva->ptr[ac_ref-1];
+ int *ac_len = &sva->len[ac_ref-1];
+ int i, ii, j, jj, k, size, ptr, end, diag;
+ xassert(n > 0);
+ /* check permutation matrices P and Q */
+ for (k = 1; k <= n; k++)
+ { xassert(1 <= pp_ind[k] && pp_ind[k] <= n);
+ xassert(pp_inv[pp_ind[k]] == k);
+ xassert(1 <= qq_ind[k] && qq_ind[k] <= n);
+ xassert(qq_inv[qq_ind[k]] == k);
+ }
+ /* check that matrix A~ is upper block triangular with non-zero
+ * diagonal */
+ xassert(1 <= num && num <= n);
+ xassert(beg[1] == 1);
+ xassert(beg[num+1] == n+1);
+ /* walk thru blocks of A~ */
+ for (k = 1; k <= num; k++)
+ { /* determine size of k-th block */
+ size = beg[k+1] - beg[k];
+ xassert(size >= 1);
+ /* walk thru columns of k-th block */
+ for (jj = beg[k]; jj < beg[k+1]; jj++)
+ { diag = 0;
+ /* jj-th column of A~ = j-th column of A */
+ j = qq_ind[jj];
+ /* walk thru elements of j-th column of A */
+ ptr = ac_ptr[j];
+ end = ptr + ac_len[j];
+ for (; ptr < end; ptr++)
+ { /* determine row index of a[i,j] */
+ i = sv_ind[ptr];
+ /* i-th row of A = ii-th row of A~ */
+ ii = pp_ind[i];
+ /* a~[ii,jj] should not be below k-th block */
+ xassert(ii < beg[k+1]);
+ if (ii == jj)
+ { /* non-zero diagonal element of A~ encountered */
+ diag = 1;
+ }
+ }
+ xassert(diag);
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* btf_build_a_rows - build matrix A in row-wise format
+*
+* This routine builds the row-wise representation of matrix A in the
+* right part of SVA using its column-wise representation.
+*
+* The working array len should have at least 1+n elements (len[0] is
+* not used). */
+
+void btf_build_a_rows(BTF *btf, int len[/*1+n*/])
+{ int n = btf->n;
+ SVA *sva = btf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int ar_ref = btf->ar_ref;
+ int *ar_ptr = &sva->ptr[ar_ref-1];
+ int *ar_len = &sva->len[ar_ref-1];
+ int ac_ref = btf->ac_ref;
+ int *ac_ptr = &sva->ptr[ac_ref-1];
+ int *ac_len = &sva->len[ac_ref-1];
+ int i, j, end, nnz, ptr, ptr1;
+ /* calculate the number of non-zeros in each row of matrix A and
+ * the total number of non-zeros */
+ nnz = 0;
+ for (i = 1; i <= n; i++)
+ len[i] = 0;
+ for (j = 1; j <= n; j++)
+ { nnz += ac_len[j];
+ for (end = (ptr = ac_ptr[j]) + ac_len[j]; ptr < end; ptr++)
+ len[sv_ind[ptr]]++;
+ }
+ /* we need at least nnz free locations in SVA */
+ if (sva->r_ptr - sva->m_ptr < nnz)
+ { sva_more_space(sva, nnz);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ /* reserve locations for rows of matrix A */
+ for (i = 1; i <= n; i++)
+ { if (len[i] > 0)
+ sva_reserve_cap(sva, ar_ref-1+i, len[i]);
+ ar_len[i] = len[i];
+ }
+ /* walk thru columns of matrix A and build its rows */
+ for (j = 1; j <= n; j++)
+ { for (end = (ptr = ac_ptr[j]) + ac_len[j]; ptr < end; ptr++)
+ { i = sv_ind[ptr];
+ sv_ind[ptr1 = ar_ptr[i] + (--len[i])] = j;
+ sv_val[ptr1] = sv_val[ptr];
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* btf_a_solve - solve system A * x = b
+*
+* This routine solves the system A * x = b, where A is the original
+* matrix.
+*
+* On entry the array b should contain elements of the right-hand size
+* vector b in locations b[1], ..., b[n], where n is the order of the
+* matrix A. On exit the array x will contain elements of the solution
+* vector in locations x[1], ..., x[n]. Note that the array b will be
+* clobbered on exit.
+*
+* The routine also uses locations [1], ..., [max_size] of two working
+* arrays w1 and w2, where max_size is the maximal size of diagonal
+* blocks in BT-factorization (max_size <= n). */
+
+void btf_a_solve(BTF *btf, double b[/*1+n*/], double x[/*1+n*/],
+ double w1[/*1+n*/], double w2[/*1+n*/])
+{ SVA *sva = btf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int *pp_inv = btf->pp_inv;
+ int *qq_ind = btf->qq_ind;
+ int num = btf->num;
+ int *beg = btf->beg;
+ int ac_ref = btf->ac_ref;
+ int *ac_ptr = &sva->ptr[ac_ref-1];
+ int *ac_len = &sva->len[ac_ref-1];
+ double *bb = w1;
+ double *xx = w2;
+ LUF luf;
+ int i, j, jj, k, beg_k, flag;
+ double t;
+ for (k = num; k >= 1; k--)
+ { /* determine order of diagonal block A~[k,k] */
+ luf.n = beg[k+1] - (beg_k = beg[k]);
+ if (luf.n == 1)
+ { /* trivial case */
+ /* solve system A~[k,k] * X[k] = B[k] */
+ t = x[qq_ind[beg_k]] =
+ b[pp_inv[beg_k]] / btf->vr_piv[beg_k];
+ /* substitute X[k] into other equations */
+ if (t != 0.0)
+ { int ptr = ac_ptr[qq_ind[beg_k]];
+ int end = ptr + ac_len[qq_ind[beg_k]];
+ for (; ptr < end; ptr++)
+ b[sv_ind[ptr]] -= sv_val[ptr] * t;
+ }
+ }
+ else
+ { /* general case */
+ /* construct B[k] */
+ flag = 0;
+ for (i = 1; i <= luf.n; i++)
+ { if ((bb[i] = b[pp_inv[i + (beg_k-1)]]) != 0.0)
+ flag = 1;
+ }
+ /* solve system A~[k,k] * X[k] = B[k] */
+ if (!flag)
+ { /* B[k] = 0, so X[k] = 0 */
+ for (j = 1; j <= luf.n; j++)
+ x[qq_ind[j + (beg_k-1)]] = 0.0;
+ continue;
+ }
+ luf.sva = sva;
+ luf.fr_ref = btf->fr_ref + (beg_k-1);
+ luf.fc_ref = btf->fc_ref + (beg_k-1);
+ luf.vr_ref = btf->vr_ref + (beg_k-1);
+ luf.vr_piv = btf->vr_piv + (beg_k-1);
+ luf.vc_ref = btf->vc_ref + (beg_k-1);
+ luf.pp_ind = btf->p1_ind + (beg_k-1);
+ luf.pp_inv = btf->p1_inv + (beg_k-1);
+ luf.qq_ind = btf->q1_ind + (beg_k-1);
+ luf.qq_inv = btf->q1_inv + (beg_k-1);
+ luf_f_solve(&luf, bb);
+ luf_v_solve(&luf, bb, xx);
+ /* store X[k] and substitute it into other equations */
+ for (j = 1; j <= luf.n; j++)
+ { jj = j + (beg_k-1);
+ t = x[qq_ind[jj]] = xx[j];
+ if (t != 0.0)
+ { int ptr = ac_ptr[qq_ind[jj]];
+ int end = ptr + ac_len[qq_ind[jj]];
+ for (; ptr < end; ptr++)
+ b[sv_ind[ptr]] -= sv_val[ptr] * t;
+ }
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* btf_at_solve - solve system A'* x = b
+*
+* This routine solves the system A'* x = b, where A' is a matrix
+* transposed to the original matrix A.
+*
+* On entry the array b should contain elements of the right-hand size
+* vector b in locations b[1], ..., b[n], where n is the order of the
+* matrix A. On exit the array x will contain elements of the solution
+* vector in locations x[1], ..., x[n]. Note that the array b will be
+* clobbered on exit.
+*
+* The routine also uses locations [1], ..., [max_size] of two working
+* arrays w1 and w2, where max_size is the maximal size of diagonal
+* blocks in BT-factorization (max_size <= n). */
+
+void btf_at_solve(BTF *btf, double b[/*1+n*/], double x[/*1+n*/],
+ double w1[/*1+n*/], double w2[/*1+n*/])
+{ SVA *sva = btf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int *pp_inv = btf->pp_inv;
+ int *qq_ind = btf->qq_ind;
+ int num = btf->num;
+ int *beg = btf->beg;
+ int ar_ref = btf->ar_ref;
+ int *ar_ptr = &sva->ptr[ar_ref-1];
+ int *ar_len = &sva->len[ar_ref-1];
+ double *bb = w1;
+ double *xx = w2;
+ LUF luf;
+ int i, j, jj, k, beg_k, flag;
+ double t;
+ for (k = 1; k <= num; k++)
+ { /* determine order of diagonal block A~[k,k] */
+ luf.n = beg[k+1] - (beg_k = beg[k]);
+ if (luf.n == 1)
+ { /* trivial case */
+ /* solve system A~'[k,k] * X[k] = B[k] */
+ t = x[pp_inv[beg_k]] =
+ b[qq_ind[beg_k]] / btf->vr_piv[beg_k];
+ /* substitute X[k] into other equations */
+ if (t != 0.0)
+ { int ptr = ar_ptr[pp_inv[beg_k]];
+ int end = ptr + ar_len[pp_inv[beg_k]];
+ for (; ptr < end; ptr++)
+ b[sv_ind[ptr]] -= sv_val[ptr] * t;
+ }
+ }
+ else
+ { /* general case */
+ /* construct B[k] */
+ flag = 0;
+ for (i = 1; i <= luf.n; i++)
+ { if ((bb[i] = b[qq_ind[i + (beg_k-1)]]) != 0.0)
+ flag = 1;
+ }
+ /* solve system A~'[k,k] * X[k] = B[k] */
+ if (!flag)
+ { /* B[k] = 0, so X[k] = 0 */
+ for (j = 1; j <= luf.n; j++)
+ x[pp_inv[j + (beg_k-1)]] = 0.0;
+ continue;
+ }
+ luf.sva = sva;
+ luf.fr_ref = btf->fr_ref + (beg_k-1);
+ luf.fc_ref = btf->fc_ref + (beg_k-1);
+ luf.vr_ref = btf->vr_ref + (beg_k-1);
+ luf.vr_piv = btf->vr_piv + (beg_k-1);
+ luf.vc_ref = btf->vc_ref + (beg_k-1);
+ luf.pp_ind = btf->p1_ind + (beg_k-1);
+ luf.pp_inv = btf->p1_inv + (beg_k-1);
+ luf.qq_ind = btf->q1_ind + (beg_k-1);
+ luf.qq_inv = btf->q1_inv + (beg_k-1);
+ luf_vt_solve(&luf, bb, xx);
+ luf_ft_solve(&luf, xx);
+ /* store X[k] and substitute it into other equations */
+ for (j = 1; j <= luf.n; j++)
+ { jj = j + (beg_k-1);
+ t = x[pp_inv[jj]] = xx[j];
+ if (t != 0.0)
+ { int ptr = ar_ptr[pp_inv[jj]];
+ int end = ptr + ar_len[pp_inv[jj]];
+ for (; ptr < end; ptr++)
+ b[sv_ind[ptr]] -= sv_val[ptr] * t;
+ }
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* btf_at_solve1 - solve system A'* y = e' to cause growth in y
+*
+* This routine is a special version of btf_at_solve. It solves the
+* system A'* y = e' = e + delta e, where A' is a matrix transposed to
+* the original matrix A, e is the specified right-hand side vector,
+* and delta e is a vector of +1 and -1 chosen to cause growth in the
+* solution vector y.
+*
+* On entry the array e should contain elements of the right-hand size
+* vector e in locations e[1], ..., e[n], where n is the order of the
+* matrix A. On exit the array y will contain elements of the solution
+* vector in locations y[1], ..., y[n]. Note that the array e will be
+* clobbered on exit.
+*
+* The routine also uses locations [1], ..., [max_size] of two working
+* arrays w1 and w2, where max_size is the maximal size of diagonal
+* blocks in BT-factorization (max_size <= n). */
+
+void btf_at_solve1(BTF *btf, double e[/*1+n*/], double y[/*1+n*/],
+ double w1[/*1+n*/], double w2[/*1+n*/])
+{ SVA *sva = btf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int *pp_inv = btf->pp_inv;
+ int *qq_ind = btf->qq_ind;
+ int num = btf->num;
+ int *beg = btf->beg;
+ int ar_ref = btf->ar_ref;
+ int *ar_ptr = &sva->ptr[ar_ref-1];
+ int *ar_len = &sva->len[ar_ref-1];
+ double *ee = w1;
+ double *yy = w2;
+ LUF luf;
+ int i, j, jj, k, beg_k, ptr, end;
+ double e_k, y_k;
+ for (k = 1; k <= num; k++)
+ { /* determine order of diagonal block A~[k,k] */
+ luf.n = beg[k+1] - (beg_k = beg[k]);
+ if (luf.n == 1)
+ { /* trivial case */
+ /* determine E'[k] = E[k] + delta E[k] */
+ e_k = e[qq_ind[beg_k]];
+ e_k = (e_k >= 0.0 ? e_k + 1.0 : e_k - 1.0);
+ /* solve system A~'[k,k] * Y[k] = E[k] */
+ y_k = y[pp_inv[beg_k]] = e_k / btf->vr_piv[beg_k];
+ /* substitute Y[k] into other equations */
+ ptr = ar_ptr[pp_inv[beg_k]];
+ end = ptr + ar_len[pp_inv[beg_k]];
+ for (; ptr < end; ptr++)
+ e[sv_ind[ptr]] -= sv_val[ptr] * y_k;
+ }
+ else
+ { /* general case */
+ /* construct E[k] */
+ for (i = 1; i <= luf.n; i++)
+ ee[i] = e[qq_ind[i + (beg_k-1)]];
+ /* solve system A~'[k,k] * Y[k] = E[k] + delta E[k] */
+ luf.sva = sva;
+ luf.fr_ref = btf->fr_ref + (beg_k-1);
+ luf.fc_ref = btf->fc_ref + (beg_k-1);
+ luf.vr_ref = btf->vr_ref + (beg_k-1);
+ luf.vr_piv = btf->vr_piv + (beg_k-1);
+ luf.vc_ref = btf->vc_ref + (beg_k-1);
+ luf.pp_ind = btf->p1_ind + (beg_k-1);
+ luf.pp_inv = btf->p1_inv + (beg_k-1);
+ luf.qq_ind = btf->q1_ind + (beg_k-1);
+ luf.qq_inv = btf->q1_inv + (beg_k-1);
+ luf_vt_solve1(&luf, ee, yy);
+ luf_ft_solve(&luf, yy);
+ /* store Y[k] and substitute it into other equations */
+ for (j = 1; j <= luf.n; j++)
+ { jj = j + (beg_k-1);
+ y_k = y[pp_inv[jj]] = yy[j];
+ ptr = ar_ptr[pp_inv[jj]];
+ end = ptr + ar_len[pp_inv[jj]];
+ for (; ptr < end; ptr++)
+ e[sv_ind[ptr]] -= sv_val[ptr] * y_k;
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* btf_estimate_norm - estimate 1-norm of inv(A)
+*
+* This routine estimates 1-norm of inv(A) by one step of inverse
+* iteration for the small singular vector as described in [1]. This
+* involves solving two systems of equations:
+*
+* A'* y = e,
+*
+* A * z = y,
+*
+* where A' is a matrix transposed to A, and e is a vector of +1 and -1
+* chosen to cause growth in y. Then
+*
+* estimate 1-norm of inv(A) = (1-norm of z) / (1-norm of y)
+*
+* REFERENCES
+*
+* 1. G.E.Forsythe, M.A.Malcolm, C.B.Moler. Computer Methods for
+* Mathematical Computations. Prentice-Hall, Englewood Cliffs, N.J.,
+* pp. 30-62 (subroutines DECOMP and SOLVE). */
+
+double btf_estimate_norm(BTF *btf, double w1[/*1+n*/], double
+ w2[/*1+n*/], double w3[/*1+n*/], double w4[/*1+n*/])
+{ int n = btf->n;
+ double *e = w1;
+ double *y = w2;
+ double *z = w1;
+ int i;
+ double y_norm, z_norm;
+ /* compute y = inv(A') * e to cause growth in y */
+ for (i = 1; i <= n; i++)
+ e[i] = 0.0;
+ btf_at_solve1(btf, e, y, w3, w4);
+ /* compute 1-norm of y = sum |y[i]| */
+ y_norm = 0.0;
+ for (i = 1; i <= n; i++)
+ y_norm += (y[i] >= 0.0 ? +y[i] : -y[i]);
+ /* compute z = inv(A) * y */
+ btf_a_solve(btf, y, z, w3, w4);
+ /* compute 1-norm of z = sum |z[i]| */
+ z_norm = 0.0;
+ for (i = 1; i <= n; i++)
+ z_norm += (z[i] >= 0.0 ? +z[i] : -z[i]);
+ /* estimate 1-norm of inv(A) = (1-norm of z) / (1-norm of y) */
+ return z_norm / y_norm;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/btf.h b/test/monniaux/glpk-4.65/src/bflib/btf.h
new file mode 100644
index 00000000..3f1b5926
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/btf.h
@@ -0,0 +1,207 @@
+/* btf.h (sparse block triangular LU-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2013-2014 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/>.
+***********************************************************************/
+
+#ifndef BTF_H
+#define BTF_H
+
+#include "sva.h"
+
+/***********************************************************************
+* The structure BTF describes BT-factorization, which is sparse block
+* triangular LU-factorization.
+*
+* The BT-factorization has the following format:
+*
+* A = P * A~ * Q, (1)
+*
+* where A is a given (unsymmetric) square matrix, A~ is an upper block
+* triangular matrix (see below), P and Q are permutation matrices. All
+* the matrices have the same order n.
+*
+* The matrix A~, which is a permuted version of the original matrix A,
+* has the following structure:
+*
+* A~[1,1] A~[1,2] ... A~[1,num-1] A~[1,num]
+*
+* A~[2,2] ... A~[2,num-1] A~[2,num]
+*
+* . . . . . . . . . (2)
+*
+* A~[num-1,num-1] A~[num-1,num]
+*
+* A~[num,num]
+*
+* where A~[i,j] is a submatrix called a "block," num is the number of
+* blocks. Each diagonal block A~[k,k] is a non-singular square matrix,
+* and each subdiagonal block A~[i,j], i > j, is a zero submatrix, thus
+* A~ is an upper block triangular matrix.
+*
+* Permutation matrices P and Q are stored in ordinary arrays in both
+* row- and column-like formats.
+*
+* The original matrix A is stored in both row- and column-wise sparse
+* formats in the associated sparse vector area (SVA). Should note that
+* elements of all diagonal blocks A~[k,k] in matrix A are set to zero
+* (i.e. removed), so only elements of non-diagonal blocks are stored.
+*
+* Each diagonal block A~[k,k], 1 <= k <= num, is stored in the form of
+* LU-factorization (see the module LUF). */
+
+typedef struct BTF BTF;
+
+struct BTF
+{ /* sparse block triangular LU-factorization */
+ int n;
+ /* order of matrices A, A~, P, Q */
+ SVA *sva;
+ /* associated sparse vector area used to store rows and columns
+ * of matrix A as well as sparse vectors for LU-factorizations of
+ * all diagonal blocks A~[k,k] */
+ /*--------------------------------------------------------------*/
+ /* matrix P */
+ int *pp_ind; /* int pp_ind[1+n]; */
+ /* pp_ind[i] = j means that P[i,j] = 1 */
+ int *pp_inv; /* int pp_inv[1+n]; */
+ /* pp_inv[j] = i means that P[i,j] = 1 */
+ /* if i-th row of matrix A is i'-th row of matrix A~, then
+ * pp_ind[i] = i' and pp_inv[i'] = i */
+ /*--------------------------------------------------------------*/
+ /* matrix Q */
+ int *qq_ind; /* int qq_ind[1+n]; */
+ /* qq_ind[i] = j means that Q[i,j] = 1 */
+ int *qq_inv; /* int qq_inv[1+n]; */
+ /* qq_inv[j] = i means that Q[i,j] = 1 */
+ /* if j-th column of matrix A is j'-th column of matrix A~, then
+ * qq_ind[j'] = j and qq_inv[j] = j' */
+ /*--------------------------------------------------------------*/
+ /* block triangular structure of matrix A~ */
+ int num;
+ /* number of diagonal blocks, 1 <= num <= n */
+ int *beg; /* int beg[1+num+1]; */
+ /* beg[0] is not used;
+ * beg[k], 1 <= k <= num, is index of first row/column of k-th
+ * block of matrix A~;
+ * beg[num+1] is always n+1;
+ * note that order (size) of k-th diagonal block can be computed
+ * as beg[k+1] - beg[k] */
+ /*--------------------------------------------------------------*/
+ /* original matrix A in row-wise format */
+ /* NOTE: elements of all diagonal blocks A~[k,k] are removed */
+ int ar_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ * row of matrix A */
+#if 0 + 0
+ int *ar_ptr = &sva->ptr[ar_ref-1];
+ /* ar_ptr[0] is not used;
+ * ar_ptr[i], 1 <= i <= n, is pointer to i-th row in SVA */
+ int *ar_len = &sva->ptr[ar_ref-1];
+ /* ar_len[0] is not used;
+ * ar_len[i], 1 <= i <= n, is length of i-th row */
+#endif
+ /*--------------------------------------------------------------*/
+ /* original matrix A in column-wise format */
+ /* NOTE: elements of all diagonal blocks A~[k,k] are removed */
+ int ac_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ * column of matrix A */
+#if 0 + 0
+ int *ac_ptr = &sva->ptr[ac_ref-1];
+ /* ac_ptr[0] is not used;
+ * ac_ptr[j], 1 <= j <= n, is pointer to j-th column in SVA */
+ int *ac_len = &sva->ptr[ac_ref-1];
+ /* ac_len[0] is not used;
+ * ac_len[j], 1 <= j <= n, is length of j-th column */
+#endif
+ /*--------------------------------------------------------------*/
+ /* LU-factorizations of diagonal blocks A~[k,k] */
+ /* to decrease overhead expenses similar arrays for all LUFs are
+ * packed into a single array; for example, elements fr_ptr[1],
+ * ..., fr_ptr[n1], where n1 = beg[2] - beg[1], are related to
+ * LUF for first diagonal block A~[1,1], elements fr_ptr[n1+1],
+ * ..., fr_ptr[n1+n2], where n2 = beg[3] - beg[2], are related to
+ * LUF for second diagonal block A~[2,2], etc.; in other words,
+ * elements related to LUF for k-th diagonal block A~[k,k] have
+ * indices beg[k], beg[k]+1, ..., beg[k+1]-1 */
+ /* for details about LUF see description of the LUF module */
+ int fr_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ row of matrix F for first diagonal block A~[1,1] */
+ int fc_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ column of matrix F for first diagonal block A~[1,1] */
+ int vr_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ row of matrix V for first diagonal block A~[1,1] */
+ double *vr_piv; /* double vr_piv[1+n]; */
+ /* vr_piv[0] is not used;
+ vr_piv[1,...,n] are pivot elements for all diagonal blocks */
+ int vc_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ column of matrix V for first diagonal block A~[1,1] */
+ int *p1_ind; /* int p1_ind[1+n]; */
+ int *p1_inv; /* int p1_inv[1+n]; */
+ int *q1_ind; /* int q1_ind[1+n]; */
+ int *q1_inv; /* int q1_inv[1+n]; */
+ /* permutation matrices P and Q for all diagonal blocks */
+};
+
+#define btf_store_a_cols _glp_btf_store_a_cols
+int btf_store_a_cols(BTF *btf, int (*col)(void *info, int j, int ind[],
+ double val[]), void *info, int ind[], double val[]);
+/* store pattern of matrix A in column-wise format */
+
+#define btf_make_blocks _glp_btf_make_blocks
+int btf_make_blocks(BTF *btf);
+/* permutations to block triangular form */
+
+#define btf_check_blocks _glp_btf_check_blocks
+void btf_check_blocks(BTF *btf);
+/* check structure of matrix A~ */
+
+#define btf_build_a_rows _glp_btf_build_a_rows
+void btf_build_a_rows(BTF *btf, int len[/*1+n*/]);
+/* build matrix A in row-wise format */
+
+#define btf_a_solve _glp_btf_a_solve
+void btf_a_solve(BTF *btf, double b[/*1+n*/], double x[/*1+n*/],
+ double w1[/*1+n*/], double w2[/*1+n*/]);
+/* solve system A * x = b */
+
+#define btf_at_solve _glp_btf_at_solve
+void btf_at_solve(BTF *btf, double b[/*1+n*/], double x[/*1+n*/],
+ double w1[/*1+n*/], double w2[/*1+n*/]);
+/* solve system A'* x = b */
+
+#define btf_at_solve1 _glp_btf_at_solve1
+void btf_at_solve1(BTF *btf, double e[/*1+n*/], double y[/*1+n*/],
+ double w1[/*1+n*/], double w2[/*1+n*/]);
+/* solve system A'* y = e' to cause growth in y */
+
+#define btf_estimate_norm _glp_btf_estimate_norm
+double btf_estimate_norm(BTF *btf, double w1[/*1+n*/], double
+ w2[/*1+n*/], double w3[/*1+n*/], double w4[/*1+n*/]);
+/* estimate 1-norm of inv(A) */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/btfint.c b/test/monniaux/glpk-4.65/src/bflib/btfint.c
new file mode 100644
index 00000000..378d3a81
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/btfint.c
@@ -0,0 +1,407 @@
+/* btfint.c (interface to BT-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2013-2014 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "btfint.h"
+
+BTFINT *btfint_create(void)
+{ /* create interface to BT-factorization */
+ BTFINT *fi;
+ fi = talloc(1, BTFINT);
+ fi->n_max = 0;
+ fi->valid = 0;
+ fi->sva = NULL;
+ fi->btf = NULL;
+ fi->sgf = NULL;
+ fi->sva_n_max = fi->sva_size = 0;
+ fi->delta_n0 = fi->delta_n = 0;
+ fi->sgf_piv_tol = 0.10;
+ fi->sgf_piv_lim = 4;
+ fi->sgf_suhl = 1;
+ fi->sgf_eps_tol = DBL_EPSILON;
+ return fi;
+}
+
+static void factorize_triv(BTFINT *fi, int k, int (*col)(void *info,
+ int j, int ind[], double val[]), void *info)
+{ /* compute LU-factorization of diagonal block A~[k,k] and store
+ * corresponding columns of matrix A except elements of A~[k,k]
+ * (trivial case when the block has unity size) */
+ SVA *sva = fi->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ BTF *btf = fi->btf;
+ int *pp_inv = btf->pp_inv;
+ int *qq_ind = btf->qq_ind;
+ int *beg = btf->beg;
+ int ac_ref = btf->ac_ref;
+ int *ac_ptr = &sva->ptr[ac_ref-1];
+ int *ac_len = &sva->len[ac_ref-1];
+ SGF *sgf = fi->sgf;
+ int *ind = (int *)sgf->vr_max; /* working array */
+ double *val = sgf->work; /* working array */
+ int i, j, t, len, ptr, beg_k;
+ /* diagonal block A~[k,k] has the only element in matrix A~,
+ * which is a~[beg[k],beg[k]] = a[i,j] */
+ beg_k = beg[k];
+ i = pp_inv[beg_k];
+ j = qq_ind[beg_k];
+ /* get j-th column of A */
+ len = col(info, j, ind, val);
+ /* find element a[i,j] = a~[beg[k],beg[k]] in j-th column */
+ for (t = 1; t <= len; t++)
+ { if (ind[t] == i)
+ break;
+ }
+ xassert(t <= len);
+ /* compute LU-factorization of diagonal block A~[k,k], where
+ * F = (1), V = (a[i,j]), P = Q = (1) (see the module LUF) */
+#if 1 /* FIXME */
+ xassert(val[t] != 0.0);
+#endif
+ btf->vr_piv[beg_k] = val[t];
+ btf->p1_ind[beg_k] = btf->p1_inv[beg_k] = 1;
+ btf->q1_ind[beg_k] = btf->q1_inv[beg_k] = 1;
+ /* remove element a[i,j] = a~[beg[k],beg[k]] from j-th column */
+ memmove(&ind[t], &ind[t+1], (len-t) * sizeof(int));
+ memmove(&val[t], &val[t+1], (len-t) * sizeof(double));
+ len--;
+ /* and store resulting j-th column of A into BTF */
+ if (len > 0)
+ { /* reserve locations for j-th column of A */
+ if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_reserve_cap(sva, ac_ref+(j-1), len);
+ /* store j-th column of A (except elements of A~[k,k]) */
+ ptr = ac_ptr[j];
+ memcpy(&sv_ind[ptr], &ind[1], len * sizeof(int));
+ memcpy(&sv_val[ptr], &val[1], len * sizeof(double));
+ ac_len[j] = len;
+ }
+ return;
+}
+
+static int factorize_block(BTFINT *fi, int k, int (*col)(void *info,
+ int j, int ind[], double val[]), void *info)
+{ /* compute LU-factorization of diagonal block A~[k,k] and store
+ * corresponding columns of matrix A except elements of A~[k,k]
+ * (general case) */
+ SVA *sva = fi->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ BTF *btf = fi->btf;
+ int *pp_ind = btf->pp_ind;
+ int *qq_ind = btf->qq_ind;
+ int *beg = btf->beg;
+ int ac_ref = btf->ac_ref;
+ int *ac_ptr = &sva->ptr[ac_ref-1];
+ int *ac_len = &sva->len[ac_ref-1];
+ SGF *sgf = fi->sgf;
+ int *ind = (int *)sgf->vr_max; /* working array */
+ double *val = sgf->work; /* working array */
+ LUF luf;
+ int *vc_ptr, *vc_len, *vc_cap;
+ int i, ii, j, jj, t, len, cnt, ptr, beg_k;
+ /* construct fake LUF for LU-factorization of A~[k,k] */
+ sgf->luf = &luf;
+ luf.n = beg[k+1] - (beg_k = beg[k]);
+ luf.sva = sva;
+ luf.fr_ref = btf->fr_ref + (beg_k-1);
+ luf.fc_ref = btf->fc_ref + (beg_k-1);
+ luf.vr_ref = btf->vr_ref + (beg_k-1);
+ luf.vr_piv = btf->vr_piv + (beg_k-1);
+ luf.vc_ref = btf->vc_ref + (beg_k-1);
+ luf.pp_ind = btf->p1_ind + (beg_k-1);
+ luf.pp_inv = btf->p1_inv + (beg_k-1);
+ luf.qq_ind = btf->q1_ind + (beg_k-1);
+ luf.qq_inv = btf->q1_inv + (beg_k-1);
+ /* process columns of k-th block of matrix A~ */
+ vc_ptr = &sva->ptr[luf.vc_ref-1];
+ vc_len = &sva->len[luf.vc_ref-1];
+ vc_cap = &sva->cap[luf.vc_ref-1];
+ for (jj = 1; jj <= luf.n; jj++)
+ { /* jj-th column of A~ = j-th column of A */
+ j = qq_ind[jj + (beg_k-1)];
+ /* get j-th column of A */
+ len = col(info, j, ind, val);
+ /* move elements of diagonal block A~[k,k] to the beginning of
+ * the column list */
+ cnt = 0;
+ for (t = 1; t <= len; t++)
+ { /* i = row index of element a[i,j] */
+ i = ind[t];
+ /* i-th row of A = ii-th row of A~ */
+ ii = pp_ind[i];
+ if (ii >= beg_k)
+ { /* a~[ii,jj] = a[i,j] is in diagonal block A~[k,k] */
+ double temp;
+ cnt++;
+ ind[t] = ind[cnt];
+ ind[cnt] = ii - (beg_k-1); /* local index */
+ temp = val[t], val[t] = val[cnt], val[cnt] = temp;
+ }
+ }
+ /* first cnt elements in the column list give jj-th column of
+ * diagonal block A~[k,k], which is initial matrix V in LUF */
+ /* enlarge capacity of jj-th column of V = A~[k,k] */
+ if (vc_cap[jj] < cnt)
+ { if (sva->r_ptr - sva->m_ptr < cnt)
+ { sva_more_space(sva, cnt);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_enlarge_cap(sva, luf.vc_ref+(jj-1), cnt, 0);
+ }
+ /* store jj-th column of V = A~[k,k] */
+ ptr = vc_ptr[jj];
+ memcpy(&sv_ind[ptr], &ind[1], cnt * sizeof(int));
+ memcpy(&sv_val[ptr], &val[1], cnt * sizeof(double));
+ vc_len[jj] = cnt;
+ /* other (len-cnt) elements in the column list are stored in
+ * j-th column of the original matrix A */
+ len -= cnt;
+ if (len > 0)
+ { /* reserve locations for j-th column of A */
+ if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_reserve_cap(sva, ac_ref-1+j, len);
+ /* store j-th column of A (except elements of A~[k,k]) */
+ ptr = ac_ptr[j];
+ memcpy(&sv_ind[ptr], &ind[cnt+1], len * sizeof(int));
+ memcpy(&sv_val[ptr], &val[cnt+1], len * sizeof(double));
+ ac_len[j] = len;
+ }
+ }
+ /* compute LU-factorization of diagonal block A~[k,k]; may note
+ * that A~[k,k] is irreducible (strongly connected), so singleton
+ * phase will have no effect */
+ k = sgf_factorize(sgf, 0 /* disable singleton phase */);
+ /* now left (dynamic) part of SVA should be empty (wichtig!) */
+ xassert(sva->m_ptr == 1);
+ return k;
+}
+
+int btfint_factorize(BTFINT *fi, int n, int (*col)(void *info, int j,
+ int ind[], double val[]), void *info)
+{ /* compute BT-factorization of specified matrix A */
+ SVA *sva;
+ BTF *btf;
+ SGF *sgf;
+ int k, rank;
+ xassert(n > 0);
+ fi->valid = 0;
+ /* create sparse vector area (SVA), if necessary */
+ sva = fi->sva;
+ if (sva == NULL)
+ { int sva_n_max = fi->sva_n_max;
+ int sva_size = fi->sva_size;
+ if (sva_n_max == 0)
+ sva_n_max = 6 * n;
+ if (sva_size == 0)
+ sva_size = 10 * n;
+ sva = fi->sva = sva_create_area(sva_n_max, sva_size);
+ }
+ /* allocate/reallocate underlying objects, if necessary */
+ if (fi->n_max < n)
+ { int n_max = fi->n_max;
+ if (n_max == 0)
+ n_max = fi->n_max = n + fi->delta_n0;
+ else
+ n_max = fi->n_max = n + fi->delta_n;
+ xassert(n_max >= n);
+ /* allocate/reallocate block triangular factorization (BTF) */
+ btf = fi->btf;
+ if (btf == NULL)
+ { btf = fi->btf = talloc(1, BTF);
+ memset(btf, 0, sizeof(BTF));
+ btf->sva = sva;
+ }
+ else
+ { tfree(btf->pp_ind);
+ tfree(btf->pp_inv);
+ tfree(btf->qq_ind);
+ tfree(btf->qq_inv);
+ tfree(btf->beg);
+ tfree(btf->vr_piv);
+ tfree(btf->p1_ind);
+ tfree(btf->p1_inv);
+ tfree(btf->q1_ind);
+ tfree(btf->q1_inv);
+ }
+ btf->pp_ind = talloc(1+n_max, int);
+ btf->pp_inv = talloc(1+n_max, int);
+ btf->qq_ind = talloc(1+n_max, int);
+ btf->qq_inv = talloc(1+n_max, int);
+ btf->beg = talloc(1+n_max+1, int);
+ btf->vr_piv = talloc(1+n_max, double);
+ btf->p1_ind = talloc(1+n_max, int);
+ btf->p1_inv = talloc(1+n_max, int);
+ btf->q1_ind = talloc(1+n_max, int);
+ btf->q1_inv = talloc(1+n_max, int);
+ /* allocate/reallocate factorizer workspace (SGF) */
+ /* (note that for SGF we could use the size of largest block
+ * rather than n_max) */
+ sgf = fi->sgf;
+ sgf = fi->sgf;
+ if (sgf == NULL)
+ { sgf = fi->sgf = talloc(1, SGF);
+ memset(sgf, 0, sizeof(SGF));
+ }
+ else
+ { tfree(sgf->rs_head);
+ tfree(sgf->rs_prev);
+ tfree(sgf->rs_next);
+ tfree(sgf->cs_head);
+ tfree(sgf->cs_prev);
+ tfree(sgf->cs_next);
+ tfree(sgf->vr_max);
+ tfree(sgf->flag);
+ tfree(sgf->work);
+ }
+ sgf->rs_head = talloc(1+n_max, int);
+ sgf->rs_prev = talloc(1+n_max, int);
+ sgf->rs_next = talloc(1+n_max, int);
+ sgf->cs_head = talloc(1+n_max, int);
+ sgf->cs_prev = talloc(1+n_max, int);
+ sgf->cs_next = talloc(1+n_max, int);
+ sgf->vr_max = talloc(1+n_max, double);
+ sgf->flag = talloc(1+n_max, char);
+ sgf->work = talloc(1+n_max, double);
+ }
+ btf = fi->btf;
+ btf->n = n;
+ sgf = fi->sgf;
+#if 1 /* FIXME */
+ /* initialize SVA */
+ sva->n = 0;
+ sva->m_ptr = 1;
+ sva->r_ptr = sva->size + 1;
+ sva->head = sva->tail = 0;
+#endif
+ /* store pattern of original matrix A in column-wise format */
+ btf->ac_ref = sva_alloc_vecs(btf->sva, btf->n);
+ btf_store_a_cols(btf, col, info, btf->pp_ind, btf->vr_piv);
+#ifdef GLP_DEBUG
+ sva_check_area(sva);
+#endif
+ /* analyze pattern of original matrix A and determine permutation
+ * matrices P and Q such that A = P * A~* Q, where A~ is an upper
+ * block triangular matrix */
+ rank = btf_make_blocks(btf);
+ if (rank != n)
+ { /* original matrix A is structurally singular */
+ return 1;
+ }
+#ifdef GLP_DEBUG
+ btf_check_blocks(btf);
+#endif
+#if 1 /* FIXME */
+ /* initialize SVA */
+ sva->n = 0;
+ sva->m_ptr = 1;
+ sva->r_ptr = sva->size + 1;
+ sva->head = sva->tail = 0;
+#endif
+ /* allocate sparse vectors in SVA */
+ btf->ar_ref = sva_alloc_vecs(btf->sva, btf->n);
+ btf->ac_ref = sva_alloc_vecs(btf->sva, btf->n);
+ btf->fr_ref = sva_alloc_vecs(btf->sva, btf->n);
+ btf->fc_ref = sva_alloc_vecs(btf->sva, btf->n);
+ btf->vr_ref = sva_alloc_vecs(btf->sva, btf->n);
+ btf->vc_ref = sva_alloc_vecs(btf->sva, btf->n);
+ /* setup factorizer control parameters */
+ sgf->updat = 0; /* wichtig! */
+ sgf->piv_tol = fi->sgf_piv_tol;
+ sgf->piv_lim = fi->sgf_piv_lim;
+ sgf->suhl = fi->sgf_suhl;
+ sgf->eps_tol = fi->sgf_eps_tol;
+ /* compute LU-factorizations of diagonal blocks A~[k,k] and also
+ * store corresponding columns of matrix A except elements of all
+ * blocks A~[k,k] */
+ for (k = 1; k <= btf->num; k++)
+ { if (btf->beg[k+1] - btf->beg[k] == 1)
+ { /* trivial case (A~[k,k] has unity order) */
+ factorize_triv(fi, k, col, info);
+ }
+ else
+ { /* general case */
+ if (factorize_block(fi, k, col, info) != 0)
+ return 2; /* factorization of A~[k,k] failed */
+ }
+ }
+#ifdef GLP_DEBUG
+ sva_check_area(sva);
+#endif
+ /* build row-wise representation of matrix A */
+ btf_build_a_rows(fi->btf, fi->sgf->rs_head);
+#ifdef GLP_DEBUG
+ sva_check_area(sva);
+#endif
+ /* BT-factorization has been successfully computed */
+ fi->valid = 1;
+ return 0;
+}
+
+void btfint_delete(BTFINT *fi)
+{ /* delete interface to BT-factorization */
+ SVA *sva = fi->sva;
+ BTF *btf = fi->btf;
+ SGF *sgf = fi->sgf;
+ if (sva != NULL)
+ sva_delete_area(sva);
+ if (btf != NULL)
+ { tfree(btf->pp_ind);
+ tfree(btf->pp_inv);
+ tfree(btf->qq_ind);
+ tfree(btf->qq_inv);
+ tfree(btf->beg);
+ tfree(btf->vr_piv);
+ tfree(btf->p1_ind);
+ tfree(btf->p1_inv);
+ tfree(btf->q1_ind);
+ tfree(btf->q1_inv);
+ tfree(btf);
+ }
+ if (sgf != NULL)
+ { tfree(sgf->rs_head);
+ tfree(sgf->rs_prev);
+ tfree(sgf->rs_next);
+ tfree(sgf->cs_head);
+ tfree(sgf->cs_prev);
+ tfree(sgf->cs_next);
+ tfree(sgf->vr_max);
+ tfree(sgf->flag);
+ tfree(sgf->work);
+ tfree(sgf);
+ }
+ tfree(fi);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/btfint.h b/test/monniaux/glpk-4.65/src/bflib/btfint.h
new file mode 100644
index 00000000..8d0e70e2
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/btfint.h
@@ -0,0 +1,73 @@
+/* btfint.h (interface to BT-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2013-2014 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/>.
+***********************************************************************/
+
+#ifndef BTFINT_H
+#define BTFINT_H
+
+#include "btf.h"
+#include "sgf.h"
+
+typedef struct BTFINT BTFINT;
+
+struct BTFINT
+{ /* interface to BT-factorization */
+ int n_max;
+ /* maximal value of n (increased automatically) */
+ int valid;
+ /* factorization is valid only if this flag is set */
+ SVA *sva;
+ /* sparse vector area (SVA) */
+ BTF *btf;
+ /* sparse block triangular LU-factorization */
+ SGF *sgf;
+ /* sparse Gaussian factorizer workspace */
+ /*--------------------------------------------------------------*/
+ /* control parameters */
+ int sva_n_max, sva_size;
+ /* parameters passed to sva_create_area */
+ int delta_n0, delta_n;
+ /* if n_max = 0, set n_max = n + delta_n0
+ * if n_max < n, set n_max = n + delta_n */
+ double sgf_piv_tol;
+ int sgf_piv_lim;
+ int sgf_suhl;
+ double sgf_eps_tol;
+ /* factorizer control parameters */
+};
+
+#define btfint_create _glp_btfint_create
+BTFINT *btfint_create(void);
+/* create interface to BT-factorization */
+
+#define btfint_factorize _glp_btfint_factorize
+int btfint_factorize(BTFINT *fi, int n, int (*col)(void *info, int j,
+ int ind[], double val[]), void *info);
+/* compute BT-factorization of specified matrix A */
+
+#define btfint_delete _glp_btfint_delete
+void btfint_delete(BTFINT *fi);
+/* delete interface to BT-factorization */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/fhv.c b/test/monniaux/glpk-4.65/src/bflib/fhv.c
new file mode 100644
index 00000000..e4bdf855
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/fhv.c
@@ -0,0 +1,586 @@
+/* fhv.c (sparse updatable FHV-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "fhv.h"
+
+/***********************************************************************
+* fhv_ft_update - update FHV-factorization (Forrest-Tomlin)
+*
+* This routine updates FHV-factorization of the original matrix A
+* after replacing its j-th column by a new one. The routine is based
+* on the method proposed by Forrest and Tomlin [1].
+*
+* The parameter q specifies the number of column of A, which has been
+* replaced, 1 <= q <= n, where n is the order of A.
+*
+* Row indices and numerical values of non-zero elements of the new
+* j-th column of A should be placed in locations aq_ind[1], ...,
+* aq_ind[aq_len] and aq_val[1], ..., aq_val[aq_len], respectively,
+* where aq_len is the number of non-zeros. Neither zero nor duplicate
+* elements are allowed.
+*
+* The working arrays ind, val, and work should have at least 1+n
+* elements (0-th elements are not used).
+*
+* RETURNS
+*
+* 0 The factorization has been successfully updated.
+*
+* 1 New matrix U = P'* V * Q' is upper triangular with zero diagonal
+* element u[s,s]. (Elimination was not performed.)
+*
+* 2 New matrix U = P'* V * Q' is upper triangular, and its diagonal
+* element u[s,s] or u[t,t] is too small in magnitude. (Elimination
+* was not performed.)
+*
+* 3 The same as 2, but after performing elimination.
+*
+* 4 The factorization has not been updated, because maximal number of
+* updates has been reached.
+*
+* 5 Accuracy test failed for the updated factorization.
+*
+* BACKGROUND
+*
+* The routine is based on the updating method proposed by Forrest and
+* Tomlin [1].
+*
+* Let q-th column of the original matrix A have been replaced by new
+* column A[q]. Then, to keep the equality A = F * H * V, q-th column
+* of matrix V should be replaced by column V[q] = inv(F * H) * A[q].
+* From the standpoint of matrix U = P'* V * Q' such replacement is
+* equivalent to replacement of s-th column of matrix U, where s is
+* determined from q by permutation matrix Q. Thus, matrix U loses its
+* upper triangular form and becomes the following:
+*
+* 1 s t n
+* 1 x x * x x x x x x
+* . x * x x x x x x
+* s . . * x x x x x x
+* . . * x x x x x x
+* . . * . x x x x x
+* . . * . . x x x x
+* t . . * . . . x x x
+* . . . . . . . x x
+* n . . . . . . . . x
+*
+* where t is largest row index of a non-zero element in s-th column.
+*
+* The routine makes matrix U upper triangular as follows. First, it
+* moves rows and columns s+1, ..., t by one position to the left and
+* upwards, resp., and moves s-th row and s-th column to position t.
+* Due to such symmetric permutations matrix U becomes the following
+* (note that all diagonal elements remain on the diagonal, and element
+* u[s,s] becomes u[t,t]):
+*
+* 1 s t n
+* 1 x x x x x x * x x
+* . x x x x x * x x
+* s . . x x x x * x x
+* . . . x x x * x x
+* . . . . x x * x x
+* . . . . . x * x x
+* t . . x x x x * x x
+* . . . . . . . x x
+* n . . . . . . . . x
+*
+* Then the routine performs gaussian elimination to eliminate
+* subdiagonal elements u[t,s], ..., u[t,t-1] using diagonal elements
+* u[s,s], ..., u[t-1,t-1] as pivots. During the elimination process
+* the routine permutes neither rows nor columns, so only t-th row is
+* changed. Should note that actually all operations are performed on
+* matrix V = P * U * Q, since matrix U is not stored.
+*
+* To keep the equality A = F * H * V, the routine appends new row-like
+* factor H[k] to matrix H, and every time it applies elementary
+* gaussian transformation to eliminate u[t,j'] = v[p,j] using pivot
+* u[j',j'] = v[i,j], it also adds new element f[p,j] = v[p,j] / v[i,j]
+* (gaussian multiplier) to factor H[k], which initially is a unity
+* matrix. At the end of elimination process the row-like factor H[k]
+* may look as follows:
+*
+* 1 n 1 s t n
+* 1 1 . . . . . . . . 1 1 . . . . . . . .
+* . 1 . . . . . . . . 1 . . . . . . .
+* . . 1 . . . . . . s . . 1 . . . . . .
+* p . x x 1 . x . x . . . . 1 . . . . .
+* . . . . 1 . . . . . . . . 1 . . . .
+* . . . . . 1 . . . . . . . . 1 . . .
+* . . . . . . 1 . . t . . x x x x 1 . .
+* . . . . . . . 1 . . . . . . . . 1 .
+* n . . . . . . . . 1 n . . . . . . . . 1
+*
+* H[k] inv(P) * H[k] * P
+*
+* If, however, s = t, no elimination is needed, in which case no new
+* row-like factor is created.
+*
+* REFERENCES
+*
+* 1. J.J.H.Forrest and J.A.Tomlin, "Updated triangular factors of the
+* basis to maintain sparsity in the product form simplex method,"
+* Math. Prog. 2 (1972), pp. 263-78. */
+
+int fhv_ft_update(FHV *fhv, int q, int aq_len, const int aq_ind[],
+ const double aq_val[], int ind[/*1+n*/], double val[/*1+n*/],
+ double work[/*1+n*/])
+{ LUF *luf = fhv->luf;
+ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int *vr_cap = &sva->cap[vr_ref-1];
+ double *vr_piv = luf->vr_piv;
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int *vc_cap = &sva->cap[vc_ref-1];
+ int *pp_ind = luf->pp_ind;
+ int *pp_inv = luf->pp_inv;
+ int *qq_ind = luf->qq_ind;
+ int *qq_inv = luf->qq_inv;
+ int *hh_ind = fhv->hh_ind;
+ int hh_ref = fhv->hh_ref;
+ int *hh_ptr = &sva->ptr[hh_ref-1];
+ int *hh_len = &sva->len[hh_ref-1];
+#if 1 /* FIXME */
+ const double eps_tol = DBL_EPSILON;
+ const double vpq_tol = 1e-5;
+ const double err_tol = 1e-10;
+#endif
+ int end, i, i_end, i_ptr, j, j_end, j_ptr, k, len, nnz, p, p_end,
+ p_ptr, ptr, q_end, q_ptr, s, t;
+ double f, vpq, temp;
+ /*--------------------------------------------------------------*/
+ /* replace current q-th column of matrix V by new one */
+ /*--------------------------------------------------------------*/
+ xassert(1 <= q && q <= n);
+ /* convert new q-th column of matrix A to dense format */
+ for (i = 1; i <= n; i++)
+ val[i] = 0.0;
+ xassert(0 <= aq_len && aq_len <= n);
+ for (k = 1; k <= aq_len; k++)
+ { i = aq_ind[k];
+ xassert(1 <= i && i <= n);
+ xassert(val[i] == 0.0);
+ xassert(aq_val[k] != 0.0);
+ val[i] = aq_val[k];
+ }
+ /* compute new q-th column of matrix V:
+ * new V[q] = inv(F * H) * (new A[q]) */
+ luf->pp_ind = fhv->p0_ind;
+ luf->pp_inv = fhv->p0_inv;
+ luf_f_solve(luf, val);
+ luf->pp_ind = pp_ind;
+ luf->pp_inv = pp_inv;
+ fhv_h_solve(fhv, val);
+ /* q-th column of V = s-th column of U */
+ s = qq_inv[q];
+ /* determine row number of element v[p,q] that corresponds to
+ * diagonal element u[s,s] */
+ p = pp_inv[s];
+ /* convert new q-th column of V to sparse format;
+ * element v[p,q] = u[s,s] is not included in the element list
+ * and stored separately */
+ vpq = 0.0;
+ len = 0;
+ for (i = 1; i <= n; i++)
+ { temp = val[i];
+#if 1 /* FIXME */
+ if (-eps_tol < temp && temp < +eps_tol)
+#endif
+ /* nop */;
+ else if (i == p)
+ vpq = temp;
+ else
+ { ind[++len] = i;
+ val[len] = temp;
+ }
+ }
+ /* clear q-th column of matrix V */
+ for (q_end = (q_ptr = vc_ptr[q]) + vc_len[q];
+ q_ptr < q_end; q_ptr++)
+ { /* get row index of v[i,q] */
+ i = sv_ind[q_ptr];
+ /* find and remove v[i,q] from i-th row */
+ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i];
+ sv_ind[i_ptr] != q; i_ptr++)
+ /* nop */;
+ xassert(i_ptr < i_end);
+ sv_ind[i_ptr] = sv_ind[i_end-1];
+ sv_val[i_ptr] = sv_val[i_end-1];
+ vr_len[i]--;
+ }
+ /* now q-th column of matrix V is empty */
+ vc_len[q] = 0;
+ /* put new q-th column of V (except element v[p,q] = u[s,s]) in
+ * column-wise format */
+ if (len > 0)
+ { if (vc_cap[q] < len)
+ { if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_enlarge_cap(sva, vc_ref-1+q, len, 0);
+ }
+ ptr = vc_ptr[q];
+ memcpy(&sv_ind[ptr], &ind[1], len * sizeof(int));
+ memcpy(&sv_val[ptr], &val[1], len * sizeof(double));
+ vc_len[q] = len;
+ }
+ /* put new q-th column of V (except element v[p,q] = u[s,s]) in
+ * row-wise format, and determine largest row number t such that
+ * u[s,t] != 0 */
+ t = (vpq == 0.0 ? 0 : s);
+ for (k = 1; k <= len; k++)
+ { /* get row index of v[i,q] */
+ i = ind[k];
+ /* put v[i,q] to i-th row */
+ if (vr_cap[i] == vr_len[i])
+ { /* reserve extra locations in i-th row to reduce further
+ * relocations of that row */
+#if 1 /* FIXME */
+ int need = vr_len[i] + 5;
+#endif
+ if (sva->r_ptr - sva->m_ptr < need)
+ { sva_more_space(sva, need);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_enlarge_cap(sva, vr_ref-1+i, need, 0);
+ }
+ sv_ind[ptr = vr_ptr[i] + (vr_len[i]++)] = q;
+ sv_val[ptr] = val[k];
+ /* v[i,q] is non-zero; increase t */
+ if (t < pp_ind[i])
+ t = pp_ind[i];
+ }
+ /*--------------------------------------------------------------*/
+ /* check if matrix U is already upper triangular */
+ /*--------------------------------------------------------------*/
+ /* check if there is a spike in s-th column of matrix U, which
+ * is q-th column of matrix V */
+ if (s >= t)
+ { /* no spike; matrix U is already upper triangular */
+ /* store its diagonal element u[s,s] = v[p,q] */
+ vr_piv[p] = vpq;
+ if (s > t)
+ { /* matrix U is structurally singular, because its diagonal
+ * element u[s,s] = v[p,q] is exact zero */
+ xassert(vpq == 0.0);
+ return 1;
+ }
+#if 1 /* FIXME */
+ else if (-vpq_tol < vpq && vpq < +vpq_tol)
+#endif
+ { /* matrix U is not well conditioned, because its diagonal
+ * element u[s,s] = v[p,q] is too small in magnitude */
+ return 2;
+ }
+ else
+ { /* normal case */
+ return 0;
+ }
+ }
+ /*--------------------------------------------------------------*/
+ /* perform implicit symmetric permutations of rows and columns */
+ /* of matrix U */
+ /*--------------------------------------------------------------*/
+ /* currently v[p,q] = u[s,s] */
+ xassert(p == pp_inv[s] && q == qq_ind[s]);
+ for (k = s; k < t; k++)
+ { pp_ind[pp_inv[k] = pp_inv[k+1]] = k;
+ qq_inv[qq_ind[k] = qq_ind[k+1]] = k;
+ }
+ /* now v[p,q] = u[t,t] */
+ pp_ind[pp_inv[t] = p] = qq_inv[qq_ind[t] = q] = t;
+ /*--------------------------------------------------------------*/
+ /* check if matrix U is already upper triangular */
+ /*--------------------------------------------------------------*/
+ /* check if there is a spike in t-th row of matrix U, which is
+ * p-th row of matrix V */
+ for (p_end = (p_ptr = vr_ptr[p]) + vr_len[p];
+ p_ptr < p_end; p_ptr++)
+ { if (qq_inv[sv_ind[p_ptr]] < t)
+ break; /* spike detected */
+ }
+ if (p_ptr == p_end)
+ { /* no spike; matrix U is already upper triangular */
+ /* store its diagonal element u[t,t] = v[p,q] */
+ vr_piv[p] = vpq;
+#if 1 /* FIXME */
+ if (-vpq_tol < vpq && vpq < +vpq_tol)
+#endif
+ { /* matrix U is not well conditioned, because its diagonal
+ * element u[t,t] = v[p,q] is too small in magnitude */
+ return 2;
+ }
+ else
+ { /* normal case */
+ return 0;
+ }
+ }
+ /*--------------------------------------------------------------*/
+ /* copy p-th row of matrix V, which is t-th row of matrix U, to */
+ /* working array */
+ /*--------------------------------------------------------------*/
+ /* copy p-th row of matrix V, including element v[p,q] = u[t,t],
+ * to the working array in dense format and remove these elements
+ * from matrix V; since no pivoting is used, only this row will
+ * change during elimination */
+ for (j = 1; j <= n; j++)
+ work[j] = 0.0;
+ work[q] = vpq;
+ for (p_end = (p_ptr = vr_ptr[p]) + vr_len[p];
+ p_ptr < p_end; p_ptr++)
+ { /* get column index of v[p,j] and store this element to the
+ * working array */
+ work[j = sv_ind[p_ptr]] = sv_val[p_ptr];
+ /* find and remove v[p,j] from j-th column */
+ for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j];
+ sv_ind[j_ptr] != p; j_ptr++)
+ /* nop */;
+ xassert(j_ptr < j_end);
+ sv_ind[j_ptr] = sv_ind[j_end-1];
+ sv_val[j_ptr] = sv_val[j_end-1];
+ vc_len[j]--;
+ }
+ /* now p-th row of matrix V is temporarily empty */
+ vr_len[p] = 0;
+ /*--------------------------------------------------------------*/
+ /* perform gaussian elimination */
+ /*--------------------------------------------------------------*/
+ /* transform p-th row of matrix V stored in working array, which
+ * is t-th row of matrix U, to eliminate subdiagonal elements
+ * u[t,s], ..., u[t,t-1]; corresponding gaussian multipliers will
+ * form non-trivial row of new row-like factor */
+ nnz = 0; /* number of non-zero gaussian multipliers */
+ for (k = s; k < t; k++)
+ { /* diagonal element u[k,k] = v[i,j] is used as pivot */
+ i = pp_inv[k], j = qq_ind[k];
+ /* take subdiagonal element u[t,k] = v[p,j] */
+ temp = work[j];
+#if 1 /* FIXME */
+ if (-eps_tol < temp && temp < +eps_tol)
+ continue;
+#endif
+ /* compute and save gaussian multiplier:
+ * f := u[t,k] / u[k,k] = v[p,j] / v[i,j] */
+ ind[++nnz] = i;
+ val[nnz] = f = work[j] / vr_piv[i];
+ /* gaussian transformation to eliminate u[t,k] = v[p,j]:
+ * (p-th row of V) := (p-th row of V) - f * (i-th row of V) */
+ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i];
+ i_ptr < i_end; i_ptr++)
+ work[sv_ind[i_ptr]] -= f * sv_val[i_ptr];
+ }
+ /* now matrix U is again upper triangular */
+#if 1 /* FIXME */
+ if (-vpq_tol < work[q] && work[q] < +vpq_tol)
+#endif
+ { /* however, its new diagonal element u[t,t] = v[p,q] is too
+ * small in magnitude */
+ return 3;
+ }
+ /*--------------------------------------------------------------*/
+ /* create new row-like factor H[k] and add to eta file H */
+ /*--------------------------------------------------------------*/
+ /* (nnz = 0 means that all subdiagonal elements were too small
+ * in magnitude) */
+ if (nnz > 0)
+ { if (fhv->nfs == fhv->nfs_max)
+ { /* maximal number of row-like factors has been reached */
+ return 4;
+ }
+ k = ++(fhv->nfs);
+ hh_ind[k] = p;
+ /* store non-trivial row of H[k] in right (dynamic) part of
+ * SVA (diagonal unity element is not stored) */
+ if (sva->r_ptr - sva->m_ptr < nnz)
+ { sva_more_space(sva, nnz);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_reserve_cap(sva, fhv->hh_ref-1+k, nnz);
+ ptr = hh_ptr[k];
+ memcpy(&sv_ind[ptr], &ind[1], nnz * sizeof(int));
+ memcpy(&sv_val[ptr], &val[1], nnz * sizeof(double));
+ hh_len[k] = nnz;
+ }
+ /*--------------------------------------------------------------*/
+ /* copy transformed p-th row of matrix V, which is t-th row of */
+ /* matrix U, from working array back to matrix V */
+ /*--------------------------------------------------------------*/
+ /* copy elements of transformed p-th row of matrix V, which are
+ * non-diagonal elements u[t,t+1], ..., u[t,n] of matrix U, from
+ * working array to corresponding columns of matrix V (note that
+ * diagonal element u[t,t] = v[p,q] not copied); also transform
+ * p-th row of matrix V to sparse format */
+ len = 0;
+ for (k = t+1; k <= n; k++)
+ { /* j-th column of V = k-th column of U */
+ j = qq_ind[k];
+ /* take non-diagonal element v[p,j] = u[t,k] */
+ temp = work[j];
+#if 1 /* FIXME */
+ if (-eps_tol < temp && temp < +eps_tol)
+ continue;
+#endif
+ /* add v[p,j] to j-th column of matrix V */
+ if (vc_cap[j] == vc_len[j])
+ { /* reserve extra locations in j-th column to reduce further
+ * relocations of that column */
+#if 1 /* FIXME */
+ int need = vc_len[j] + 5;
+#endif
+ if (sva->r_ptr - sva->m_ptr < need)
+ { sva_more_space(sva, need);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_enlarge_cap(sva, vc_ref-1+j, need, 0);
+ }
+ sv_ind[ptr = vc_ptr[j] + (vc_len[j]++)] = p;
+ sv_val[ptr] = temp;
+ /* store element v[p,j] = u[t,k] to working sparse vector */
+ ind[++len] = j;
+ val[len] = temp;
+ }
+ /* copy elements from working sparse vector to p-th row of matrix
+ * V (this row is currently empty) */
+ if (vr_cap[p] < len)
+ { if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_enlarge_cap(sva, vr_ref-1+p, len, 0);
+ }
+ ptr = vr_ptr[p];
+ memcpy(&sv_ind[ptr], &ind[1], len * sizeof(int));
+ memcpy(&sv_val[ptr], &val[1], len * sizeof(double));
+ vr_len[p] = len;
+ /* store new diagonal element u[t,t] = v[p,q] */
+ vr_piv[p] = work[q];
+ /*--------------------------------------------------------------*/
+ /* perform accuracy test (only if new H[k] was added) */
+ /*--------------------------------------------------------------*/
+ if (nnz > 0)
+ { /* copy p-th (non-trivial) row of row-like factor H[k] (except
+ * unity diagonal element) to working array in dense format */
+ for (j = 1; j <= n; j++)
+ work[j] = 0.0;
+ k = fhv->nfs;
+ for (end = (ptr = hh_ptr[k]) + hh_len[k]; ptr < end; ptr++)
+ work[sv_ind[ptr]] = sv_val[ptr];
+ /* compute inner product of p-th (non-trivial) row of matrix
+ * H[k] and q-th column of matrix V */
+ temp = vr_piv[p]; /* 1 * v[p,q] */
+ ptr = vc_ptr[q];
+ end = ptr + vc_len[q];
+ for (; ptr < end; ptr++)
+ temp += work[sv_ind[ptr]] * sv_val[ptr];
+ /* inner product should be equal to element v[p,q] *before*
+ * matrix V was transformed */
+ /* compute relative error */
+ temp = fabs(vpq - temp) / (1.0 + fabs(vpq));
+#if 1 /* FIXME */
+ if (temp > err_tol)
+#endif
+ { /* relative error is too large */
+ return 5;
+ }
+ }
+ /* factorization has been successfully updated */
+ return 0;
+}
+
+/***********************************************************************
+* fhv_h_solve - solve system H * x = b
+*
+* This routine solves the system H * x = b, where the matrix H is the
+* middle factor of the sparse updatable FHV-factorization.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix H. On exit this array will contain elements of the solution
+* vector x in the same locations. */
+
+void fhv_h_solve(FHV *fhv, double x[/*1+n*/])
+{ SVA *sva = fhv->luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int nfs = fhv->nfs;
+ int *hh_ind = fhv->hh_ind;
+ int hh_ref = fhv->hh_ref;
+ int *hh_ptr = &sva->ptr[hh_ref-1];
+ int *hh_len = &sva->len[hh_ref-1];
+ int i, k, end, ptr;
+ double x_i;
+ for (k = 1; k <= nfs; k++)
+ { x_i = x[i = hh_ind[k]];
+ for (end = (ptr = hh_ptr[k]) + hh_len[k]; ptr < end; ptr++)
+ x_i -= sv_val[ptr] * x[sv_ind[ptr]];
+ x[i] = x_i;
+ }
+ return;
+}
+
+/***********************************************************************
+* fhv_ht_solve - solve system H' * x = b
+*
+* This routine solves the system H' * x = b, where H' is a matrix
+* transposed to the matrix H, which is the middle factor of the sparse
+* updatable FHV-factorization.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix H. On exit this array will contain elements of the solution
+* vector x in the same locations. */
+
+void fhv_ht_solve(FHV *fhv, double x[/*1+n*/])
+{ SVA *sva = fhv->luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int nfs = fhv->nfs;
+ int *hh_ind = fhv->hh_ind;
+ int hh_ref = fhv->hh_ref;
+ int *hh_ptr = &sva->ptr[hh_ref-1];
+ int *hh_len = &sva->len[hh_ref-1];
+ int k, end, ptr;
+ double x_j;
+ for (k = nfs; k >= 1; k--)
+ { if ((x_j = x[hh_ind[k]]) == 0.0)
+ continue;
+ for (end = (ptr = hh_ptr[k]) + hh_len[k]; ptr < end; ptr++)
+ x[sv_ind[ptr]] -= sv_val[ptr] * x_j;
+ }
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/fhv.h b/test/monniaux/glpk-4.65/src/bflib/fhv.h
new file mode 100644
index 00000000..df39ca5c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/fhv.h
@@ -0,0 +1,114 @@
+/* fhv.h (sparse updatable FHV-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#ifndef FHV_H
+#define FHV_H
+
+#include "luf.h"
+
+/***********************************************************************
+* The structure FHV describes sparse updatable FHV-factorization.
+*
+* The FHV-factorization has the following format:
+*
+* A = F * H * V, (1)
+*
+* F = P0 * L * P0', (2)
+*
+* H = H[1] * H[2] * ... * H[nfs], (3)
+*
+* V = P * U * Q, (4)
+*
+* where: A is a given (unsymmetric) square matrix; F, H, V are matrix
+* factors actually computed; L is a lower triangular matrix with unity
+* diagonal; U is an upper tringular matrix; H[k], k = 1, 2, ..., nfs,
+* is a row-like factor, which differs from unity matrix only in one
+* row called a non-trivial row; P0, P, Q are permutation matrices; and
+* P0' is a matrix transposed to P0.
+*
+* Matrices F, V, P, Q are stored in the underlying LUF object.
+*
+* Non-trivial rows of factors H[k] are stored as sparse vectors in the
+* right (static) part of the sparse vector area (SVA). Note that unity
+* diagonal elements of non-trivial rows are not stored.
+*
+* Matrix P0 is stored in the same way as matrix P.
+*
+* Matrices L and U are completely defined by matrices F, V, P, and Q,
+* and therefore not stored explicitly. */
+
+typedef struct FHV FHV;
+
+struct FHV
+{ /* FHV-factorization */
+ LUF *luf;
+ /* LU-factorization (contains matrices F, V, P, Q) */
+ /*--------------------------------------------------------------*/
+ /* matrix H in the form of eta file */
+ int nfs_max;
+ /* maximal number of row-like factors (this limits the number of
+ * updates of the factorization) */
+ int nfs;
+ /* current number of row-like factors, 0 <= nfs <= nfs_max */
+ int *hh_ind; /* int hh_ind[1+nfs_max]; */
+ /* hh_ind[0] is not used;
+ * hh_ind[k], 1 <= k <= nfs, is number of non-trivial row of
+ * factor H[k] */
+ int hh_ref;
+ /* reference number of sparse vector in SVA, which is non-trivial
+ * row of factor H[1] */
+#if 0 + 0
+ int *hh_ptr = &sva->ptr[hh_ref-1];
+ /* hh_ptr[0] is not used;
+ * hh_ptr[k], 1 <= k <= nfs, is pointer to non-trivial row of
+ * factor H[k] */
+ int *hh_len = &sva->len[hh_ref-1];
+ /* hh_len[0] is not used;
+ * hh_len[k], 1 <= k <= nfs, is number of non-zero elements in
+ * non-trivial row of factor H[k] */
+#endif
+ /*--------------------------------------------------------------*/
+ /* matrix P0 */
+ int *p0_ind; /* int p0_ind[1+n]; */
+ /* p0_ind[i] = j means that P0[i,j] = 1 */
+ int *p0_inv; /* int p0_inv[1+n]; */
+ /* p0_inv[j] = i means that P0[i,j] = 1 */
+};
+
+#define fhv_ft_update _glp_fhv_ft_update
+int fhv_ft_update(FHV *fhv, int q, int aq_len, const int aq_ind[],
+ const double aq_val[], int ind[/*1+n*/], double val[/*1+n*/],
+ double work[/*1+n*/]);
+/* update FHV-factorization (Forrest-Tomlin) */
+
+#define fhv_h_solve _glp_fhv_h_solve
+void fhv_h_solve(FHV *fhv, double x[/*1+n*/]);
+/* solve system H * x = b */
+
+#define fhv_ht_solve _glp_fhv_ht_solve
+void fhv_ht_solve(FHV *fhv, double x[/*1+n*/]);
+/* solve system H' * x = b */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/fhvint.c b/test/monniaux/glpk-4.65/src/bflib/fhvint.c
new file mode 100644
index 00000000..a21b71c6
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/fhvint.c
@@ -0,0 +1,168 @@
+/* fhvint.c (interface to FHV-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2014 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "fhvint.h"
+
+FHVINT *fhvint_create(void)
+{ /* create interface to FHV-factorization */
+ FHVINT *fi;
+ fi = talloc(1, FHVINT);
+ memset(fi, 0, sizeof(FHVINT));
+ fi->lufi = lufint_create();
+ return fi;
+}
+
+int fhvint_factorize(FHVINT *fi, int n, int (*col)(void *info, int j,
+ int ind[], double val[]), void *info)
+{ /* compute FHV-factorization of specified matrix A */
+ int nfs_max, old_n_max, n_max, k, ret;
+ xassert(n > 0);
+ fi->valid = 0;
+ /* get required value of nfs_max */
+ nfs_max = fi->nfs_max;
+ if (nfs_max == 0)
+ nfs_max = 100;
+ xassert(nfs_max > 0);
+ /* compute factorization of specified matrix A */
+ old_n_max = fi->lufi->n_max;
+ fi->lufi->sva_n_max = 4 * n + nfs_max;
+ fi->lufi->sgf_updat = 1;
+ ret = lufint_factorize(fi->lufi, n, col, info);
+ n_max = fi->lufi->n_max;
+ /* allocate/reallocate arrays, if necessary */
+ if (fi->fhv.nfs_max != nfs_max)
+ { if (fi->fhv.hh_ind != NULL)
+ tfree(fi->fhv.hh_ind);
+ fi->fhv.hh_ind = talloc(1+nfs_max, int);
+ }
+ if (old_n_max < n_max)
+ { if (fi->fhv.p0_ind != NULL)
+ tfree(fi->fhv.p0_ind);
+ if (fi->fhv.p0_inv != NULL)
+ tfree(fi->fhv.p0_inv);
+ fi->fhv.p0_ind = talloc(1+n_max, int);
+ fi->fhv.p0_inv = talloc(1+n_max, int);
+ }
+ /* initialize FHV-factorization */
+ fi->fhv.luf = fi->lufi->luf;
+ fi->fhv.nfs_max = nfs_max;
+ /* H := I */
+ fi->fhv.nfs = 0;
+ fi->fhv.hh_ref = sva_alloc_vecs(fi->lufi->sva, nfs_max);
+ /* P0 := P */
+ for (k = 1; k <= n; k++)
+ { fi->fhv.p0_ind[k] = fi->fhv.luf->pp_ind[k];
+ fi->fhv.p0_inv[k] = fi->fhv.luf->pp_inv[k];
+ }
+ /* set validation flag */
+ if (ret == 0)
+ fi->valid = 1;
+ return ret;
+}
+
+int fhvint_update(FHVINT *fi, int j, int len, const int ind[],
+ const double val[])
+{ /* update FHV-factorization after replacing j-th column of A */
+ SGF *sgf = fi->lufi->sgf;
+ int *ind1 = sgf->rs_next;
+ double *val1 = sgf->vr_max;
+ double *work = sgf->work;
+ int ret;
+ xassert(fi->valid);
+ ret = fhv_ft_update(&fi->fhv, j, len, ind, val, ind1, val1, work);
+ if (ret != 0)
+ fi->valid = 0;
+ return ret;
+}
+
+void fhvint_ftran(FHVINT *fi, double x[])
+{ /* solve system A * x = b */
+ FHV *fhv = &fi->fhv;
+ LUF *luf = fhv->luf;
+ int n = luf->n;
+ int *pp_ind = luf->pp_ind;
+ int *pp_inv = luf->pp_inv;
+ SGF *sgf = fi->lufi->sgf;
+ double *work = sgf->work;
+ xassert(fi->valid);
+ /* A = F * H * V */
+ /* x = inv(A) * b = inv(V) * inv(H) * inv(F) * b */
+ luf->pp_ind = fhv->p0_ind;
+ luf->pp_inv = fhv->p0_inv;
+ luf_f_solve(luf, x);
+ luf->pp_ind = pp_ind;
+ luf->pp_inv = pp_inv;
+ fhv_h_solve(fhv, x);
+ luf_v_solve(luf, x, work);
+ memcpy(&x[1], &work[1], n * sizeof(double));
+ return;
+}
+
+void fhvint_btran(FHVINT *fi, double x[])
+{ /* solve system A'* x = b */
+ FHV *fhv = &fi->fhv;
+ LUF *luf = fhv->luf;
+ int n = luf->n;
+ int *pp_ind = luf->pp_ind;
+ int *pp_inv = luf->pp_inv;
+ SGF *sgf = fi->lufi->sgf;
+ double *work = sgf->work;
+ xassert(fi->valid);
+ /* A' = (F * H * V)' = V'* H'* F' */
+ /* x = inv(A') * b = inv(F') * inv(H') * inv(V') * b */
+ luf_vt_solve(luf, x, work);
+ fhv_ht_solve(fhv, work);
+ luf->pp_ind = fhv->p0_ind;
+ luf->pp_inv = fhv->p0_inv;
+ luf_ft_solve(luf, work);
+ luf->pp_ind = pp_ind;
+ luf->pp_inv = pp_inv;
+ memcpy(&x[1], &work[1], n * sizeof(double));
+ return;
+}
+
+double fhvint_estimate(FHVINT *fi)
+{ /* estimate 1-norm of inv(A) */
+ double norm;
+ xassert(fi->valid);
+ xassert(fi->fhv.nfs == 0);
+ norm = luf_estimate_norm(fi->fhv.luf, fi->lufi->sgf->vr_max,
+ fi->lufi->sgf->work);
+ return norm;
+}
+
+void fhvint_delete(FHVINT *fi)
+{ /* delete interface to FHV-factorization */
+ lufint_delete(fi->lufi);
+ if (fi->fhv.hh_ind != NULL)
+ tfree(fi->fhv.hh_ind);
+ if (fi->fhv.p0_ind != NULL)
+ tfree(fi->fhv.p0_ind);
+ if (fi->fhv.p0_inv != NULL)
+ tfree(fi->fhv.p0_inv);
+ tfree(fi);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/fhvint.h b/test/monniaux/glpk-4.65/src/bflib/fhvint.h
new file mode 100644
index 00000000..000829c6
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/fhvint.h
@@ -0,0 +1,78 @@
+/* fhvint.h (interface to FHV-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2014 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/>.
+***********************************************************************/
+
+#ifndef FHVINT_H
+#define FHVINT_H
+
+#include "fhv.h"
+#include "lufint.h"
+
+typedef struct FHVINT FHVINT;
+
+struct FHVINT
+{ /* interface to FHV-factorization */
+ int valid;
+ /* factorization is valid only if this flag is set */
+ FHV fhv;
+ /* FHV-factorization */
+ LUFINT *lufi;
+ /* interface to underlying LU-factorization */
+ /*--------------------------------------------------------------*/
+ /* control parameters */
+ int nfs_max;
+ /* required maximal number of row-like factors */
+};
+
+#define fhvint_create _glp_fhvint_create
+FHVINT *fhvint_create(void);
+/* create interface to FHV-factorization */
+
+#define fhvint_factorize _glp_fhvint_factorize
+int fhvint_factorize(FHVINT *fi, int n, int (*col)(void *info, int j,
+ int ind[], double val[]), void *info);
+/* compute FHV-factorization of specified matrix A */
+
+#define fhvint_update _glp_fhvint_update
+int fhvint_update(FHVINT *fi, int j, int len, const int ind[],
+ const double val[]);
+/* update FHV-factorization after replacing j-th column of A */
+
+#define fhvint_ftran _glp_fhvint_ftran
+void fhvint_ftran(FHVINT *fi, double x[]);
+/* solve system A * x = b */
+
+#define fhvint_btran _glp_fhvint_btran
+void fhvint_btran(FHVINT *fi, double x[]);
+/* solve system A'* x = b */
+
+#define fhvint_estimate _glp_fhvint_estimate
+double fhvint_estimate(FHVINT *fi);
+/* estimate 1-norm of inv(A) */
+
+#define fhvint_delete _glp_fhvint_delete
+void fhvint_delete(FHVINT *fi);
+/* delete interface to FHV-factorization */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/ifu.c b/test/monniaux/glpk-4.65/src/bflib/ifu.c
new file mode 100644
index 00000000..aa47fb09
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/ifu.c
@@ -0,0 +1,392 @@
+/* ifu.c (dense updatable IFU-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ifu.h"
+
+/***********************************************************************
+* ifu_expand - expand IFU-factorization
+*
+* This routine expands the IFU-factorization of the matrix A according
+* to the following expansion of A:
+*
+* ( A c )
+* new A = ( )
+* ( r' d )
+*
+* where c[1,...,n] is a new column, r[1,...,n] is a new row, and d is
+* a new diagonal element.
+*
+* From the main equality F * A = U it follows that:
+*
+* ( F 0 ) ( A c ) ( FA Fc ) ( U Fc )
+* ( ) ( ) = ( ) = ( ),
+* ( 0 1 ) ( r' d ) ( r' d ) ( r' d )
+*
+* thus,
+*
+* ( F 0 ) ( U Fc )
+* new F = ( ), new U = ( ).
+* ( 0 1 ) ( r' d )
+*
+* Note that the resulting matrix U loses its upper triangular form due
+* to row spike r', which should be eliminated. */
+
+void ifu_expand(IFU *ifu, double c[/*1+n*/], double r[/*1+n*/],
+ double d)
+{ /* non-optimized version */
+ int n_max = ifu->n_max;
+ int n = ifu->n;
+ double *f_ = ifu->f;
+ double *u_ = ifu->u;
+ int i, j;
+ double t;
+# define f(i,j) f_[(i)*n_max+(j)]
+# define u(i,j) u_[(i)*n_max+(j)]
+ xassert(0 <= n && n < n_max);
+ /* adjust indexing */
+ c++, r++;
+ /* set new zero column of matrix F */
+ for (i = 0; i < n; i++)
+ f(i,n) = 0.0;
+ /* set new zero row of matrix F */
+ for (j = 0; j < n; j++)
+ f(n,j) = 0.0;
+ /* set new unity diagonal element of matrix F */
+ f(n,n) = 1.0;
+ /* set new column of matrix U to vector (old F) * c */
+ for (i = 0; i < n; i++)
+ { /* u[i,n] := (i-th row of old F) * c */
+ t = 0.0;
+ for (j = 0; j < n; j++)
+ t += f(i,j) * c[j];
+ u(i,n) = t;
+ }
+ /* set new row of matrix U to vector r */
+ for (j = 0; j < n; j++)
+ u(n,j) = r[j];
+ /* set new diagonal element of matrix U to scalar d */
+ u(n,n) = d;
+ /* increase factorization order */
+ ifu->n++;
+# undef f
+# undef u
+ return;
+}
+
+/***********************************************************************
+* ifu_bg_update - update IFU-factorization (Bartels-Golub)
+*
+* This routine updates IFU-factorization of the matrix A according to
+* its expansion (see comments to the routine ifu_expand). The routine
+* is based on the method proposed by Bartels and Golub [1].
+*
+* RETURNS
+*
+* 0 The factorization has been successfully updated.
+*
+* 1 On some elimination step diagional element u[k,k] to be used as
+* pivot is too small in magnitude.
+*
+* 2 Diagonal element u[n,n] is too small in magnitude (at the end of
+* update).
+*
+* REFERENCES
+*
+* 1. R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming
+* Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */
+
+int ifu_bg_update(IFU *ifu, double c[/*1+n*/], double r[/*1+n*/],
+ double d)
+{ /* non-optimized version */
+ int n_max = ifu->n_max;
+ int n = ifu->n;
+ double *f_ = ifu->f;
+ double *u_ = ifu->u;
+#if 1 /* FIXME */
+ double tol = 1e-5;
+#endif
+ int j, k;
+ double t;
+# define f(i,j) f_[(i)*n_max+(j)]
+# define u(i,j) u_[(i)*n_max+(j)]
+ /* expand factorization */
+ ifu_expand(ifu, c, r, d);
+ /* NOTE: n keeps its old value */
+ /* eliminate spike (non-zero subdiagonal elements) in last row of
+ * matrix U */
+ for (k = 0; k < n; k++)
+ { /* if |u[k,k]| < |u[n,k]|, interchange k-th and n-th rows to
+ * provide |u[k,k]| >= |u[n,k]| for numeric stability */
+ if (fabs(u(k,k)) < fabs(u(n,k)))
+ { /* interchange k-th and n-th rows of matrix U */
+ for (j = k; j <= n; j++)
+ t = u(k,j), u(k,j) = u(n,j), u(n,j) = t;
+ /* interchange k-th and n-th rows of matrix F to keep the
+ * main equality F * A = U */
+ for (j = 0; j <= n; j++)
+ t = f(k,j), f(k,j) = f(n,j), f(n,j) = t;
+ }
+ /* now |u[k,k]| >= |u[n,k]| */
+ /* check if diagonal element u[k,k] can be used as pivot */
+ if (fabs(u(k,k)) < tol)
+ { /* u[k,k] is too small in magnitude */
+ return 1;
+ }
+ /* if u[n,k] = 0, elimination is not needed */
+ if (u(n,k) == 0.0)
+ continue;
+ /* compute gaussian multiplier t = u[n,k] / u[k,k] */
+ t = u(n,k) / u(k,k);
+ /* apply gaussian transformation to eliminate u[n,k] */
+ /* (n-th row of U) := (n-th row of U) - t * (k-th row of U) */
+ for (j = k+1; j <= n; j++)
+ u(n,j) -= t * u(k,j);
+ /* apply the same transformation to matrix F to keep the main
+ * equality F * A = U */
+ for (j = 0; j <= n; j++)
+ f(n,j) -= t * f(k,j);
+ }
+ /* now matrix U is upper triangular */
+ if (fabs(u(n,n)) < tol)
+ { /* u[n,n] is too small in magnitude */
+ return 2;
+ }
+# undef f
+# undef u
+ return 0;
+}
+
+/***********************************************************************
+* The routine givens computes the parameters of Givens plane rotation
+* c = cos(teta) and s = sin(teta) such that:
+*
+* ( c -s ) ( a ) ( r )
+* ( ) ( ) = ( ) ,
+* ( s c ) ( b ) ( 0 )
+*
+* where a and b are given scalars.
+*
+* REFERENCES
+*
+* G.H.Golub, C.F.Van Loan, "Matrix Computations", 2nd ed. */
+
+static void givens(double a, double b, double *c, double *s)
+{ /* non-optimized version */
+ double t;
+ if (b == 0.0)
+ (*c) = 1.0, (*s) = 0.0;
+ else if (fabs(a) <= fabs(b))
+ t = - a / b, (*s) = 1.0 / sqrt(1.0 + t * t), (*c) = (*s) * t;
+ else
+ t = - b / a, (*c) = 1.0 / sqrt(1.0 + t * t), (*s) = (*c) * t;
+ return;
+}
+
+/***********************************************************************
+* ifu_gr_update - update IFU-factorization (Givens rotations)
+*
+* This routine updates IFU-factorization of the matrix A according to
+* its expansion (see comments to the routine ifu_expand). The routine
+* is based on Givens plane rotations [1].
+*
+* RETURNS
+*
+* 0 The factorization has been successfully updated.
+*
+* 1 On some elimination step both elements u[k,k] and u[n,k] are too
+* small in magnitude.
+*
+* 2 Diagonal element u[n,n] is too small in magnitude (at the end of
+* update).
+*
+* REFERENCES
+*
+* 1. G.H.Golub, C.F.Van Loan, "Matrix Computations", 2nd ed. */
+
+int ifu_gr_update(IFU *ifu, double c[/*1+n*/], double r[/*1+n*/],
+ double d)
+{ /* non-optimized version */
+ int n_max = ifu->n_max;
+ int n = ifu->n;
+ double *f_ = ifu->f;
+ double *u_ = ifu->u;
+#if 1 /* FIXME */
+ double tol = 1e-5;
+#endif
+ int j, k;
+ double cs, sn;
+# define f(i,j) f_[(i)*n_max+(j)]
+# define u(i,j) u_[(i)*n_max+(j)]
+ /* expand factorization */
+ ifu_expand(ifu, c, r, d);
+ /* NOTE: n keeps its old value */
+ /* eliminate spike (non-zero subdiagonal elements) in last row of
+ * matrix U */
+ for (k = 0; k < n; k++)
+ { /* check if elements u[k,k] and u[n,k] are eligible */
+ if (fabs(u(k,k)) < tol && fabs(u(n,k)) < tol)
+ { /* both u[k,k] and u[n,k] are too small in magnitude */
+ return 1;
+ }
+ /* if u[n,k] = 0, elimination is not needed */
+ if (u(n,k) == 0.0)
+ continue;
+ /* compute parameters of Givens plane rotation */
+ givens(u(k,k), u(n,k), &cs, &sn);
+ /* apply Givens rotation to k-th and n-th rows of matrix U to
+ * eliminate u[n,k] */
+ for (j = k; j <= n; j++)
+ { double ukj = u(k,j), unj = u(n,j);
+ u(k,j) = cs * ukj - sn * unj;
+ u(n,j) = sn * ukj + cs * unj;
+ }
+ /* apply the same transformation to matrix F to keep the main
+ * equality F * A = U */
+ for (j = 0; j <= n; j++)
+ { double fkj = f(k,j), fnj = f(n,j);
+ f(k,j) = cs * fkj - sn * fnj;
+ f(n,j) = sn * fkj + cs * fnj;
+ }
+ }
+ /* now matrix U is upper triangular */
+ if (fabs(u(n,n)) < tol)
+ { /* u[n,n] is too small in magnitude */
+ return 2;
+ }
+# undef f
+# undef u
+ return 0;
+}
+
+/***********************************************************************
+* ifu_a_solve - solve system A * x = b
+*
+* This routine solves the system A * x = b, where the matrix A is
+* specified by its IFU-factorization.
+*
+* Using the main equality F * A = U we have:
+*
+* A * x = b => F * A * x = F * b => U * x = F * b =>
+*
+* x = inv(U) * F * b.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix A. On exit this array will contain elements of the solution
+* vector x in the same locations.
+*
+* The working array w should have at least 1+n elements (0-th element
+* is not used). */
+
+void ifu_a_solve(IFU *ifu, double x[/*1+n*/], double w[/*1+n*/])
+{ /* non-optimized version */
+ int n_max = ifu->n_max;
+ int n = ifu->n;
+ double *f_ = ifu->f;
+ double *u_ = ifu->u;
+ int i, j;
+ double t;
+# define f(i,j) f_[(i)*n_max+(j)]
+# define u(i,j) u_[(i)*n_max+(j)]
+ xassert(0 <= n && n <= n_max);
+ /* adjust indexing */
+ x++, w++;
+ /* y := F * b */
+ memcpy(w, x, n * sizeof(double));
+ for (i = 0; i < n; i++)
+ { /* y[i] := (i-th row of F) * b */
+ t = 0.0;
+ for (j = 0; j < n; j++)
+ t += f(i,j) * w[j];
+ x[i] = t;
+ }
+ /* x := inv(U) * y */
+ for (i = n-1; i >= 0; i--)
+ { t = x[i];
+ for (j = i+1; j < n; j++)
+ t -= u(i,j) * x[j];
+ x[i] = t / u(i,i);
+ }
+# undef f
+# undef u
+ return;
+}
+
+/***********************************************************************
+* ifu_at_solve - solve system A'* x = b
+*
+* This routine solves the system A'* x = b, where A' is a matrix
+* transposed to the matrix A, specified by its IFU-factorization.
+*
+* Using the main equality F * A = U, from which it follows that
+* A'* F' = U', we have:
+*
+* A'* x = b => A'* F'* inv(F') * x = b =>
+*
+* U'* inv(F') * x = b => inv(F') * x = inv(U') * b =>
+*
+* x = F' * inv(U') * b.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix A. On exit this array will contain elements of the solution
+* vector x in the same locations.
+*
+* The working array w should have at least 1+n elements (0-th element
+* is not used). */
+
+void ifu_at_solve(IFU *ifu, double x[/*1+n*/], double w[/*1+n*/])
+{ /* non-optimized version */
+ int n_max = ifu->n_max;
+ int n = ifu->n;
+ double *f_ = ifu->f;
+ double *u_ = ifu->u;
+ int i, j;
+ double t;
+# define f(i,j) f_[(i)*n_max+(j)]
+# define u(i,j) u_[(i)*n_max+(j)]
+ xassert(0 <= n && n <= n_max);
+ /* adjust indexing */
+ x++, w++;
+ /* y := inv(U') * b */
+ for (i = 0; i < n; i++)
+ { t = (x[i] /= u(i,i));
+ for (j = i+1; j < n; j++)
+ x[j] -= u(i,j) * t;
+ }
+ /* x := F'* y */
+ for (j = 0; j < n; j++)
+ { /* x[j] := (j-th column of F) * y */
+ t = 0.0;
+ for (i = 0; i < n; i++)
+ t += f(i,j) * x[i];
+ w[j] = t;
+ }
+ memcpy(x, w, n * sizeof(double));
+# undef f
+# undef u
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/ifu.h b/test/monniaux/glpk-4.65/src/bflib/ifu.h
new file mode 100644
index 00000000..1c67a801
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/ifu.h
@@ -0,0 +1,99 @@
+/* ifu.h (dense updatable IFU-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#ifndef IFU_H
+#define IFU_H
+
+/***********************************************************************
+* The structure IFU describes dense updatable IFU-factorization.
+*
+* The IFU-factorization has the following format:
+*
+* A = inv(F) * U, (1)
+*
+* where A is a given (unsymmetric) nxn square matrix, F is a square
+* matrix, U is an upper triangular matrix. Obviously, the equality (1)
+* is equivalent to the following equality:
+*
+* F * A = U. (2)
+*
+* It is assumed that matrix A is small and dense, so matrices F and U
+* are stored by rows in dense format as follows:
+*
+* 1 n n_max 1 n n_max
+* 1 * * * * * * x x x x 1 * * * * * * x x x x
+* * * * * * * x x x x ? * * * * * x x x x
+* * * * * * * x x x x ? ? * * * * x x x x
+* * * * * * * x x x x ? ? ? * * * x x x x
+* * * * * * * x x x x ? ? ? ? * * x x x x
+* n * * * * * * x x x x n ? ? ? ? ? * x x x x
+* x x x x x x x x x x x x x x x x x x x x
+* x x x x x x x x x x x x x x x x x x x x
+* x x x x x x x x x x x x x x x x x x x x
+* n_max x x x x x x x x x x n_max x x x x x x x x x x
+*
+* matrix F matrix U
+*
+* where '*' are matrix elements, '?' are unused locations, 'x' are
+* reserved locations. */
+
+typedef struct IFU IFU;
+
+struct IFU
+{ /* IFU-factorization */
+ int n_max;
+ /* maximal order of matrices A, F, U; n_max >= 1 */
+ int n;
+ /* current order of matrices A, F, U; 0 <= n <= n_max */
+ double *f; /* double f[n_max*n_max]; */
+ /* matrix F stored by rows */
+ double *u; /* double u[n_max*n_max]; */
+ /* matrix U stored by rows */
+};
+
+#define ifu_expand _glp_ifu_expand
+void ifu_expand(IFU *ifu, double c[/*1+n*/], double r[/*1+n*/],
+ double d);
+/* expand IFU-factorization */
+
+#define ifu_bg_update _glp_ifu_bg_update
+int ifu_bg_update(IFU *ifu, double c[/*1+n*/], double r[/*1+n*/],
+ double d);
+/* update IFU-factorization (Bartels-Golub) */
+
+#define ifu_gr_update _glp_ifu_gr_update
+int ifu_gr_update(IFU *ifu, double c[/*1+n*/], double r[/*1+n*/],
+ double d);
+/* update IFU-factorization (Givens rotations) */
+
+#define ifu_a_solve _glp_ifu_a_solve
+void ifu_a_solve(IFU *ifu, double x[/*1+n*/], double w[/*1+n*/]);
+/* solve system A * x = b */
+
+#define ifu_at_solve _glp_ifu_at_solve
+void ifu_at_solve(IFU *ifu, double x[/*1+n*/], double w[/*1+n*/]);
+/* solve system A'* x = b */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/luf.c b/test/monniaux/glpk-4.65/src/bflib/luf.c
new file mode 100644
index 00000000..2797407d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/luf.c
@@ -0,0 +1,713 @@
+/* luf.c (sparse LU-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "luf.h"
+
+/***********************************************************************
+* luf_store_v_cols - store matrix V = A in column-wise format
+*
+* This routine stores matrix V = A in column-wise format, where A is
+* the original matrix to be factorized.
+*
+* On exit the routine returns the number of non-zeros in matrix V. */
+
+int luf_store_v_cols(LUF *luf, int (*col)(void *info, int j, int ind[],
+ double val[]), void *info, int ind[], double val[])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int *vc_cap = &sva->cap[vc_ref-1];
+ int j, len, ptr, nnz;
+ nnz = 0;
+ for (j = 1; j <= n; j++)
+ { /* get j-th column */
+ len = col(info, j, ind, val);
+ xassert(0 <= len && len <= n);
+ /* enlarge j-th column capacity */
+ if (vc_cap[j] < len)
+ { if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_enlarge_cap(sva, vc_ref-1+j, len, 0);
+ }
+ /* store j-th column */
+ ptr = vc_ptr[j];
+ memcpy(&sv_ind[ptr], &ind[1], len * sizeof(int));
+ memcpy(&sv_val[ptr], &val[1], len * sizeof(double));
+ vc_len[j] = len;
+ nnz += len;
+ }
+ return nnz;
+}
+
+/***********************************************************************
+* luf_check_all - check LU-factorization before k-th elimination step
+*
+* This routine checks that before performing k-th elimination step,
+* 1 <= k <= n+1, all components of the LU-factorization are correct.
+*
+* In case of k = n+1, i.e. after last elimination step, it is assumed
+* that rows of F and columns of V are *not* built yet.
+*
+* NOTE: For testing/debugging only. */
+
+void luf_check_all(LUF *luf, int k)
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int fr_ref = luf->fr_ref;
+ int *fr_len = &sva->len[fr_ref-1];
+ int fc_ref = luf->fc_ref;
+ int *fc_ptr = &sva->ptr[fc_ref-1];
+ int *fc_len = &sva->len[fc_ref-1];
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int *pp_ind = luf->pp_ind;
+ int *pp_inv = luf->pp_inv;
+ int *qq_ind = luf->qq_ind;
+ int *qq_inv = luf->qq_inv;
+ int i, ii, i_ptr, i_end, j, jj, j_ptr, j_end;
+ xassert(n > 0);
+ xassert(1 <= k && k <= n+1);
+ /* check permutation matrix P */
+ for (i = 1; i <= n; i++)
+ { ii = pp_ind[i];
+ xassert(1 <= ii && ii <= n);
+ xassert(pp_inv[ii] == i);
+ }
+ /* check permutation matrix Q */
+ for (j = 1; j <= n; j++)
+ { jj = qq_inv[j];
+ xassert(1 <= jj && jj <= n);
+ xassert(qq_ind[jj] == j);
+ }
+ /* check row-wise representation of matrix F */
+ for (i = 1; i <= n; i++)
+ xassert(fr_len[i] == 0);
+ /* check column-wise representation of matrix F */
+ for (j = 1; j <= n; j++)
+ { /* j-th column of F = jj-th column of L */
+ jj = pp_ind[j];
+ if (jj < k)
+ { j_ptr = fc_ptr[j];
+ j_end = j_ptr + fc_len[j];
+ for (; j_ptr < j_end; j_ptr++)
+ { i = sv_ind[j_ptr];
+ xassert(1 <= i && i <= n);
+ ii = pp_ind[i]; /* f[i,j] = l[ii,jj] */
+ xassert(ii > jj);
+ xassert(sv_val[j_ptr] != 0.0);
+ }
+ }
+ else /* jj >= k */
+ xassert(fc_len[j] == 0);
+ }
+ /* check row-wise representation of matrix V */
+ for (i = 1; i <= n; i++)
+ { /* i-th row of V = ii-th row of U */
+ ii = pp_ind[i];
+ i_ptr = vr_ptr[i];
+ i_end = i_ptr + vr_len[i];
+ for (; i_ptr < i_end; i_ptr++)
+ { j = sv_ind[i_ptr];
+ xassert(1 <= j && j <= n);
+ jj = qq_inv[j]; /* v[i,j] = u[ii,jj] */
+ if (ii < k)
+ xassert(jj > ii);
+ else /* ii >= k */
+ { xassert(jj >= k);
+ /* find v[i,j] in j-th column */
+ j_ptr = vc_ptr[j];
+ j_end = j_ptr + vc_len[j];
+ for (; sv_ind[j_ptr] != i; j_ptr++)
+ /* nop */;
+ xassert(j_ptr < j_end);
+ }
+ xassert(sv_val[i_ptr] != 0.0);
+ }
+ }
+ /* check column-wise representation of matrix V */
+ for (j = 1; j <= n; j++)
+ { /* j-th column of V = jj-th column of U */
+ jj = qq_inv[j];
+ if (jj < k)
+ xassert(vc_len[j] == 0);
+ else /* jj >= k */
+ { j_ptr = vc_ptr[j];
+ j_end = j_ptr + vc_len[j];
+ for (; j_ptr < j_end; j_ptr++)
+ { i = sv_ind[j_ptr];
+ ii = pp_ind[i]; /* v[i,j] = u[ii,jj] */
+ xassert(ii >= k);
+ /* find v[i,j] in i-th row */
+ i_ptr = vr_ptr[i];
+ i_end = i_ptr + vr_len[i];
+ for (; sv_ind[i_ptr] != j; i_ptr++)
+ /* nop */;
+ xassert(i_ptr < i_end);
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_build_v_rows - build matrix V in row-wise format
+*
+* This routine builds the row-wise representation of matrix V in the
+* left part of SVA using its column-wise representation.
+*
+* NOTE: On entry to the routine all rows of matrix V should have zero
+* capacity.
+*
+* The working array len should have at least 1+n elements (len[0] is
+* not used). */
+
+void luf_build_v_rows(LUF *luf, int len[/*1+n*/])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int i, j, end, nnz, ptr, ptr1;
+ /* calculate the number of non-zeros in each row of matrix V and
+ * the total number of non-zeros */
+ nnz = 0;
+ for (i = 1; i <= n; i++)
+ len[i] = 0;
+ for (j = 1; j <= n; j++)
+ { nnz += vc_len[j];
+ for (end = (ptr = vc_ptr[j]) + vc_len[j]; ptr < end; ptr++)
+ len[sv_ind[ptr]]++;
+ }
+ /* we need at least nnz free locations in SVA */
+ if (sva->r_ptr - sva->m_ptr < nnz)
+ { sva_more_space(sva, nnz);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ /* reserve locations for rows of matrix V */
+ for (i = 1; i <= n; i++)
+ { if (len[i] > 0)
+ sva_enlarge_cap(sva, vr_ref-1+i, len[i], 0);
+ vr_len[i] = len[i];
+ }
+ /* walk thru column of matrix V and build its rows */
+ for (j = 1; j <= n; j++)
+ { for (end = (ptr = vc_ptr[j]) + vc_len[j]; ptr < end; ptr++)
+ { i = sv_ind[ptr];
+ sv_ind[ptr1 = vr_ptr[i] + (--len[i])] = j;
+ sv_val[ptr1] = sv_val[ptr];
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_build_f_rows - build matrix F in row-wise format
+*
+* This routine builds the row-wise representation of matrix F in the
+* right part of SVA using its column-wise representation.
+*
+* NOTE: On entry to the routine all rows of matrix F should have zero
+* capacity.
+*
+* The working array len should have at least 1+n elements (len[0] is
+* not used). */
+
+void luf_build_f_rows(LUF *luf, int len[/*1+n*/])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int fr_ref = luf->fr_ref;
+ int *fr_ptr = &sva->ptr[fr_ref-1];
+ int *fr_len = &sva->len[fr_ref-1];
+ int fc_ref = luf->fc_ref;
+ int *fc_ptr = &sva->ptr[fc_ref-1];
+ int *fc_len = &sva->len[fc_ref-1];
+ int i, j, end, nnz, ptr, ptr1;
+ /* calculate the number of non-zeros in each row of matrix F and
+ * the total number of non-zeros (except diagonal elements) */
+ nnz = 0;
+ for (i = 1; i <= n; i++)
+ len[i] = 0;
+ for (j = 1; j <= n; j++)
+ { nnz += fc_len[j];
+ for (end = (ptr = fc_ptr[j]) + fc_len[j]; ptr < end; ptr++)
+ len[sv_ind[ptr]]++;
+ }
+ /* we need at least nnz free locations in SVA */
+ if (sva->r_ptr - sva->m_ptr < nnz)
+ { sva_more_space(sva, nnz);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ /* reserve locations for rows of matrix F */
+ for (i = 1; i <= n; i++)
+ { if (len[i] > 0)
+ sva_reserve_cap(sva, fr_ref-1+i, len[i]);
+ fr_len[i] = len[i];
+ }
+ /* walk through columns of matrix F and build its rows */
+ for (j = 1; j <= n; j++)
+ { for (end = (ptr = fc_ptr[j]) + fc_len[j]; ptr < end; ptr++)
+ { i = sv_ind[ptr];
+ sv_ind[ptr1 = fr_ptr[i] + (--len[i])] = j;
+ sv_val[ptr1] = sv_val[ptr];
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_build_v_cols - build matrix V in column-wise format
+*
+* This routine builds the column-wise representation of matrix V in
+* the left (if the flag updat is set) or right (if the flag updat is
+* clear) part of SVA using its row-wise representation.
+*
+* NOTE: On entry to the routine all columns of matrix V should have
+* zero capacity.
+*
+* The working array len should have at least 1+n elements (len[0] is
+* not used). */
+
+void luf_build_v_cols(LUF *luf, int updat, int len[/*1+n*/])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int i, j, end, nnz, ptr, ptr1;
+ /* calculate the number of non-zeros in each column of matrix V
+ * and the total number of non-zeros (except pivot elements) */
+ nnz = 0;
+ for (j = 1; j <= n; j++)
+ len[j] = 0;
+ for (i = 1; i <= n; i++)
+ { nnz += vr_len[i];
+ for (end = (ptr = vr_ptr[i]) + vr_len[i]; ptr < end; ptr++)
+ len[sv_ind[ptr]]++;
+ }
+ /* we need at least nnz free locations in SVA */
+ if (sva->r_ptr - sva->m_ptr < nnz)
+ { sva_more_space(sva, nnz);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ /* reserve locations for columns of matrix V */
+ for (j = 1; j <= n; j++)
+ { if (len[j] > 0)
+ { if (updat)
+ sva_enlarge_cap(sva, vc_ref-1+j, len[j], 0);
+ else
+ sva_reserve_cap(sva, vc_ref-1+j, len[j]);
+ }
+ vc_len[j] = len[j];
+ }
+ /* walk through rows of matrix V and build its columns */
+ for (i = 1; i <= n; i++)
+ { for (end = (ptr = vr_ptr[i]) + vr_len[i]; ptr < end; ptr++)
+ { j = sv_ind[ptr];
+ sv_ind[ptr1 = vc_ptr[j] + (--len[j])] = i;
+ sv_val[ptr1] = sv_val[ptr];
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_check_f_rc - check rows and columns of matrix F
+*
+* This routine checks that the row- and column-wise representations
+* of matrix F are identical.
+*
+* NOTE: For testing/debugging only. */
+
+void luf_check_f_rc(LUF *luf)
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int fr_ref = luf->fr_ref;
+ int *fr_ptr = &sva->ptr[fr_ref-1];
+ int *fr_len = &sva->len[fr_ref-1];
+ int fc_ref = luf->fc_ref;
+ int *fc_ptr = &sva->ptr[fc_ref-1];
+ int *fc_len = &sva->len[fc_ref-1];
+ int i, i_end, i_ptr, j, j_end, j_ptr;
+ /* walk thru rows of matrix F */
+ for (i = 1; i <= n; i++)
+ { for (i_end = (i_ptr = fr_ptr[i]) + fr_len[i];
+ i_ptr < i_end; i_ptr++)
+ { j = sv_ind[i_ptr];
+ /* find element f[i,j] in j-th column of matrix F */
+ for (j_end = (j_ptr = fc_ptr[j]) + fc_len[j];
+ sv_ind[j_ptr] != i; j_ptr++)
+ /* nop */;
+ xassert(j_ptr < j_end);
+ xassert(sv_val[i_ptr] == sv_val[j_ptr]);
+ /* mark element f[i,j] */
+ sv_ind[j_ptr] = -i;
+ }
+ }
+ /* walk thru column of matix F and check that all elements has
+ been marked */
+ for (j = 1; j <= n; j++)
+ { for (j_end = (j_ptr = fc_ptr[j]) + fc_len[j];
+ j_ptr < j_end; j_ptr++)
+ { xassert((i = sv_ind[j_ptr]) < 0);
+ /* unmark element f[i,j] */
+ sv_ind[j_ptr] = -i;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_check_v_rc - check rows and columns of matrix V
+*
+* This routine checks that the row- and column-wise representations
+* of matrix V are identical.
+*
+* NOTE: For testing/debugging only. */
+
+void luf_check_v_rc(LUF *luf)
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int i, i_end, i_ptr, j, j_end, j_ptr;
+ /* walk thru rows of matrix V */
+ for (i = 1; i <= n; i++)
+ { for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i];
+ i_ptr < i_end; i_ptr++)
+ { j = sv_ind[i_ptr];
+ /* find element v[i,j] in j-th column of matrix V */
+ for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j];
+ sv_ind[j_ptr] != i; j_ptr++)
+ /* nop */;
+ xassert(j_ptr < j_end);
+ xassert(sv_val[i_ptr] == sv_val[j_ptr]);
+ /* mark element v[i,j] */
+ sv_ind[j_ptr] = -i;
+ }
+ }
+ /* walk thru column of matix V and check that all elements has
+ been marked */
+ for (j = 1; j <= n; j++)
+ { for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j];
+ j_ptr < j_end; j_ptr++)
+ { xassert((i = sv_ind[j_ptr]) < 0);
+ /* unmark element v[i,j] */
+ sv_ind[j_ptr] = -i;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_f_solve - solve system F * x = b
+*
+* This routine solves the system F * x = b, where the matrix F is the
+* left factor of the sparse LU-factorization.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix F. On exit this array will contain elements of the solution
+* vector x in the same locations. */
+
+void luf_f_solve(LUF *luf, double x[/*1+n*/])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int fc_ref = luf->fc_ref;
+ int *fc_ptr = &sva->ptr[fc_ref-1];
+ int *fc_len = &sva->len[fc_ref-1];
+ int *pp_inv = luf->pp_inv;
+ int j, k, ptr, end;
+ double x_j;
+ for (k = 1; k <= n; k++)
+ { /* k-th column of L = j-th column of F */
+ j = pp_inv[k];
+ /* x[j] is already computed */
+ /* walk thru j-th column of matrix F and substitute x[j] into
+ * other equations */
+ if ((x_j = x[j]) != 0.0)
+ { for (end = (ptr = fc_ptr[j]) + fc_len[j]; ptr < end; ptr++)
+ x[sv_ind[ptr]] -= sv_val[ptr] * x_j;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_ft_solve - solve system F' * x = b
+*
+* This routine solves the system F' * x = b, where F' is a matrix
+* transposed to the matrix F, which is the left factor of the sparse
+* LU-factorization.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix F. On exit this array will contain elements of the solution
+* vector x in the same locations. */
+
+void luf_ft_solve(LUF *luf, double x[/*1+n*/])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int fr_ref = luf->fr_ref;
+ int *fr_ptr = &sva->ptr[fr_ref-1];
+ int *fr_len = &sva->len[fr_ref-1];
+ int *pp_inv = luf->pp_inv;
+ int i, k, ptr, end;
+ double x_i;
+ for (k = n; k >= 1; k--)
+ { /* k-th column of L' = i-th row of F */
+ i = pp_inv[k];
+ /* x[i] is already computed */
+ /* walk thru i-th row of matrix F and substitute x[i] into
+ * other equations */
+ if ((x_i = x[i]) != 0.0)
+ { for (end = (ptr = fr_ptr[i]) + fr_len[i]; ptr < end; ptr++)
+ x[sv_ind[ptr]] -= sv_val[ptr] * x_i;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_v_solve - solve system V * x = b
+*
+* This routine solves the system V * x = b, where the matrix V is the
+* right factor of the sparse LU-factorization.
+*
+* On entry the array b should contain elements of the right-hand side
+* vector b in locations b[1], ..., b[n], where n is the order of the
+* matrix V. On exit the array x will contain elements of the solution
+* vector x in locations x[1], ..., x[n]. Note that the array b will be
+* clobbered on exit. */
+
+void luf_v_solve(LUF *luf, double b[/*1+n*/], double x[/*1+n*/])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ double *vr_piv = luf->vr_piv;
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int *pp_inv = luf->pp_inv;
+ int *qq_ind = luf->qq_ind;
+ int i, j, k, ptr, end;
+ double x_j;
+ for (k = n; k >= 1; k--)
+ { /* k-th row of U = i-th row of V */
+ /* k-th column of U = j-th column of V */
+ i = pp_inv[k];
+ j = qq_ind[k];
+ /* compute x[j] = b[i] / u[k,k], where u[k,k] = v[i,j];
+ * walk through j-th column of matrix V and substitute x[j]
+ * into other equations */
+ if ((x_j = x[j] = b[i] / vr_piv[i]) != 0.0)
+ { for (end = (ptr = vc_ptr[j]) + vc_len[j]; ptr < end; ptr++)
+ b[sv_ind[ptr]] -= sv_val[ptr] * x_j;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_vt_solve - solve system V' * x = b
+*
+* This routine solves the system V' * x = b, where V' is a matrix
+* transposed to the matrix V, which is the right factor of the sparse
+* LU-factorization.
+*
+* On entry the array b should contain elements of the right-hand side
+* vector b in locations b[1], ..., b[n], where n is the order of the
+* matrix V. On exit the array x will contain elements of the solution
+* vector x in locations x[1], ..., x[n]. Note that the array b will be
+* clobbered on exit. */
+
+void luf_vt_solve(LUF *luf, double b[/*1+n*/], double x[/*1+n*/])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ double *vr_piv = luf->vr_piv;
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int *pp_inv = luf->pp_inv;
+ int *qq_ind = luf->qq_ind;
+ int i, j, k, ptr, end;
+ double x_i;
+ for (k = 1; k <= n; k++)
+ { /* k-th row of U' = j-th column of V */
+ /* k-th column of U' = i-th row of V */
+ i = pp_inv[k];
+ j = qq_ind[k];
+ /* compute x[i] = b[j] / u'[k,k], where u'[k,k] = v[i,j];
+ * walk through i-th row of matrix V and substitute x[i] into
+ * other equations */
+ if ((x_i = x[i] = b[j] / vr_piv[i]) != 0.0)
+ { for (end = (ptr = vr_ptr[i]) + vr_len[i]; ptr < end; ptr++)
+ b[sv_ind[ptr]] -= sv_val[ptr] * x_i;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_vt_solve1 - solve system V' * y = e' to cause growth in y
+*
+* This routine is a special version of luf_vt_solve. It solves the
+* system V'* y = e' = e + delta e, where V' is a matrix transposed to
+* the matrix V, e is the specified right-hand side vector, and delta e
+* is a vector of +1 and -1 chosen to cause growth in the solution
+* vector y.
+*
+* On entry the array e should contain elements of the right-hand side
+* vector e in locations e[1], ..., e[n], where n is the order of the
+* matrix V. On exit the array y will contain elements of the solution
+* vector y in locations y[1], ..., y[n]. Note that the array e will be
+* clobbered on exit. */
+
+void luf_vt_solve1(LUF *luf, double e[/*1+n*/], double y[/*1+n*/])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ double *vr_piv = luf->vr_piv;
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int *pp_inv = luf->pp_inv;
+ int *qq_ind = luf->qq_ind;
+ int i, j, k, ptr, end;
+ double e_j, y_i;
+ for (k = 1; k <= n; k++)
+ { /* k-th row of U' = j-th column of V */
+ /* k-th column of U' = i-th row of V */
+ i = pp_inv[k];
+ j = qq_ind[k];
+ /* determine e'[j] = e[j] + delta e[j] */
+ e_j = (e[j] >= 0.0 ? e[j] + 1.0 : e[j] - 1.0);
+ /* compute y[i] = e'[j] / u'[k,k], where u'[k,k] = v[i,j] */
+ y_i = y[i] = e_j / vr_piv[i];
+ /* walk through i-th row of matrix V and substitute y[i] into
+ * other equations */
+ for (end = (ptr = vr_ptr[i]) + vr_len[i]; ptr < end; ptr++)
+ e[sv_ind[ptr]] -= sv_val[ptr] * y_i;
+ }
+ return;
+}
+
+/***********************************************************************
+* luf_estimate_norm - estimate 1-norm of inv(A)
+*
+* This routine estimates 1-norm of inv(A) by one step of inverse
+* iteration for the small singular vector as described in [1]. This
+* involves solving two systems of equations:
+*
+* A'* y = e,
+*
+* A * z = y,
+*
+* where A' is a matrix transposed to A, and e is a vector of +1 and -1
+* chosen to cause growth in y. Then
+*
+* estimate 1-norm of inv(A) = (1-norm of z) / (1-norm of y)
+*
+* REFERENCES
+*
+* 1. G.E.Forsythe, M.A.Malcolm, C.B.Moler. Computer Methods for
+* Mathematical Computations. Prentice-Hall, Englewood Cliffs, N.J.,
+* pp. 30-62 (subroutines DECOMP and SOLVE). */
+
+double luf_estimate_norm(LUF *luf, double w1[/*1+n*/], double
+ w2[/*1+n*/])
+{ int n = luf->n;
+ double *e = w1;
+ double *y = w2;
+ double *z = w1;
+ int i;
+ double y_norm, z_norm;
+ /* y = inv(A') * e = inv(F') * inv(V') * e */
+ /* compute y' = inv(V') * e to cause growth in y' */
+ for (i = 1; i <= n; i++)
+ e[i] = 0.0;
+ luf_vt_solve1(luf, e, y);
+ /* compute y = inv(F') * y' */
+ luf_ft_solve(luf, y);
+ /* compute 1-norm of y = sum |y[i]| */
+ y_norm = 0.0;
+ for (i = 1; i <= n; i++)
+ y_norm += (y[i] >= 0.0 ? +y[i] : -y[i]);
+ /* z = inv(A) * y = inv(V) * inv(F) * y */
+ /* compute z' = inv(F) * y */
+ luf_f_solve(luf, y);
+ /* compute z = inv(V) * z' */
+ luf_v_solve(luf, y, z);
+ /* compute 1-norm of z = sum |z[i]| */
+ z_norm = 0.0;
+ for (i = 1; i <= n; i++)
+ z_norm += (z[i] >= 0.0 ? +z[i] : -z[i]);
+ /* estimate 1-norm of inv(A) = (1-norm of z) / (1-norm of y) */
+ return z_norm / y_norm;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/luf.h b/test/monniaux/glpk-4.65/src/bflib/luf.h
new file mode 100644
index 00000000..5634a753
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/luf.h
@@ -0,0 +1,227 @@
+/* luf.h (sparse LU-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#ifndef LUF_H
+#define LUF_H
+
+#include "sva.h"
+
+/***********************************************************************
+* The structure LUF describes sparse LU-factorization.
+*
+* The LU-factorization has the following format:
+*
+* A = F * V = P * L * U * Q, (1)
+*
+* F = P * L * P', (2)
+*
+* V = P * U * Q, (3)
+*
+* where A is a given (unsymmetric) square matrix, F and V are matrix
+* factors actually computed, L is a lower triangular matrix with unity
+* diagonal, U is an upper triangular matrix, P and Q are permutation
+* matrices, P' is a matrix transposed to P. All the matrices have the
+* same order n.
+*
+* Matrices F and V are stored in both row- and column-wise sparse
+* formats in the associated sparse vector area (SVA). Unity diagonal
+* elements of matrix F are not stored. Pivot elements of matrix V
+* (which correspond to diagonal elements of matrix U) are stored in
+* a separate ordinary array.
+*
+* Permutation matrices P and Q are stored in ordinary arrays in both
+* row- and column-like formats.
+*
+* Matrices L and U are completely defined by matrices F, V, P, and Q,
+* and therefore not stored explicitly. */
+
+typedef struct LUF LUF;
+
+struct LUF
+{ /* sparse LU-factorization */
+ int n;
+ /* order of matrices A, F, V, P, Q */
+ SVA *sva;
+ /* associated sparse vector area (SVA) used to store rows and
+ * columns of matrices F and V; note that different objects may
+ * share the same SVA */
+ /*--------------------------------------------------------------*/
+ /* matrix F in row-wise format */
+ /* during the factorization process this object is not used */
+ int fr_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ * row of matrix F */
+#if 0 + 0
+ int *fr_ptr = &sva->ptr[fr_ref-1];
+ /* fr_ptr[0] is not used;
+ * fr_ptr[i], 1 <= i <= n, is pointer to i-th row in SVA */
+ int *fr_len = &sva->len[fr_ref-1];
+ /* fr_len[0] is not used;
+ * fr_len[i], 1 <= i <= n, is length of i-th row */
+#endif
+ /*--------------------------------------------------------------*/
+ /* matrix F in column-wise format */
+ /* during the factorization process this object is constructed
+ * by columns */
+ int fc_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ * column of matrix F */
+#if 0 + 0
+ int *fc_ptr = &sva->ptr[fc_ref-1];
+ /* fc_ptr[0] is not used;
+ * fc_ptr[j], 1 <= j <= n, is pointer to j-th column in SVA */
+ int *fc_len = &sva->len[fc_ref-1];
+ /* fc_len[0] is not used;
+ * fc_len[j], 1 <= j <= n, is length of j-th column */
+#endif
+ /*--------------------------------------------------------------*/
+ /* matrix V in row-wise format */
+ int vr_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ * row of matrix V */
+#if 0 + 0
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ /* vr_ptr[0] is not used;
+ * vr_ptr[i], 1 <= i <= n, is pointer to i-th row in SVA */
+ int *vr_len = &sva->len[vr_ref-1];
+ /* vr_len[0] is not used;
+ * vr_len[i], 1 <= i <= n, is length of i-th row */
+ int *vr_cap = &sva->cap[vr_ref-1];
+ /* vr_cap[0] is not used;
+ * vr_cap[i], 1 <= i <= n, is capacity of i-th row */
+#endif
+ double *vr_piv; /* double vr_piv[1+n]; */
+ /* vr_piv[0] is not used;
+ * vr_piv[i], 1 <= i <= n, is pivot element of i-th row */
+ /*--------------------------------------------------------------*/
+ /* matrix V in column-wise format */
+ /* during the factorization process this object contains only the
+ * patterns (row indices) of columns of the active submatrix */
+ int vc_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ * column of matrix V */
+#if 0 + 0
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ /* vc_ptr[0] is not used;
+ * vc_ptr[j], 1 <= j <= n, is pointer to j-th column in SVA */
+ int *vc_len = &sva->len[vc_ref-1];
+ /* vc_len[0] is not used;
+ * vc_len[j], 1 <= j <= n, is length of j-th column */
+ int *vc_cap = &sva->cap[vc_ref-1];
+ /* vc_cap[0] is not used;
+ * vc_cap[j], 1 <= j <= n, is capacity of j-th column */
+#endif
+ /*--------------------------------------------------------------*/
+ /* matrix P */
+ int *pp_ind; /* int pp_ind[1+n]; */
+ /* pp_ind[i] = j means that P[i,j] = 1 */
+ int *pp_inv; /* int pp_inv[1+n]; */
+ /* pp_inv[j] = i means that P[i,j] = 1 */
+ /* if i-th row or column of matrix F is i'-th row or column of
+ * matrix L, or if i-th row of matrix V is i'-th row of matrix U,
+ * then pp_ind[i] = i' and pp_inv[i'] = i */
+ /*--------------------------------------------------------------*/
+ /* matrix Q */
+ int *qq_ind; /* int qq_ind[1+n]; */
+ /* qq_ind[i] = j means that Q[i,j] = 1 */
+ int *qq_inv; /* int qq_inv[1+n]; */
+ /* qq_inv[j] = i means that Q[i,j] = 1 */
+ /* if j-th column of matrix V is j'-th column of matrix U, then
+ * qq_ind[j'] = j and qq_inv[j] = j' */
+};
+
+#define luf_swap_u_rows(i1, i2) \
+ do \
+ { int j1, j2; \
+ j1 = pp_inv[i1], j2 = pp_inv[i2]; \
+ pp_ind[j1] = i2, pp_inv[i2] = j1; \
+ pp_ind[j2] = i1, pp_inv[i1] = j2; \
+ } while (0)
+/* swap rows i1 and i2 of matrix U = P'* V * Q' */
+
+#define luf_swap_u_cols(j1, j2) \
+ do \
+ { int i1, i2; \
+ i1 = qq_ind[j1], i2 = qq_ind[j2]; \
+ qq_ind[j1] = i2, qq_inv[i2] = j1; \
+ qq_ind[j2] = i1, qq_inv[i1] = j2; \
+ } while (0)
+/* swap columns j1 and j2 of matrix U = P'* V * Q' */
+
+#define luf_store_v_cols _glp_luf_store_v_cols
+int luf_store_v_cols(LUF *luf, int (*col)(void *info, int j, int ind[],
+ double val[]), void *info, int ind[], double val[]);
+/* store matrix V = A in column-wise format */
+
+#define luf_check_all _glp_luf_check_all
+void luf_check_all(LUF *luf, int k);
+/* check LU-factorization before k-th elimination step */
+
+#define luf_build_v_rows _glp_luf_build_v_rows
+void luf_build_v_rows(LUF *luf, int len[/*1+n*/]);
+/* build matrix V in row-wise format */
+
+#define luf_build_f_rows _glp_luf_build_f_rows
+void luf_build_f_rows(LUF *luf, int len[/*1+n*/]);
+/* build matrix F in row-wise format */
+
+#define luf_build_v_cols _glp_luf_build_v_cols
+void luf_build_v_cols(LUF *luf, int updat, int len[/*1+n*/]);
+/* build matrix V in column-wise format */
+
+#define luf_check_f_rc _glp_luf_check_f_rc
+void luf_check_f_rc(LUF *luf);
+/* check rows and columns of matrix F */
+
+#define luf_check_v_rc _glp_luf_check_v_rc
+void luf_check_v_rc(LUF *luf);
+/* check rows and columns of matrix V */
+
+#define luf_f_solve _glp_luf_f_solve
+void luf_f_solve(LUF *luf, double x[/*1+n*/]);
+/* solve system F * x = b */
+
+#define luf_ft_solve _glp_luf_ft_solve
+void luf_ft_solve(LUF *luf, double x[/*1+n*/]);
+/* solve system F' * x = b */
+
+#define luf_v_solve _glp_luf_v_solve
+void luf_v_solve(LUF *luf, double b[/*1+n*/], double x[/*1+n*/]);
+/* solve system V * x = b */
+
+#define luf_vt_solve _glp_luf_vt_solve
+void luf_vt_solve(LUF *luf, double b[/*1+n*/], double x[/*1+n*/]);
+/* solve system V' * x = b */
+
+#define luf_vt_solve1 _glp_luf_vt_solve1
+void luf_vt_solve1(LUF *luf, double e[/*1+n*/], double y[/*1+n*/]);
+/* solve system V' * y = e' to cause growth in y */
+
+#define luf_estimate_norm _glp_luf_estimate_norm
+double luf_estimate_norm(LUF *luf, double w1[/*1+n*/], double
+ w2[/*1+n*/]);
+/* estimate 1-norm of inv(A) */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/lufint.c b/test/monniaux/glpk-4.65/src/bflib/lufint.c
new file mode 100644
index 00000000..7cd00924
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/lufint.c
@@ -0,0 +1,182 @@
+/* lufint.c (interface to LU-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "lufint.h"
+
+LUFINT *lufint_create(void)
+{ /* create interface to LU-factorization */
+ LUFINT *fi;
+ fi = talloc(1, LUFINT);
+ fi->n_max = 0;
+ fi->valid = 0;
+ fi->sva = NULL;
+ fi->luf = NULL;
+ fi->sgf = NULL;
+ fi->sva_n_max = fi->sva_size = 0;
+ fi->delta_n0 = fi->delta_n = 0;
+ fi->sgf_updat = 0;
+ fi->sgf_piv_tol = 0.10;
+ fi->sgf_piv_lim = 4;
+ fi->sgf_suhl = 1;
+ fi->sgf_eps_tol = DBL_EPSILON;
+ return fi;
+}
+
+int lufint_factorize(LUFINT *fi, int n, int (*col)(void *info, int j,
+ int ind[], double val[]), void *info)
+{ /* compute LU-factorization of specified matrix A */
+ SVA *sva;
+ LUF *luf;
+ SGF *sgf;
+ int k;
+ xassert(n > 0);
+ fi->valid = 0;
+ /* create sparse vector area (SVA), if necessary */
+ sva = fi->sva;
+ if (sva == NULL)
+ { int sva_n_max = fi->sva_n_max;
+ int sva_size = fi->sva_size;
+ if (sva_n_max == 0)
+ sva_n_max = 4 * n;
+ if (sva_size == 0)
+ sva_size = 10 * n;
+ sva = fi->sva = sva_create_area(sva_n_max, sva_size);
+ }
+ /* allocate/reallocate underlying objects, if necessary */
+ if (fi->n_max < n)
+ { int n_max = fi->n_max;
+ if (n_max == 0)
+ n_max = fi->n_max = n + fi->delta_n0;
+ else
+ n_max = fi->n_max = n + fi->delta_n;
+ xassert(n_max >= n);
+ /* allocate/reallocate LU-factorization (LUF) */
+ luf = fi->luf;
+ if (luf == NULL)
+ { luf = fi->luf = talloc(1, LUF);
+ memset(luf, 0, sizeof(LUF));
+ luf->sva = sva;
+ }
+ else
+ { tfree(luf->vr_piv);
+ tfree(luf->pp_ind);
+ tfree(luf->pp_inv);
+ tfree(luf->qq_ind);
+ tfree(luf->qq_inv);
+ }
+ luf->vr_piv = talloc(1+n_max, double);
+ luf->pp_ind = talloc(1+n_max, int);
+ luf->pp_inv = talloc(1+n_max, int);
+ luf->qq_ind = talloc(1+n_max, int);
+ luf->qq_inv = talloc(1+n_max, int);
+ /* allocate/reallocate factorizer workspace (SGF) */
+ sgf = fi->sgf;
+ if (sgf == NULL)
+ { sgf = fi->sgf = talloc(1, SGF);
+ memset(sgf, 0, sizeof(SGF));
+ sgf->luf = luf;
+ }
+ else
+ { tfree(sgf->rs_head);
+ tfree(sgf->rs_prev);
+ tfree(sgf->rs_next);
+ tfree(sgf->cs_head);
+ tfree(sgf->cs_prev);
+ tfree(sgf->cs_next);
+ tfree(sgf->vr_max);
+ tfree(sgf->flag);
+ tfree(sgf->work);
+ }
+ sgf->rs_head = talloc(1+n_max, int);
+ sgf->rs_prev = talloc(1+n_max, int);
+ sgf->rs_next = talloc(1+n_max, int);
+ sgf->cs_head = talloc(1+n_max, int);
+ sgf->cs_prev = talloc(1+n_max, int);
+ sgf->cs_next = talloc(1+n_max, int);
+ sgf->vr_max = talloc(1+n_max, double);
+ sgf->flag = talloc(1+n_max, char);
+ sgf->work = talloc(1+n_max, double);
+ }
+ luf = fi->luf;
+ sgf = fi->sgf;
+#if 1 /* FIXME */
+ /* initialize SVA */
+ sva->n = 0;
+ sva->m_ptr = 1;
+ sva->r_ptr = sva->size + 1;
+ sva->head = sva->tail = 0;
+#endif
+ /* allocate sparse vectors in SVA */
+ luf->n = n;
+ luf->fr_ref = sva_alloc_vecs(sva, n);
+ luf->fc_ref = sva_alloc_vecs(sva, n);
+ luf->vr_ref = sva_alloc_vecs(sva, n);
+ luf->vc_ref = sva_alloc_vecs(sva, n);
+ /* store matrix V = A in column-wise format */
+ luf_store_v_cols(luf, col, info, sgf->rs_prev, sgf->work);
+ /* setup factorizer control parameters */
+ sgf->updat = fi->sgf_updat;
+ sgf->piv_tol = fi->sgf_piv_tol;
+ sgf->piv_lim = fi->sgf_piv_lim;
+ sgf->suhl = fi->sgf_suhl;
+ sgf->eps_tol = fi->sgf_eps_tol;
+ /* compute LU-factorization of specified matrix A */
+ k = sgf_factorize(sgf, 1);
+ if (k == 0)
+ fi->valid = 1;
+ return k;
+}
+
+void lufint_delete(LUFINT *fi)
+{ /* delete interface to LU-factorization */
+ SVA *sva = fi->sva;
+ LUF *luf = fi->luf;
+ SGF *sgf = fi->sgf;
+ if (sva != NULL)
+ sva_delete_area(sva);
+ if (luf != NULL)
+ { tfree(luf->vr_piv);
+ tfree(luf->pp_ind);
+ tfree(luf->pp_inv);
+ tfree(luf->qq_ind);
+ tfree(luf->qq_inv);
+ tfree(luf);
+ }
+ if (sgf != NULL)
+ { tfree(sgf->rs_head);
+ tfree(sgf->rs_prev);
+ tfree(sgf->rs_next);
+ tfree(sgf->cs_head);
+ tfree(sgf->cs_prev);
+ tfree(sgf->cs_next);
+ tfree(sgf->vr_max);
+ tfree(sgf->flag);
+ tfree(sgf->work);
+ tfree(sgf);
+ }
+ tfree(fi);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/lufint.h b/test/monniaux/glpk-4.65/src/bflib/lufint.h
new file mode 100644
index 00000000..b3ad5b64
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/lufint.h
@@ -0,0 +1,73 @@
+/* lufint.h (interface to LU-factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#ifndef LUFINT_H
+#define LUFINT_H
+
+#include "sgf.h"
+
+typedef struct LUFINT LUFINT;
+
+struct LUFINT
+{ /* interface to LU-factorization */
+ int n_max;
+ /* maximal value of n (increased automatically) */
+ int valid;
+ /* factorization is valid only if this flag is set */
+ SVA *sva;
+ /* sparse vector area (SVA) */
+ LUF *luf;
+ /* sparse LU-factorization */
+ SGF *sgf;
+ /* sparse Gaussian factorizer workspace */
+ /*--------------------------------------------------------------*/
+ /* control parameters */
+ int sva_n_max, sva_size;
+ /* parameters passed to sva_create_area */
+ int delta_n0, delta_n;
+ /* if n_max = 0, set n_max = n + delta_n0
+ * if n_max < n, set n_max = n + delta_n */
+ int sgf_updat;
+ double sgf_piv_tol;
+ int sgf_piv_lim;
+ int sgf_suhl;
+ double sgf_eps_tol;
+ /* factorizer control parameters */
+};
+
+#define lufint_create _glp_lufint_create
+LUFINT *lufint_create(void);
+/* create interface to LU-factorization */
+
+#define lufint_factorize _glp_lufint_factorize
+int lufint_factorize(LUFINT *fi, int n, int (*col)(void *info, int j,
+ int ind[], double val[]), void *info);
+/* compute LU-factorization of specified matrix A */
+
+#define lufint_delete _glp_lufint_delete
+void lufint_delete(LUFINT *fi);
+/* delete interface to LU-factorization */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/scf.c b/test/monniaux/glpk-4.65/src/bflib/scf.c
new file mode 100644
index 00000000..556b1911
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/scf.c
@@ -0,0 +1,523 @@
+/* scf.c (sparse updatable Schur-complement-based factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2013-2014 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "scf.h"
+
+/***********************************************************************
+* scf_r0_solve - solve system R0 * x = b or R0'* x = b
+*
+* This routine solves the system R0 * x = b (if tr is zero) or the
+* system R0'* x = b (if tr is non-zero), where R0 is the left factor
+* of the initial matrix A0 = R0 * S0.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n0], where n0 is the order of the
+* matrix R0. On exit the array x will contain elements of the solution
+* vector in the same locations. */
+
+void scf_r0_solve(SCF *scf, int tr, double x[/*1+n0*/])
+{ switch (scf->type)
+ { case 1:
+ /* A0 = F0 * V0, so R0 = F0 */
+ if (!tr)
+ luf_f_solve(scf->a0.luf, x);
+ else
+ luf_ft_solve(scf->a0.luf, x);
+ break;
+ case 2:
+ /* A0 = I * A0, so R0 = I */
+ break;
+ default:
+ xassert(scf != scf);
+ }
+ return;
+}
+
+/***********************************************************************
+* scf_s0_solve - solve system S0 * x = b or S0'* x = b
+*
+* This routine solves the system S0 * x = b (if tr is zero) or the
+* system S0'* x = b (if tr is non-zero), where S0 is the right factor
+* of the initial matrix A0 = R0 * S0.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n0], where n0 is the order of the
+* matrix S0. On exit the array x will contain elements of the solution
+* vector in the same locations.
+*
+* The routine uses locations [1], ..., [n0] of three working arrays
+* w1, w2, and w3. (In case of type = 1 arrays w2 and w3 are not used
+* and can be specified as NULL.) */
+
+void scf_s0_solve(SCF *scf, int tr, double x[/*1+n0*/],
+ double w1[/*1+n0*/], double w2[/*1+n0*/], double w3[/*1+n0*/])
+{ int n0 = scf->n0;
+ switch (scf->type)
+ { case 1:
+ /* A0 = F0 * V0, so S0 = V0 */
+ if (!tr)
+ luf_v_solve(scf->a0.luf, x, w1);
+ else
+ luf_vt_solve(scf->a0.luf, x, w1);
+ break;
+ case 2:
+ /* A0 = I * A0, so S0 = A0 */
+ if (!tr)
+ btf_a_solve(scf->a0.btf, x, w1, w2, w3);
+ else
+ btf_at_solve(scf->a0.btf, x, w1, w2, w3);
+ break;
+ default:
+ xassert(scf != scf);
+ }
+ memcpy(&x[1], &w1[1], n0 * sizeof(double));
+ return;
+}
+
+/***********************************************************************
+* scf_r_prod - compute product y := y + alpha * R * x
+*
+* This routine computes the product y := y + alpha * R * x, where
+* x is a n0-vector, alpha is a scalar, y is a nn-vector.
+*
+* Since matrix R is available by rows, the product components are
+* computed as inner products:
+*
+* y[i] = y[i] + alpha * (i-th row of R) * x
+*
+* for i = 1, 2, ..., nn. */
+
+void scf_r_prod(SCF *scf, double y[/*1+nn*/], double a, const double
+ x[/*1+n0*/])
+{ int nn = scf->nn;
+ SVA *sva = scf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int rr_ref = scf->rr_ref;
+ int *rr_ptr = &sva->ptr[rr_ref-1];
+ int *rr_len = &sva->len[rr_ref-1];
+ int i, ptr, end;
+ double t;
+ for (i = 1; i <= nn; i++)
+ { /* t := (i-th row of R) * x */
+ t = 0.0;
+ for (end = (ptr = rr_ptr[i]) + rr_len[i]; ptr < end; ptr++)
+ t += sv_val[ptr] * x[sv_ind[ptr]];
+ /* y[i] := y[i] + alpha * t */
+ y[i] += a * t;
+ }
+ return;
+}
+
+/***********************************************************************
+* scf_rt_prod - compute product y := y + alpha * R'* x
+*
+* This routine computes the product y := y + alpha * R'* x, where
+* R' is a matrix transposed to R, x is a nn-vector, alpha is a scalar,
+* y is a n0-vector.
+*
+* Since matrix R is available by rows, the product is computed as a
+* linear combination:
+*
+* y := y + alpha * (R'[1] * x[1] + ... + R'[nn] * x[nn]),
+*
+* where R'[i] is i-th row of R. */
+
+void scf_rt_prod(SCF *scf, double y[/*1+n0*/], double a, const double
+ x[/*1+nn*/])
+{ int nn = scf->nn;
+ SVA *sva = scf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int rr_ref = scf->rr_ref;
+ int *rr_ptr = &sva->ptr[rr_ref-1];
+ int *rr_len = &sva->len[rr_ref-1];
+ int i, ptr, end;
+ double t;
+ for (i = 1; i <= nn; i++)
+ { if (x[i] == 0.0)
+ continue;
+ /* y := y + alpha * R'[i] * x[i] */
+ t = a * x[i];
+ for (end = (ptr = rr_ptr[i]) + rr_len[i]; ptr < end; ptr++)
+ y[sv_ind[ptr]] += sv_val[ptr] * t;
+ }
+ return;
+}
+
+/***********************************************************************
+* scf_s_prod - compute product y := y + alpha * S * x
+*
+* This routine computes the product y := y + alpha * S * x, where
+* x is a nn-vector, alpha is a scalar, y is a n0 vector.
+*
+* Since matrix S is available by columns, the product is computed as
+* a linear combination:
+*
+* y := y + alpha * (S[1] * x[1] + ... + S[nn] * x[nn]),
+*
+* where S[j] is j-th column of S. */
+
+void scf_s_prod(SCF *scf, double y[/*1+n0*/], double a, const double
+ x[/*1+nn*/])
+{ int nn = scf->nn;
+ SVA *sva = scf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int ss_ref = scf->ss_ref;
+ int *ss_ptr = &sva->ptr[ss_ref-1];
+ int *ss_len = &sva->len[ss_ref-1];
+ int j, ptr, end;
+ double t;
+ for (j = 1; j <= nn; j++)
+ { if (x[j] == 0.0)
+ continue;
+ /* y := y + alpha * S[j] * x[j] */
+ t = a * x[j];
+ for (end = (ptr = ss_ptr[j]) + ss_len[j]; ptr < end; ptr++)
+ y[sv_ind[ptr]] += sv_val[ptr] * t;
+ }
+ return;
+}
+
+/***********************************************************************
+* scf_st_prod - compute product y := y + alpha * S'* x
+*
+* This routine computes the product y := y + alpha * S'* x, where
+* S' is a matrix transposed to S, x is a n0-vector, alpha is a scalar,
+* y is a nn-vector.
+*
+* Since matrix S is available by columns, the product components are
+* computed as inner products:
+*
+* y[j] := y[j] + alpha * (j-th column of S) * x
+*
+* for j = 1, 2, ..., nn. */
+
+void scf_st_prod(SCF *scf, double y[/*1+nn*/], double a, const double
+ x[/*1+n0*/])
+{ int nn = scf->nn;
+ SVA *sva = scf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int ss_ref = scf->ss_ref;
+ int *ss_ptr = &sva->ptr[ss_ref-1];
+ int *ss_len = &sva->len[ss_ref-1];
+ int j, ptr, end;
+ double t;
+ for (j = 1; j <= nn; j++)
+ { /* t := (j-th column of S) * x */
+ t = 0.0;
+ for (end = (ptr = ss_ptr[j]) + ss_len[j]; ptr < end; ptr++)
+ t += sv_val[ptr] * x[sv_ind[ptr]];
+ /* y[j] := y[j] + alpha * t */
+ y[j] += a * t;
+ }
+ return;
+}
+
+/***********************************************************************
+* scf_a_solve - solve system A * x = b
+*
+* This routine solves the system A * x = b, where A is the current
+* matrix.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix A. On exit the array x will contain elements of the solution
+* vector in the same locations.
+*
+* For details see the program documentation. */
+
+void scf_a_solve(SCF *scf, double x[/*1+n*/],
+ double w[/*1+n0+nn*/], double work1[/*1+max(n0,nn)*/],
+ double work2[/*1+n*/], double work3[/*1+n*/])
+{ int n = scf->n;
+ int n0 = scf->n0;
+ int nn = scf->nn;
+ int *pp_ind = scf->pp_ind;
+ int *qq_inv = scf->qq_inv;
+ int i, ii;
+ /* (u1, u2) := inv(P) * (b, 0) */
+ for (ii = 1; ii <= n0+nn; ii++)
+ { i = pp_ind[ii];
+#if 1 /* FIXME: currently P = I */
+ xassert(i == ii);
+#endif
+ w[ii] = (i <= n ? x[i] : 0.0);
+ }
+ /* v1 := inv(R0) * u1 */
+ scf_r0_solve(scf, 0, &w[0]);
+ /* v2 := u2 - R * v1 */
+ scf_r_prod(scf, &w[n0], -1.0, &w[0]);
+ /* w2 := inv(C) * v2 */
+ ifu_a_solve(&scf->ifu, &w[n0], work1);
+ /* w1 := inv(S0) * (v1 - S * w2) */
+ scf_s_prod(scf, &w[0], -1.0, &w[n0]);
+ scf_s0_solve(scf, 0, &w[0], work1, work2, work3);
+ /* (x, x~) := inv(Q) * (w1, w2); x~ is not needed */
+ for (i = 1; i <= n; i++)
+ x[i] = w[qq_inv[i]];
+ return;
+}
+
+/***********************************************************************
+* scf_at_solve - solve system A'* x = b
+*
+* This routine solves the system A'* x = b, where A' is a matrix
+* transposed to the current matrix A.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix A. On exit the array x will contain elements of the solution
+* vector in the same locations.
+*
+* For details see the program documentation. */
+
+void scf_at_solve(SCF *scf, double x[/*1+n*/],
+ double w[/*1+n0+nn*/], double work1[/*1+max(n0,nn)*/],
+ double work2[/*1+n*/], double work3[/*1+n*/])
+{ int n = scf->n;
+ int n0 = scf->n0;
+ int nn = scf->nn;
+ int *pp_inv = scf->pp_inv;
+ int *qq_ind = scf->qq_ind;
+ int i, ii;
+ /* (u1, u2) := Q * (b, 0) */
+ for (ii = 1; ii <= n0+nn; ii++)
+ { i = qq_ind[ii];
+ w[ii] = (i <= n ? x[i] : 0.0);
+ }
+ /* v1 := inv(S0') * u1 */
+ scf_s0_solve(scf, 1, &w[0], work1, work2, work3);
+ /* v2 := inv(C') * (u2 - S'* v1) */
+ scf_st_prod(scf, &w[n0], -1.0, &w[0]);
+ ifu_at_solve(&scf->ifu, &w[n0], work1);
+ /* w2 := v2 */
+ /* nop */
+ /* w1 := inv(R0') * (v1 - R'* w2) */
+ scf_rt_prod(scf, &w[0], -1.0, &w[n0]);
+ scf_r0_solve(scf, 1, &w[0]);
+ /* compute (x, x~) := P * (w1, w2); x~ is not needed */
+ for (i = 1; i <= n; i++)
+ {
+#if 1 /* FIXME: currently P = I */
+ xassert(pp_inv[i] == i);
+#endif
+ x[i] = w[pp_inv[i]];
+ }
+ return;
+}
+
+/***********************************************************************
+* scf_add_r_row - add new row to matrix R
+*
+* This routine adds new (nn+1)-th row to matrix R, whose elements are
+* specified in locations w[1,...,n0]. */
+
+void scf_add_r_row(SCF *scf, const double w[/*1+n0*/])
+{ int n0 = scf->n0;
+ int nn = scf->nn;
+ SVA *sva = scf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int rr_ref = scf->rr_ref;
+ int *rr_ptr = &sva->ptr[rr_ref-1];
+ int *rr_len = &sva->len[rr_ref-1];
+ int j, len, ptr;
+ xassert(0 <= nn && nn < scf->nn_max);
+ /* determine length of new row */
+ len = 0;
+ for (j = 1; j <= n0; j++)
+ { if (w[j] != 0.0)
+ len++;
+ }
+ /* reserve locations for new row in static part of SVA */
+ if (len > 0)
+ { if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_reserve_cap(sva, rr_ref + nn, len);
+ }
+ /* store new row in sparse format */
+ ptr = rr_ptr[nn+1];
+ for (j = 1; j <= n0; j++)
+ { if (w[j] != 0.0)
+ { sv_ind[ptr] = j;
+ sv_val[ptr] = w[j];
+ ptr++;
+ }
+ }
+ xassert(ptr - rr_ptr[nn+1] == len);
+ rr_len[nn+1] = len;
+#ifdef GLP_DEBUG
+ sva_check_area(sva);
+#endif
+ return;
+}
+
+/***********************************************************************
+* scf_add_s_col - add new column to matrix S
+*
+* This routine adds new (nn+1)-th column to matrix S, whose elements
+* are specified in locations v[1,...,n0]. */
+
+void scf_add_s_col(SCF *scf, const double v[/*1+n0*/])
+{ int n0 = scf->n0;
+ int nn = scf->nn;
+ SVA *sva = scf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int ss_ref = scf->ss_ref;
+ int *ss_ptr = &sva->ptr[ss_ref-1];
+ int *ss_len = &sva->len[ss_ref-1];
+ int i, len, ptr;
+ xassert(0 <= nn && nn < scf->nn_max);
+ /* determine length of new column */
+ len = 0;
+ for (i = 1; i <= n0; i++)
+ { if (v[i] != 0.0)
+ len++;
+ }
+ /* reserve locations for new column in static part of SVA */
+ if (len > 0)
+ { if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_reserve_cap(sva, ss_ref + nn, len);
+ }
+ /* store new column in sparse format */
+ ptr = ss_ptr[nn+1];
+ for (i = 1; i <= n0; i++)
+ { if (v[i] != 0.0)
+ { sv_ind[ptr] = i;
+ sv_val[ptr] = v[i];
+ ptr++;
+ }
+ }
+ xassert(ptr - ss_ptr[nn+1] == len);
+ ss_len[nn+1] = len;
+#ifdef GLP_DEBUG
+ sva_check_area(sva);
+#endif
+ return;
+}
+
+/***********************************************************************
+* scf_update_aug - update factorization of augmented matrix
+*
+* Given factorization of the current augmented matrix:
+*
+* ( A0 A1 ) ( R0 ) ( S0 S )
+* ( ) = ( ) ( ),
+* ( A2 A3 ) ( R I ) ( C )
+*
+* this routine computes factorization of the new augmented matrix:
+*
+* ( A0 | A1 b )
+* ( ---+------ ) ( A0 A1^ ) ( R0 ) ( S0 S^ )
+* ( A2 | A3 f ) = ( ) = ( ) ( ),
+* ( | ) ( A2^ A3^ ) ( R^ I ) ( C^ )
+* ( d' | g' h )
+*
+* where b and d are specified n0-vectors, f and g are specified
+* nn-vectors, and h is a specified scalar. (Note that corresponding
+* arrays are clobbered on exit.)
+*
+* The parameter upd specifies how to update factorization of the Schur
+* complement C:
+*
+* 1 Bartels-Golub updating.
+*
+* 2 Givens rotations updating.
+*
+* The working arrays w1, w2, and w3 are used in the same way as in the
+* routine scf_s0_solve.
+*
+* RETURNS
+*
+* 0 Factorization has been successfully updated.
+*
+* 1 Updating limit has been reached.
+*
+* 2 Updating IFU-factorization of matrix C failed.
+*
+* For details see the program documentation. */
+
+int scf_update_aug(SCF *scf, double b[/*1+n0*/], double d[/*1+n0*/],
+ double f[/*1+nn*/], double g[/*1+nn*/], double h, int upd,
+ double w1[/*1+n0*/], double w2[/*1+n0*/], double w3[/*1+n0*/])
+{ int n0 = scf->n0;
+ int k, ret;
+ double *v, *w, *x, *y, z;
+ if (scf->nn == scf->nn_max)
+ { /* updating limit has been reached */
+ return 1;
+ }
+ /* v := inv(R0) * b */
+ scf_r0_solve(scf, 0, (v = b));
+ /* w := inv(S0') * d */
+ scf_s0_solve(scf, 1, (w = d), w1, w2, w3);
+ /* x := f - R * v */
+ scf_r_prod(scf, (x = f), -1.0, v);
+ /* y := g - S'* w */
+ scf_st_prod(scf, (y = g), -1.0, w);
+ /* z := h - v'* w */
+ z = h;
+ for (k = 1; k <= n0; k++)
+ z -= v[k] * w[k];
+ /* new R := R with row w added */
+ scf_add_r_row(scf, w);
+ /* new S := S with column v added */
+ scf_add_s_col(scf, v);
+ /* update IFU-factorization of C */
+ switch (upd)
+ { case 1:
+ ret = ifu_bg_update(&scf->ifu, x, y, z);
+ break;
+ case 2:
+ ret = ifu_gr_update(&scf->ifu, x, y, z);
+ break;
+ default:
+ xassert(upd != upd);
+ }
+ if (ret != 0)
+ { /* updating IFU-factorization failed */
+ return 2;
+ }
+ /* increase number of additional rows and columns */
+ scf->nn++;
+ /* expand P and Q */
+ k = n0 + scf->nn;
+ scf->pp_ind[k] = scf->pp_inv[k] = k;
+ scf->qq_ind[k] = scf->qq_inv[k] = k;
+ /* factorization has been successfully updated */
+ return 0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/scf.h b/test/monniaux/glpk-4.65/src/bflib/scf.h
new file mode 100644
index 00000000..69d8cfc2
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/scf.h
@@ -0,0 +1,211 @@
+/* scf.h (sparse updatable Schur-complement-based factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2013-2014 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/>.
+***********************************************************************/
+
+#ifndef SCF_H
+#define SCF_H
+
+#include "btf.h"
+#include "ifu.h"
+#include "luf.h"
+
+/***********************************************************************
+* The structure SCF describes sparse updatable factorization based on
+* Schur complement.
+*
+* The SCF-factorization has the following format:
+*
+* ( A A1~ ) ( A0 A1 ) ( R0 ) ( S0 S )
+* ( ) = P ( ) Q = P ( ) ( ) Q, (1)
+* ( A2~ A3~ ) ( A2 A3 ) ( R I ) ( C )
+*
+* where:
+*
+* A is current (unsymmetric) square matrix (not stored);
+*
+* A1~, A2~, A3~ are some additional matrices (not stored);
+*
+* A0 is initial (unsymmetric) square matrix (not stored);
+*
+* A1, A2, A3 are some additional matrices (not stored);
+*
+* R0 and S0 are matrices that define factorization of the initial
+* matrix A0 = R0 * S0 (stored in an invertable form);
+*
+* R is a matrix defined from R * S0 = A2, so R = A2 * inv(S0) (stored
+* in row-wise sparse format);
+*
+* S is a matrix defined from R0 * S = A1, so S = inv(R0) * A1 (stored
+* in column-wise sparse format);
+*
+* C is Schur complement (to matrix A0) defined from R * S + C = A3,
+* so C = A3 - R * S = A3 - A2 * inv(A0) * A1 (stored in an invertable
+* form).
+*
+* P, Q are permutation matrices (stored in both row- and column-like
+* formats). */
+
+typedef struct SCF SCF;
+
+struct SCF
+{ /* Schur-complement-based factorization */
+ int n;
+ /* order of current matrix A */
+ /*--------------------------------------------------------------*/
+ /* initial matrix A0 = R0 * S0 of order n0 in invertable form */
+ int n0;
+ /* order of matrix A0 */
+ int type;
+ /* type of factorization used:
+ * 1 - LU-factorization (R0 = F0, S0 = V0)
+ * 2 - BT-factorization (R0 = I, S0 = A0) */
+ union
+ { LUF *luf; /* type = 1 */
+ BTF *btf; /* type = 2 */
+ } a0;
+ /* factorization of matrix A0 */
+ /*--------------------------------------------------------------*/
+ /* augmented matrix (A0, A1; A2, A3) of order n0+nn */
+ int nn_max;
+ /* maximal number of additional rows and columns in the augmented
+ * matrix (this limits the number of updates) */
+ int nn;
+ /* current number of additional rows and columns in the augmented
+ * matrix, 0 <= nn <= nn_max */
+ SVA *sva;
+ /* associated sparse vector area (SVA) used to store rows of
+ * matrix R and columns of matrix S */
+ /*--------------------------------------------------------------*/
+ /* nn*n0-matrix R in row-wise format */
+ int rr_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ * row of matrix R */
+#if 0 + 0
+ int *rr_ptr = &sva->ptr[rr_ref-1];
+ /* rr_ptr[0] is not used;
+ * rr_ptr[i], 1 <= i <= nn, is pointer to i-th row in SVA;
+ * rr_ptr[nn+1,...,nn_max] are reserved locations */
+ int *rr_len = &sva->len[rr_ref-1];
+ /* rr_len[0] is not used;
+ * rr_len[i], 1 <= i <= nn, is length of i-th row;
+ * rr_len[nn+1,...,nn_max] are reserved locations */
+#endif
+ /*--------------------------------------------------------------*/
+ /* n0*nn-matrix S in column-wise format */
+ int ss_ref;
+ /* reference number of sparse vector in SVA, which is the first
+ * column of matrix S */
+#if 0 + 0
+ int *ss_ptr = &sva->ptr[ss_ref-1];
+ /* ss_ptr[0] is not used;
+ * ss_ptr[j], 1 <= j <= nn, is pointer to j-th column in SVA;
+ * ss_ptr[nn+1,...,nn_max] are reserved locations */
+ int *ss_len = &sva->len[ss_ref-1];
+ /* ss_len[0] is not used;
+ * ss_len[j], 1 <= j <= nn, is length of j-th column;
+ * ss_len[nn+1,...,nn_max] are reserved locations */
+#endif
+ /*--------------------------------------------------------------*/
+ /* Schur complement C of order nn in invertable form */
+ IFU ifu;
+ /* IFU-factorization of matrix C */
+ /*--------------------------------------------------------------*/
+ /* permutation matrix P of order n0+nn */
+ int *pp_ind; /* int pp_ind[1+n0+nn_max]; */
+ /* pp_ind[i] = j means that P[i,j] = 1 */
+ int *pp_inv; /* int pp_inv[1+n0+nn_max]; */
+ /* pp_inv[j] = i means that P[i,j] = 1 */
+ /*--------------------------------------------------------------*/
+ /* permutation matrix Q of order n0+nn */
+ int *qq_ind; /* int qq_ind[1+n0+nn_max]; */
+ /* qq_ind[i] = j means that Q[i,j] = 1 */
+ int *qq_inv; /* int qq_inv[1+n0+nn_max]; */
+ /* qq_inv[j] = i means that Q[i,j] = 1 */
+};
+
+#define scf_swap_q_cols(j1, j2) \
+ do \
+ { int i1, i2; \
+ i1 = qq_inv[j1], i2 = qq_inv[j2]; \
+ qq_ind[i1] = j2, qq_inv[j2] = i1; \
+ qq_ind[i2] = j1, qq_inv[j1] = i2; \
+ } while (0)
+/* swap columns j1 and j2 of permutation matrix Q */
+
+#define scf_r0_solve _glp_scf_r0_solve
+void scf_r0_solve(SCF *scf, int tr, double x[/*1+n0*/]);
+/* solve system R0 * x = b or R0'* x = b */
+
+#define scf_s0_solve _glp_scf_s0_solve
+void scf_s0_solve(SCF *scf, int tr, double x[/*1+n0*/],
+ double w1[/*1+n0*/], double w2[/*1+n0*/], double w3[/*1+n0*/]);
+/* solve system S0 * x = b or S0'* x = b */
+
+#define scf_r_prod _glp_scf_r_prod
+void scf_r_prod(SCF *scf, double y[/*1+nn*/], double a, const double
+ x[/*1+n0*/]);
+/* compute product y := y + alpha * R * x */
+
+#define scf_rt_prod _glp_scf_rt_prod
+void scf_rt_prod(SCF *scf, double y[/*1+n0*/], double a, const double
+ x[/*1+nn*/]);
+/* compute product y := y + alpha * R'* x */
+
+#define scf_s_prod _glp_scf_s_prod
+void scf_s_prod(SCF *scf, double y[/*1+n0*/], double a, const double
+ x[/*1+nn*/]);
+/* compute product y := y + alpha * S * x */
+
+#define scf_st_prod _glp_scf_st_prod
+void scf_st_prod(SCF *scf, double y[/*1+nn*/], double a, const double
+ x[/*1+n0*/]);
+/* compute product y := y + alpha * S'* x */
+
+#define scf_a_solve _glp_scf_a_solve
+void scf_a_solve(SCF *scf, double x[/*1+n*/],
+ double w[/*1+n0+nn*/], double work1[/*1+max(n0,nn)*/],
+ double work2[/*1+n*/], double work3[/*1+n*/]);
+/* solve system A * x = b */
+
+#define scf_at_solve _glp_scf_at_solve
+void scf_at_solve(SCF *scf, double x[/*1+n*/],
+ double w[/*1+n0+nn*/], double work1[/*1+max(n0,nn)*/],
+ double work2[/*1+n*/], double work3[/*1+n*/]);
+/* solve system A'* x = b */
+
+#define scf_add_r_row _glp_scf_add_r_row
+void scf_add_r_row(SCF *scf, const double w[/*1+n0*/]);
+/* add new row to matrix R */
+
+#define scf_add_s_col _glp_scf_add_s_col
+void scf_add_s_col(SCF *scf, const double v[/*1+n0*/]);
+/* add new column to matrix S */
+
+#define scf_update_aug _glp_scf_update_aug
+int scf_update_aug(SCF *scf, double b[/*1+n0*/], double d[/*1+n0*/],
+ double f[/*1+nn*/], double g[/*1+nn*/], double h, int upd,
+ double w1[/*1+n0*/], double w2[/*1+n0*/], double w3[/*1+n0*/]);
+/* update factorization of augmented matrix */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/scfint.c b/test/monniaux/glpk-4.65/src/bflib/scfint.c
new file mode 100644
index 00000000..06aa8f7d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/scfint.c
@@ -0,0 +1,255 @@
+/* scfint.c (interface to Schur-complement-based factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2013-2014 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "scfint.h"
+
+SCFINT *scfint_create(int type)
+{ /* create interface to SC-factorization */
+ SCFINT *fi;
+ fi = talloc(1, SCFINT);
+ memset(fi, 0, sizeof(SCFINT));
+ switch ((fi->scf.type = type))
+ { case 1:
+ fi->u.lufi = lufint_create();
+ break;
+ case 2:
+ fi->u.btfi = btfint_create();
+ break;
+ default:
+ xassert(type != type);
+ }
+ return fi;
+}
+
+int scfint_factorize(SCFINT *fi, int n, int (*col)(void *info, int j,
+ int ind[], double val[]), void *info)
+{ /* compute SC-factorization of specified matrix A */
+ int nn_max, old_n0_max, n0_max, k, ret;
+ xassert(n > 0);
+ fi->valid = 0;
+ /* get required value of nn_max */
+ nn_max = fi->nn_max;
+ if (nn_max == 0)
+ nn_max = 100;
+ xassert(nn_max > 0);
+ /* compute factorization of specified matrix A */
+ switch (fi->scf.type)
+ { case 1:
+ old_n0_max = fi->u.lufi->n_max;
+ fi->u.lufi->sva_n_max = 4 * n + 2 * nn_max;
+ ret = lufint_factorize(fi->u.lufi, n, col, info);
+ n0_max = fi->u.lufi->n_max;
+ fi->scf.sva = fi->u.lufi->sva;
+ fi->scf.a0.luf = fi->u.lufi->luf;
+ break;
+ case 2:
+ old_n0_max = fi->u.btfi->n_max;
+ fi->u.btfi->sva_n_max = 6 * n + 2 * nn_max;
+ ret = btfint_factorize(fi->u.btfi, n, col, info);
+ n0_max = fi->u.btfi->n_max;
+ fi->scf.sva = fi->u.btfi->sva;
+ fi->scf.a0.btf = fi->u.btfi->btf;
+ break;
+ default:
+ xassert(fi != fi);
+ }
+ /* allocate/reallocate arrays, if necessary */
+ if (old_n0_max < n0_max)
+ { if (fi->w1 != NULL)
+ tfree(fi->w1);
+ if (fi->w2 != NULL)
+ tfree(fi->w2);
+ if (fi->w3 != NULL)
+ tfree(fi->w3);
+ fi->w1 = talloc(1+n0_max, double);
+ fi->w2 = talloc(1+n0_max, double);
+ fi->w3 = talloc(1+n0_max, double);
+ }
+ if (fi->scf.nn_max != nn_max)
+ { if (fi->scf.ifu.f != NULL)
+ tfree(fi->scf.ifu.f);
+ if (fi->scf.ifu.u != NULL)
+ tfree(fi->scf.ifu.u);
+ fi->scf.ifu.f = talloc(nn_max * nn_max, double);
+ fi->scf.ifu.u = talloc(nn_max * nn_max, double);
+ }
+ if (old_n0_max < n0_max || fi->scf.nn_max != nn_max)
+ { if (fi->scf.pp_ind != NULL)
+ tfree(fi->scf.pp_ind);
+ if (fi->scf.pp_inv != NULL)
+ tfree(fi->scf.pp_inv);
+ if (fi->scf.qq_ind != NULL)
+ tfree(fi->scf.qq_ind);
+ if (fi->scf.qq_inv != NULL)
+ tfree(fi->scf.qq_inv);
+ if (fi->w4 != NULL)
+ tfree(fi->w4);
+ if (fi->w5 != NULL)
+ tfree(fi->w5);
+ fi->scf.pp_ind = talloc(1+n0_max+nn_max, int);
+ fi->scf.pp_inv = talloc(1+n0_max+nn_max, int);
+ fi->scf.qq_ind = talloc(1+n0_max+nn_max, int);
+ fi->scf.qq_inv = talloc(1+n0_max+nn_max, int);
+ fi->w4 = talloc(1+n0_max+nn_max, double);
+ fi->w5 = talloc(1+n0_max+nn_max, double);
+ }
+ /* initialize SC-factorization */
+ fi->scf.n = n;
+ fi->scf.n0 = n;
+ fi->scf.nn_max = nn_max;
+ fi->scf.nn = 0;
+ fi->scf.rr_ref = sva_alloc_vecs(fi->scf.sva, nn_max);
+ fi->scf.ss_ref = sva_alloc_vecs(fi->scf.sva, nn_max);
+ fi->scf.ifu.n_max = nn_max;
+ fi->scf.ifu.n = 0;
+ for (k = 1; k <= n; k++)
+ { fi->scf.pp_ind[k] = k;
+ fi->scf.pp_inv[k] = k;
+ fi->scf.qq_ind[k] = k;
+ fi->scf.qq_inv[k] = k;
+ }
+ /* set validation flag */
+ if (ret == 0)
+ fi->valid = 1;
+ return ret;
+}
+
+int scfint_update(SCFINT *fi, int upd, int j, int len, const int ind[],
+ const double val[])
+{ /* update SC-factorization after replacing j-th column of A */
+ int n = fi->scf.n;
+ int n0 = fi->scf.n0;
+ int nn = fi->scf.nn;
+ int *pp_ind = fi->scf.pp_ind;
+ int *qq_ind = fi->scf.qq_ind;
+ int *qq_inv = fi->scf.qq_inv;
+ double *bf = fi->w4;
+ double *dg = fi->w5;
+ int k, t, ret;
+ xassert(fi->valid);
+ xassert(0 <= n && n <= n0+nn);
+ /* (b, f) := inv(P) * (beta, 0) */
+ for (k = 1; k <= n0+nn; k++)
+ bf[k] = 0.0;
+ for (t = 1; t <= len; t++)
+ { k = ind[t];
+ xassert(1 <= k && k <= n);
+#if 1 /* FIXME: currently P = I */
+ xassert(pp_ind[k] == k);
+#endif
+ xassert(bf[k] == 0.0);
+ xassert(val[t] != 0.0);
+ bf[k] = val[t];
+ }
+ /* (d, g) := Q * (cj, 0) */
+ for (k = 1; k <= n0+nn; k++)
+ dg[k] = 0.0;
+ xassert(1 <= j && j <= n);
+ dg[fi->scf.qq_inv[j]] = 1;
+ /* update factorization of augmented matrix */
+ ret = scf_update_aug(&fi->scf, &bf[0], &dg[0], &bf[n0], &dg[n0],
+ 0.0, upd, fi->w1, fi->w2, fi->w3);
+ if (ret == 0)
+ { /* swap j-th and last columns of new matrix Q */
+ scf_swap_q_cols(j, n0+nn+1);
+ }
+ else
+ { /* updating failed */
+ fi->valid = 0;
+ }
+ return ret;
+}
+
+void scfint_ftran(SCFINT *fi, double x[])
+{ /* solve system A * x = b */
+ xassert(fi->valid);
+ scf_a_solve(&fi->scf, x, fi->w4, fi->w5, fi->w1, fi->w2);
+ return;
+}
+
+void scfint_btran(SCFINT *fi, double x[])
+{ /* solve system A'* x = b */
+ xassert(fi->valid);
+ scf_at_solve(&fi->scf, x, fi->w4, fi->w5, fi->w1, fi->w2);
+ return;
+}
+
+double scfint_estimate(SCFINT *fi)
+{ /* estimate 1-norm of inv(A) */
+ double norm;
+ xassert(fi->valid);
+ xassert(fi->scf.n == fi->scf.n0);
+ switch (fi->scf.type)
+ { case 1:
+ norm = luf_estimate_norm(fi->scf.a0.luf, fi->w1, fi->w2);
+ break;
+ case 2:
+ norm = btf_estimate_norm(fi->scf.a0.btf, fi->w1, fi->w2,
+ fi->w3, fi->w4);
+ break;
+ default:
+ xassert(fi != fi);
+ }
+ return norm;
+}
+
+void scfint_delete(SCFINT *fi)
+{ /* delete interface to SC-factorization */
+ switch (fi->scf.type)
+ { case 1:
+ lufint_delete(fi->u.lufi);
+ break;
+ case 2:
+ btfint_delete(fi->u.btfi);
+ break;
+ default:
+ xassert(fi != fi);
+ }
+ if (fi->scf.ifu.f != NULL)
+ tfree(fi->scf.ifu.f);
+ if (fi->scf.ifu.u != NULL)
+ tfree(fi->scf.ifu.u);
+ if (fi->scf.pp_ind != NULL)
+ tfree(fi->scf.pp_ind);
+ if (fi->scf.pp_inv != NULL)
+ tfree(fi->scf.pp_inv);
+ if (fi->scf.qq_ind != NULL)
+ tfree(fi->scf.qq_ind);
+ if (fi->scf.qq_inv != NULL)
+ tfree(fi->scf.qq_inv);
+ if (fi->w1 != NULL)
+ tfree(fi->w1);
+ if (fi->w2 != NULL)
+ tfree(fi->w2);
+ if (fi->w3 != NULL)
+ tfree(fi->w3);
+ if (fi->w4 != NULL)
+ tfree(fi->w4);
+ if (fi->w5 != NULL)
+ tfree(fi->w5);
+ tfree(fi);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/scfint.h b/test/monniaux/glpk-4.65/src/bflib/scfint.h
new file mode 100644
index 00000000..3e56355b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/scfint.h
@@ -0,0 +1,89 @@
+/* scfint.h (interface to Schur-complement-based factorization) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2013-2014 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/>.
+***********************************************************************/
+
+#ifndef SCFINT_H
+#define SCFINT_H
+
+#include "scf.h"
+#include "lufint.h"
+#include "btfint.h"
+
+typedef struct SCFINT SCFINT;
+
+struct SCFINT
+{ /* interface to SC-factorization */
+ int valid;
+ /* factorization is valid only if this flag is set */
+ SCF scf;
+ /* Schur-complement based factorization */
+ union
+ { LUFINT *lufi; /* scf.type = 1 */
+ BTFINT *btfi; /* scf.type = 2 */
+ } u;
+ /* interface to factorize initial matrix A0 */
+ /*--------------------------------------------------------------*/
+ /* working arrays */
+ double *w1; /* double w1[1+n0_max]; */
+ double *w2; /* double w2[1+n0_max]; */
+ double *w3; /* double w3[1+n0_max]; */
+ double *w4; /* double w4[1+n0_max+nn_max]; */
+ double *w5; /* double w5[1+n0_max+nn_max]; */
+ /*--------------------------------------------------------------*/
+ /* control parameters */
+ int nn_max;
+ /* required maximal number of updates */
+};
+
+#define scfint_create _glp_scfint_create
+SCFINT *scfint_create(int type);
+/* create interface to SC-factorization */
+
+#define scfint_factorize _glp_scfint_factorize
+int scfint_factorize(SCFINT *fi, int n, int (*col)(void *info, int j,
+ int ind[], double val[]), void *info);
+/* compute SC-factorization of specified matrix A */
+
+#define scfint_update _glp_scfint_update
+int scfint_update(SCFINT *fi, int upd, int j, int len, const int ind[],
+ const double val[]);
+/* update SC-factorization after replacing j-th column of A */
+
+#define scfint_ftran _glp_scfint_ftran
+void scfint_ftran(SCFINT *fi, double x[]);
+/* solve system A * x = b */
+
+#define scfint_btran _glp_scfint_btran
+void scfint_btran(SCFINT *fi, double x[]);
+/* solve system A'* x = b */
+
+#define scfint_estimate _glp_scfint_estimate
+double scfint_estimate(SCFINT *fi);
+/* estimate 1-norm of inv(A) */
+
+#define scfint_delete _glp_scfint_delete
+void scfint_delete(SCFINT *fi);
+/* delete interface to SC-factorization */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/sgf.c b/test/monniaux/glpk-4.65/src/bflib/sgf.c
new file mode 100644
index 00000000..1c1f49a6
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/sgf.c
@@ -0,0 +1,1443 @@
+/* sgf.c (sparse Gaussian factorizer) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2015 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "sgf.h"
+
+/***********************************************************************
+* sgf_reduce_nuc - initial reordering to minimize nucleus size
+*
+* On entry to this routine it is assumed that V = A and F = P = Q = I,
+* where A is the original matrix to be factorized. It is also assumed
+* that matrix V = A is stored in both row- and column-wise formats.
+*
+* This routine performs (implicit) non-symmetric permutations of rows
+* and columns of matrix U = P'* V * Q' to reduce it to the form:
+*
+* 1 k1 k2 n
+* 1 x x x x x x x x x x
+* . x x x x x x x x x
+* . . x x x x x x x x
+* k1 . . . * * * * x x x
+* . . . * * * * x x x
+* . . . * * * * x x x
+* k2 . . . * * * * x x x
+* . . . . . . . x x x
+* . . . . . . . . x x
+* n . . . . . . . . . x
+*
+* where non-zeros in rows and columns k1, k1+1, ..., k2 constitute so
+* called nucleus ('*'), whose size is minimized by the routine.
+*
+* The numbers k1 and k2 are returned by the routine on exit. Usually,
+* if the nucleus exists, 1 <= k1 < k2 <= n. However, if the resultant
+* matrix U is upper triangular (has no nucleus), k1 = n+1 and k2 = n.
+*
+* Note that the routines sgf_choose_pivot and sgf_eliminate perform
+* exactly the same transformations (by processing row and columns
+* singletons), so preliminary minimization of the nucleus may not be
+* used. However, processing row and column singletons by the routines
+* sgf_minimize_nuc and sgf_singl_phase is more efficient. */
+
+#if 1 /* 21/II-2016 */
+/* Normally this routine returns zero. If the matrix is structurally
+* singular, the routine returns non-zero. */
+#endif
+
+int sgf_reduce_nuc(LUF *luf, int *k1_, int *k2_, int cnt[/*1+n*/],
+ int list[/*1+n*/])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int *pp_ind = luf->pp_ind;
+ int *pp_inv = luf->pp_inv;
+ int *qq_ind = luf->qq_ind;
+ int *qq_inv = luf->qq_inv;
+ int i, ii, j, jj, k1, k2, ns, ptr, end;
+ /* initial nucleus is U = V = A */
+ k1 = 1, k2 = n;
+ /*--------------------------------------------------------------*/
+ /* process column singletons */
+ /*--------------------------------------------------------------*/
+ /* determine initial counts of columns of V and initialize list
+ * of active column singletons */
+ ns = 0; /* number of active column singletons */
+ for (j = 1; j <= n; j++)
+ { if ((cnt[j] = vc_len[j]) == 1)
+ list[++ns] = j;
+ }
+ /* process active column singletons */
+ while (ns > 0)
+ { /* column singleton is in j-th column of V */
+ j = list[ns--];
+#if 1 /* 21/II-2016 */
+ if (cnt[j] == 0)
+ { /* j-th column in the current nucleus is actually empty */
+ /* this happened because on a previous step in the nucleus
+ * there were two or more identical column singletons (that
+ * means structural singularity), so removing one of them
+ * from the nucleus made other columns empty */
+ return 1;
+ }
+#endif
+ /* find i-th row of V containing column singleton */
+ ptr = vc_ptr[j];
+ end = ptr + vc_len[j];
+ for (; pp_ind[i = sv_ind[ptr]] < k1; ptr++)
+ /* nop */;
+ xassert(ptr < end);
+ /* permute rows and columns of U to move column singleton to
+ * position u[k1,k1] */
+ ii = pp_ind[i];
+ luf_swap_u_rows(k1, ii);
+ jj = qq_inv[j];
+ luf_swap_u_cols(k1, jj);
+ /* nucleus size decreased */
+ k1++;
+ /* walk thru i-th row of V and decrease column counts; this
+ * may cause new column singletons to appear */
+ ptr = vr_ptr[i];
+ end = ptr + vr_len[i];
+ for (; ptr < end; ptr++)
+ { if (--(cnt[j = sv_ind[ptr]]) == 1)
+ list[++ns] = j;
+ }
+ }
+ /* nucleus begins at k1-th row/column of U */
+ if (k1 > n)
+ { /* U is upper triangular; no nucleus exist */
+ goto done;
+ }
+ /*--------------------------------------------------------------*/
+ /* process row singletons */
+ /*--------------------------------------------------------------*/
+ /* determine initial counts of rows of V and initialize list of
+ * active row singletons */
+ ns = 0; /* number of active row singletons */
+ for (i = 1; i <= n; i++)
+ { if (pp_ind[i] < k1)
+ { /* corresponding row of U is above its k1-th row; set its
+ * count to zero to prevent including it in active list */
+ cnt[i] = 0;
+ }
+ else if ((cnt[i] = vr_len[i]) == 1)
+ list[++ns] = i;
+ }
+ /* process active row singletons */
+ while (ns > 0)
+ { /* row singleton is in i-th row of V */
+ i = list[ns--];
+#if 1 /* 21/II-2016 */
+ if (cnt[i] == 0)
+ { /* i-th row in the current nucleus is actually empty */
+ /* (see comments above for similar case of empty column) */
+ return 2;
+ }
+#endif
+ /* find j-th column of V containing row singleton */
+ ptr = vr_ptr[i];
+ end = ptr + vr_len[i];
+ for (; qq_inv[j = sv_ind[ptr]] > k2; ptr++)
+ /* nop */;
+ xassert(ptr < end);
+ /* permute rows and columns of U to move row singleton to
+ * position u[k2,k2] */
+ ii = pp_ind[i];
+ luf_swap_u_rows(k2, ii);
+ jj = qq_inv[j];
+ luf_swap_u_cols(k2, jj);
+ /* nucleus size decreased */
+ k2--;
+ /* walk thru j-th column of V and decrease row counts; this
+ * may cause new row singletons to appear */
+ ptr = vc_ptr[j];
+ end = ptr + vc_len[j];
+ for (; ptr < end; ptr++)
+ { if (--(cnt[i = sv_ind[ptr]]) == 1)
+ list[++ns] = i;
+ }
+ }
+ /* nucleus ends at k2-th row/column of U */
+ xassert(k1 < k2);
+done: *k1_ = k1, *k2_ = k2;
+ return 0;
+}
+
+/***********************************************************************
+* sgf_singl_phase - compute LU-factorization (singleton phase)
+*
+* It is assumed that on entry to the routine L = P'* F * P = F = I
+* and matrix U = P'* V * Q' has the following structure (provided by
+* the routine sgf_reduce_nuc):
+*
+* 1 k1 k2 n
+* 1 a a a b b b b c c c
+* . a a b b b b c c c
+* . . a b b b b c c c
+* k1 . . . * * * * d d d
+* . . . * * * * d d d
+* . . . * * * * d d d
+* k2 . . . * * * * d d d
+* . . . . . . . e e e
+* . . . . . . . . e e
+* n . . . . . . . . . e
+*
+* First, the routine performs (implicit) symmetric permutations of
+* rows and columns of matrix U to place them in the following order:
+*
+* 1, 2, ..., k1-1; n, n-1, ..., k2+1; k1, k1+1, ..., k2
+*
+* This changes the structure of matrix U as follows:
+*
+* 1 k1 k2' n
+* 1 a a a c c c b b b b
+* . a a c c c b b b b
+* . . a c c c b b b b
+* k1 . . . e . . . . . .
+* . . . e e . . . . .
+* . . . e e e . . . .
+* k2'. . . d d d * * * *
+* . . . d d d * * * *
+* . . . d d d * * * *
+* n . . . d d d * * * *
+*
+* where k2' = n - k2 + k1.
+*
+* Then the routine performs elementary gaussian transformations to
+* eliminate subdiagonal elements in columns k1, ..., k2'-1 of U. The
+* effect is the same as if the routine sgf_eliminate would be called
+* for k = 1, ..., k2'-1 using diagonal elements u[k,k] as pivots.
+*
+* After elimination matrices L and U becomes the following:
+*
+* 1 k1 k2' n 1 k1 k2' n
+* 1 1 . . . . . . . . . 1 a a a c c c b b b b
+* . 1 . . . . . . . . . a a c c c b b b b
+* . . 1 . . . . . . . . . a c c c b b b b
+* k1 . . . 1 . . . . . . k1 . . . e . . . . . .
+* . . . e'1 . . . . . . . . . e . . . . .
+* . . . e'e'1 . . . . . . . . . e . . . .
+* k2'. . . d'd'd'1 . . . k2'. . . . . . * * * *
+* . . . d'd'd'. 1 . . . . . . . . * * * *
+* . . . d'd'd'. . 1 . . . . . . . * * * *
+* n . . . d'd'd'. . . 1 n . . . . . . * * * *
+*
+* matrix L matrix U
+*
+* where columns k1, ..., k2'-1 of L consist of subdiagonal elements
+* of initial matrix U divided by pivots u[k,k].
+*
+* On exit the routine returns k2', the elimination step number, from
+* which computing of the factorization should be continued. Note that
+* k2' = n+1 means that matrix U is already upper triangular. */
+
+int sgf_singl_phase(LUF *luf, int k1, int k2, int updat,
+ int ind[/*1+n*/], double val[/*1+n*/])
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int fc_ref = luf->fc_ref;
+ int *fc_ptr = &sva->ptr[fc_ref-1];
+ int *fc_len = &sva->len[fc_ref-1];
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ double *vr_piv = luf->vr_piv;
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int *pp_ind = luf->pp_ind;
+ int *pp_inv = luf->pp_inv;
+ int *qq_ind = luf->qq_ind;
+ int *qq_inv = luf->qq_inv;
+ int i, j, k, ptr, ptr1, end, len;
+ double piv;
+ /* (see routine sgf_reduce_nuc) */
+ xassert((1 <= k1 && k1 < k2 && k2 <= n)
+ || (k1 == n+1 && k2 == n));
+ /* perform symmetric permutations of rows/columns of U */
+ for (k = k1; k <= k2; k++)
+ pp_ind[pp_inv[k]] = qq_inv[qq_ind[k]] = k - k2 + n;
+ for (k = k2+1; k <= n; k++)
+ pp_ind[pp_inv[k]] = qq_inv[qq_ind[k]] = n - k + k1;
+ for (k = 1; k <= n; k++)
+ pp_inv[pp_ind[k]] = qq_ind[qq_inv[k]] = k;
+ /* determine k2' */
+ k2 = n - k2 + k1;
+ /* process rows and columns of V corresponding to rows and
+ * columns 1, ..., k1-1 of U */
+ for (k = 1; k < k1; k++)
+ { /* k-th row of U = i-th row of V */
+ i = pp_inv[k];
+ /* find pivot u[k,k] = v[i,j] in i-th row of V */
+ ptr = vr_ptr[i];
+ end = ptr + vr_len[i];
+ for (; qq_inv[sv_ind[ptr]] != k; ptr++)
+ /* nop */;
+ xassert(ptr < end);
+ /* store pivot */
+ vr_piv[i] = sv_val[ptr];
+ /* and remove it from i-th row of V */
+ sv_ind[ptr] = sv_ind[end-1];
+ sv_val[ptr] = sv_val[end-1];
+ vr_len[i]--;
+ /* clear column of V corresponding to k-th column of U */
+ vc_len[qq_ind[k]] = 0;
+ }
+ /* clear rows of V corresponding to rows k1, ..., k2'-1 of U */
+ for (k = k1; k < k2; k++)
+ vr_len[pp_inv[k]] = 0;
+ /* process rows and columns of V corresponding to rows and
+ * columns k2', ..., n of U */
+ for (k = k2; k <= n; k++)
+ { /* k-th row of U = i-th row of V */
+ i = pp_inv[k];
+ /* remove elements from i-th row of V that correspond to
+ * elements u[k,k1], ..., u[k,k2'-1] */
+ ptr = ptr1 = vr_ptr[i];
+ end = ptr + vr_len[i];
+ for (; ptr < end; ptr++)
+ { if (qq_inv[sv_ind[ptr]] >= k2)
+ { sv_ind[ptr1] = sv_ind[ptr];
+ sv_val[ptr1] = sv_val[ptr];
+ ptr1++;
+ }
+ }
+ vr_len[i] = ptr1 - vr_ptr[i];
+ /* k-th column of U = j-th column of V */
+ j = qq_ind[k];
+ /* remove elements from j-th column of V that correspond to
+ * elements u[1,k], ..., u[k1-1,k] */
+ ptr = ptr1 = vc_ptr[j];
+ end = ptr + vc_len[j];
+ for (; ptr < end; ptr++)
+ { if (pp_ind[sv_ind[ptr]] >= k2)
+ /* element value is not needed in this case */
+ sv_ind[ptr1++] = sv_ind[ptr];
+ }
+ vc_len[j] = ptr1 - vc_ptr[j];
+ }
+ /* process columns of V corresponding to columns k1, ..., k2'-1
+ * of U, build columns of F */
+ for (k = k1; k < k2; k++)
+ { /* k-th column of U = j-th column of V */
+ j = qq_ind[k];
+ /* remove elements from j-th column of V that correspond to
+ * pivot (diagonal) element u[k,k] and subdiagonal elements
+ * u[k+1,k], ..., u[n,k]; subdiagonal elements are stored for
+ * further addition to matrix F */
+ len = 0;
+ piv = 0.0;
+ ptr = vc_ptr[j];
+ end = ptr + vc_len[j];
+ for (; ptr < end; ptr++)
+ { i = sv_ind[ptr]; /* v[i,j] */
+ if (pp_ind[i] == k)
+ { /* store pivot v[i,j] = u[k,k] */
+ piv = vr_piv[i] = sv_val[ptr];
+ }
+ else if (pp_ind[i] > k)
+ { /* store subdiagonal element v[i,j] = u[i',k] */
+ len++;
+ ind[len] = i;
+ val[len] = sv_val[ptr];
+ }
+ }
+ /* clear j-th column of V = k-th column of U */
+ vc_len[j] = 0;
+ /* build k-th column of L = j-th column of F */
+ j = pp_inv[k];
+ xassert(piv != 0.0);
+ if (len > 0)
+ { if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_reserve_cap(sva, fc_ref-1+j, len);
+ for (ptr = fc_ptr[j], ptr1 = 1; ptr1 <= len; ptr++, ptr1++)
+ { sv_ind[ptr] = ind[ptr1];
+ sv_val[ptr] = val[ptr1] / piv;
+ }
+ fc_len[j] = len;
+ }
+ }
+ /* if it is not planned to update matrix V, relocate all its
+ * non-active rows corresponding to rows 1, ..., k2'-1 of U to
+ * the right (static) part of SVA */
+ if (!updat)
+ { for (k = 1; k < k2; k++)
+ { i = pp_inv[k];
+ len = vr_len[i];
+ if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_make_static(sva, vr_ref-1+i);
+ }
+ }
+ /* elimination steps 1, ..., k2'-1 have been performed */
+ return k2;
+}
+
+/***********************************************************************
+* sgf_choose_pivot - choose pivot element v[p,q]
+*
+* This routine chooses pivot element v[p,q], k <= p, q <= n, in the
+* active submatrix of matrix V = P * U * Q, where k is the number of
+* current elimination step, 1 <= k <= n.
+*
+* It is assumed that on entry to the routine matrix U = P'* V * Q' has
+* the following partially triangularized form:
+*
+* 1 k n
+* 1 x x x x x x x x x x
+* . x x x x x x x x x
+* . . x x x x x x x x
+* . . . x x x x x x x
+* k . . . . * * * * * *
+* . . . . * * * * * *
+* . . . . * * * * * *
+* . . . . * * * * * *
+* . . . . * * * * * *
+* n . . . . * * * * * *
+*
+* where rows and columns k, k+1, ..., n belong to the active submatrix
+* (its elements are marked by '*').
+*
+* Since the matrix U is not stored, the routine works with the matrix
+* V = P * U * Q. It is assumed that the row-wise representation
+* corresponds to the matrix V, but the column-wise representation
+* corresponds to the active submatrix of the matrix V, i.e. elements,
+* which are not in the active submatrix, are not included in column
+* vectors. It is also assumed that each active row of the matrix V is
+* in the set R[len], where len is the number of non-zeros in the row,
+* and each active column of the matrix V is in the set C[len], where
+* len is the number of non-zeros in the column (in the latter case
+* only elements of the active submatrix are counted; such elements are
+* marked by '*' on the figure above).
+*
+* For the reason of numerical stability the routine applies so called
+* threshold pivoting proposed by J.Reid. It is assumed that an element
+* v[i,j] can be selected as a pivot candidate if it is not very small
+* (in magnitude) among other elements in the same row, i.e. if it
+* satisfies to the stability condition |v[i,j]| >= tol * max|v[i,*]|,
+* where 0 < tol < 1 is a given tolerance.
+*
+* In order to keep sparsity of the matrix V the routine uses Markowitz
+* strategy, trying to choose such element v[p,q], which satisfies to
+* the stability condition (see above) and has smallest Markowitz cost
+* (nr[p]-1) * (nc[q]-1), where nr[p] and nc[q] are, resp., numbers of
+* non-zeros in p-th row and q-th column of the active submatrix.
+*
+* In order to reduce the search, i.e. not to walk through all elements
+* of the active submatrix, the routine uses a technique proposed by
+* I.Duff. This technique is based on using the sets R[len] and C[len]
+* of active rows and columns.
+*
+* If the pivot element v[p,q] has been chosen, the routine stores its
+* indices to locations *p and *q and returns zero. Otherwise, non-zero
+* is returned. */
+
+int sgf_choose_pivot(SGF *sgf, int *p_, int *q_)
+{ LUF *luf = sgf->luf;
+ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int *rs_head = sgf->rs_head;
+ int *rs_next = sgf->rs_next;
+ int *cs_head = sgf->cs_head;
+ int *cs_prev = sgf->cs_prev;
+ int *cs_next = sgf->cs_next;
+ double *vr_max = sgf->vr_max;
+ double piv_tol = sgf->piv_tol;
+ int piv_lim = sgf->piv_lim;
+ int suhl = sgf->suhl;
+ int i, i_ptr, i_end, j, j_ptr, j_end, len, min_i, min_j, min_len,
+ ncand, next_j, p, q;
+ double best, big, cost, temp;
+ /* no pivot candidate has been chosen so far */
+ p = q = 0, best = DBL_MAX, ncand = 0;
+ /* if the active submatrix contains a column having the only
+ * non-zero element (column singleton), choose it as the pivot */
+ j = cs_head[1];
+ if (j != 0)
+ { xassert(vc_len[j] == 1);
+ p = sv_ind[vc_ptr[j]], q = j;
+ goto done;
+ }
+ /* if the active submatrix contains a row having the only
+ * non-zero element (row singleton), choose it as the pivot */
+ i = rs_head[1];
+ if (i != 0)
+ { xassert(vr_len[i] == 1);
+ p = i, q = sv_ind[vr_ptr[i]];
+ goto done;
+ }
+ /* the active submatrix contains no singletons; walk thru its
+ * other non-empty rows and columns */
+ for (len = 2; len <= n; len++)
+ { /* consider active columns containing len non-zeros */
+ for (j = cs_head[len]; j != 0; j = next_j)
+ { /* save the number of next column of the same length */
+ next_j = cs_next[j];
+ /* find an element in j-th column, which is placed in the
+ * row with minimal number of non-zeros and satisfies to
+ * the stability condition (such element may not exist) */
+ min_i = min_j = 0, min_len = INT_MAX;
+ for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j];
+ j_ptr < j_end; j_ptr++)
+ { /* get row index of v[i,j] */
+ i = sv_ind[j_ptr];
+ /* if i-th row is not shorter, skip v[i,j] */
+ if (vr_len[i] >= min_len)
+ continue;
+ /* big := max|v[i,*]| */
+ if ((big = vr_max[i]) < 0.0)
+ { /* largest magnitude is unknown; compute it */
+ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i];
+ i_ptr < i_end; i_ptr++)
+ { if ((temp = sv_val[i_ptr]) < 0.0)
+ temp = -temp;
+ if (big < temp)
+ big = temp;
+ }
+ xassert(big > 0.0);
+ vr_max[i] = big;
+ }
+ /* find v[i,j] in i-th row */
+ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i];
+ sv_ind[i_ptr] != j; i_ptr++)
+ /* nop */;
+ xassert(i_ptr < i_end);
+ /* if |v[i,j]| < piv_tol * max|v[i,*]|, skip v[i,j] */
+ if ((temp = sv_val[i_ptr]) < 0.0)
+ temp = -temp;
+ if (temp < piv_tol * big)
+ continue;
+ /* v[i,j] is a better candidate */
+ min_i = i, min_j = j, min_len = vr_len[i];
+ /* if Markowitz cost of v[i,j] is not greater than
+ * (len-1)**2, v[i,j] can be chosen as the pivot right
+ * now; this heuristic reduces the search and works well
+ * in many cases */
+ if (min_len <= len)
+ { p = min_i, q = min_j;
+ goto done;
+ }
+ }
+ /* j-th column has been scanned */
+ if (min_i != 0)
+ { /* element v[min_i,min_j] is a next pivot candidate */
+ ncand++;
+ /* compute its Markowitz cost */
+ cost = (double)(min_len - 1) * (double)(len - 1);
+ /* if this element is better, choose it as the pivot */
+ if (cost < best)
+ p = min_i, q = min_j, best = cost;
+ /* if piv_lim candidates were considered, terminate
+ * the search, because it is doubtful that a much better
+ * candidate will be found */
+ if (ncand == piv_lim)
+ goto done;
+ }
+ else if (suhl)
+ { /* j-th column has no eligible elements that satisfy to
+ * the stability criterion; Uwe Suhl suggests to exclude
+ * such column from further considerations until it
+ * becomes a column singleton; in hard cases this may
+ * significantly reduce the time needed to choose the
+ * pivot element */
+ sgf_deactivate_col(j);
+ cs_prev[j] = cs_next[j] = j;
+ }
+ }
+ /* consider active rows containing len non-zeros */
+ for (i = rs_head[len]; i != 0; i = rs_next[i])
+ { /* big := max|v[i,*]| */
+ if ((big = vr_max[i]) < 0.0)
+ { /* largest magnitude is unknown; compute it */
+ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i];
+ i_ptr < i_end; i_ptr++)
+ { if ((temp = sv_val[i_ptr]) < 0.0)
+ temp = -temp;
+ if (big < temp)
+ big = temp;
+ }
+ xassert(big > 0.0);
+ vr_max[i] = big;
+ }
+ /* find an element in i-th row, which is placed in the
+ * column with minimal number of non-zeros and satisfies to
+ * the stability condition (such element always exists) */
+ min_i = min_j = 0, min_len = INT_MAX;
+ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i];
+ i_ptr < i_end; i_ptr++)
+ { /* get column index of v[i,j] */
+ j = sv_ind[i_ptr];
+ /* if j-th column is not shorter, skip v[i,j] */
+ if (vc_len[j] >= min_len)
+ continue;
+ /* if |v[i,j]| < piv_tol * max|v[i,*]|, skip v[i,j] */
+ if ((temp = sv_val[i_ptr]) < 0.0)
+ temp = -temp;
+ if (temp < piv_tol * big)
+ continue;
+ /* v[i,j] is a better candidate */
+ min_i = i, min_j = j, min_len = vc_len[j];
+ /* if Markowitz cost of v[i,j] is not greater than
+ * (len-1)**2, v[i,j] can be chosen as the pivot right
+ * now; this heuristic reduces the search and works well
+ * in many cases */
+ if (min_len <= len)
+ { p = min_i, q = min_j;
+ goto done;
+ }
+ }
+ /* i-th row has been scanned */
+ if (min_i != 0)
+ { /* element v[min_i,min_j] is a next pivot candidate */
+ ncand++;
+ /* compute its Markowitz cost */
+ cost = (double)(len - 1) * (double)(min_len - 1);
+ /* if this element is better, choose it as the pivot */
+ if (cost < best)
+ p = min_i, q = min_j, best = cost;
+ /* if piv_lim candidates were considered, terminate
+ * the search, because it is doubtful that a much better
+ * candidate will be found */
+ if (ncand == piv_lim)
+ goto done;
+ }
+ else
+ { /* this can never be */
+ xassert(min_i != min_i);
+ }
+ }
+ }
+done: /* report the pivot to the factorization routine */
+ *p_ = p, *q_ = q;
+ return (p == 0);
+}
+
+/***********************************************************************
+* sgf_eliminate - perform gaussian elimination
+*
+* This routine performs elementary gaussian transformations in order
+* to eliminate subdiagonal elements in k-th column of matrix
+* U = P'* V * Q' using pivot element u[k,k], where k is the number of
+* current elimination step, 1 <= k <= n.
+*
+* The parameters p and q specify, resp., row and column indices of the
+* pivot element v[p,q] = u[k,k].
+*
+* On entry the routine assumes that partially triangularized matrices
+* L = P'* F * P and U = P'* V * Q' have the following structure:
+*
+* 1 k n 1 k n
+* 1 1 . . . . . . . . . 1 x x x x x x x x x x
+* x 1 . . . . . . . . . x x x x x x x x x
+* x x 1 . . . . . . . . . x x x x x x x x
+* x x x 1 . . . . . . . . . x x x x x x x
+* k x x x x 1 . . . . . k . . . . * * * * * *
+* x x x x _ 1 . . . . . . . . # * * * * *
+* x x x x _ . 1 . . . . . . . # * * * * *
+* x x x x _ . . 1 . . . . . . # * * * * *
+* x x x x _ . . . 1 . . . . . # * * * * *
+* n x x x x _ . . . . 1 n . . . . # * * * * *
+*
+* matrix L matrix U
+*
+* where rows and columns k, k+1, ..., n of matrix U constitute the
+* active submatrix. Elements to be eliminated are marked by '#', and
+* other elements of the active submatrix are marked by '*'. May note
+* that each eliminated non-zero element u[i,k] of matrix U gives
+* corresponding non-zero element l[i,k] of matrix L (marked by '_').
+*
+* Actually all operations are performed on matrix V. It is assumed
+* that the row-wise representation corresponds to matrix V, but the
+* column-wise representation corresponds to the active submatrix of
+* matrix V (or, more precisely, to its pattern, because only row
+* indices for columns of the active submatrix are used on this stage).
+*
+* Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
+* elements u[i',k] = v[i,q], i'= k+1, k+2, ..., n, the routine applies
+* the following elementary gaussian transformations:
+*
+* (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
+*
+* where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier stored to
+* p-th column of matrix F to keep the main equality A = F * V
+* (corresponding elements l[i',k] of matrix L are marked by '_' on the
+* figure above).
+*
+* NOTE: On entry to the routine the working arrays flag and work
+* should contain zeros. This status is retained by the routine
+* on exit. */
+
+int sgf_eliminate(SGF *sgf, int p, int q)
+{ LUF *luf = sgf->luf;
+ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int fc_ref = luf->fc_ref;
+ int *fc_ptr = &sva->ptr[fc_ref-1];
+ int *fc_len = &sva->len[fc_ref-1];
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int *vr_cap = &sva->cap[vr_ref-1];
+ double *vr_piv = luf->vr_piv;
+ int vc_ref = luf->vc_ref;
+ int *vc_ptr = &sva->ptr[vc_ref-1];
+ int *vc_len = &sva->len[vc_ref-1];
+ int *vc_cap = &sva->cap[vc_ref-1];
+ int *rs_head = sgf->rs_head;
+ int *rs_prev = sgf->rs_prev;
+ int *rs_next = sgf->rs_next;
+ int *cs_head = sgf->cs_head;
+ int *cs_prev = sgf->cs_prev;
+ int *cs_next = sgf->cs_next;
+ double *vr_max = sgf->vr_max;
+ char *flag = sgf->flag;
+ double *work = sgf->work;
+ double eps_tol = sgf->eps_tol;
+ int nnz_diff = 0;
+ int fill, i, i_ptr, i_end, j, j_ptr, j_end, ptr, len, loc, loc1;
+ double vpq, fip, vij;
+ xassert(1 <= p && p <= n);
+ xassert(1 <= q && q <= n);
+ /* remove p-th row from the active set; this row will never
+ * return there */
+ sgf_deactivate_row(p);
+ /* process p-th (pivot) row */
+ ptr = 0;
+ for (i_end = (i_ptr = vr_ptr[p]) + vr_len[p];
+ i_ptr < i_end; i_ptr++)
+ { /* get column index of v[p,j] */
+ j = sv_ind[i_ptr];
+ if (j == q)
+ { /* save pointer to pivot v[p,q] */
+ ptr = i_ptr;
+ }
+ else
+ { /* store v[p,j], j != q, to working array */
+ flag[j] = 1;
+ work[j] = sv_val[i_ptr];
+ }
+ /* remove j-th column from the active set; q-th column will
+ * never return there while other columns will return to the
+ * active set with new length */
+ if (cs_next[j] == j)
+ { /* j-th column was marked by the pivoting routine according
+ * to Uwe Suhl's suggestion and is already inactive */
+ xassert(cs_prev[j] == j);
+ }
+ else
+ sgf_deactivate_col(j);
+ nnz_diff -= vc_len[j];
+ /* find and remove v[p,j] from j-th column */
+ for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j];
+ sv_ind[j_ptr] != p; j_ptr++)
+ /* nop */;
+ xassert(j_ptr < j_end);
+ sv_ind[j_ptr] = sv_ind[j_end-1];
+ vc_len[j]--;
+ }
+ /* save pivot v[p,q] and remove it from p-th row */
+ xassert(ptr > 0);
+ vpq = vr_piv[p] = sv_val[ptr];
+ sv_ind[ptr] = sv_ind[i_end-1];
+ sv_val[ptr] = sv_val[i_end-1];
+ vr_len[p]--;
+ /* if it is not planned to update matrix V, relocate p-th row to
+ * the right (static) part of SVA */
+ if (!sgf->updat)
+ { len = vr_len[p];
+ if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_make_static(sva, vr_ref-1+p);
+ }
+ /* copy the pattern (row indices) of q-th column of the active
+ * submatrix (from which v[p,q] has been just removed) to p-th
+ * column of matrix F (without unity diagonal element) */
+ len = vc_len[q];
+ if (len > 0)
+ { if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_reserve_cap(sva, fc_ref-1+p, len);
+ memcpy(&sv_ind[fc_ptr[p]], &sv_ind[vc_ptr[q]],
+ len * sizeof(int));
+ fc_len[p] = len;
+ }
+ /* make q-th column of the active submatrix empty */
+ vc_len[q] = 0;
+ /* transform non-pivot rows of the active submatrix */
+ for (loc = fc_len[p]-1; loc >= 0; loc--)
+ { /* get row index of v[i,q] = row index of f[i,p] */
+ i = sv_ind[fc_ptr[p] + loc];
+ xassert(i != p); /* v[p,q] was removed */
+ /* remove i-th row from the active set; this row will return
+ * there with new length */
+ sgf_deactivate_row(i);
+ /* find v[i,q] in i-th row */
+ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i];
+ sv_ind[i_ptr] != q; i_ptr++)
+ /* nop */;
+ xassert(i_ptr < i_end);
+ /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] */
+ fip = sv_val[fc_ptr[p] + loc] = sv_val[i_ptr] / vpq;
+ /* remove v[i,q] from i-th row */
+ sv_ind[i_ptr] = sv_ind[i_end-1];
+ sv_val[i_ptr] = sv_val[i_end-1];
+ vr_len[i]--;
+ /* perform elementary gaussian transformation:
+ * (i-th row) := (i-th row) - f[i,p] * (p-th row)
+ * note that p-th row of V, which is in the working array,
+ * doesn't contain pivot v[p,q], and i-th row of V doesn't
+ * contain v[i,q] to be eliminated */
+ /* walk thru i-th row and transform existing elements */
+ fill = vr_len[p];
+ for (i_end = (i_ptr = ptr = vr_ptr[i]) + vr_len[i];
+ i_ptr < i_end; i_ptr++)
+ { /* get column index and value of v[i,j] */
+ j = sv_ind[i_ptr];
+ vij = sv_val[i_ptr];
+ if (flag[j])
+ { /* v[p,j] != 0 */
+ flag[j] = 0, fill--;
+ /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
+ vij -= fip * work[j];
+ if (-eps_tol < vij && vij < +eps_tol)
+ { /* new v[i,j] is close to zero; remove it from the
+ * active submatrix, i.e. replace it by exact zero */
+ /* find and remove v[i,j] from j-th column */
+ for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j];
+ sv_ind[j_ptr] != i; j_ptr++)
+ /* nop */;
+ xassert(j_ptr < j_end);
+ sv_ind[j_ptr] = sv_ind[j_end-1];
+ vc_len[j]--;
+ continue;
+ }
+ }
+ /* keep new v[i,j] in i-th row */
+ sv_ind[ptr] = j;
+ sv_val[ptr] = vij;
+ ptr++;
+ }
+ /* (new length of i-th row may decrease because of numerical
+ * cancellation) */
+ vr_len[i] = len = ptr - vr_ptr[i];
+ /* now flag[*] is the pattern of the set v[p,*] \ v[i,*], and
+ * fill is the number of non-zeros in this set */
+ if (fill == 0)
+ { /* no fill-in occurs */
+ /* walk thru p-th row and restore the column flags */
+ for (i_end = (i_ptr = vr_ptr[p]) + vr_len[p];
+ i_ptr < i_end; i_ptr++)
+ flag[sv_ind[i_ptr]] = 1; /* v[p,j] != 0 */
+ goto skip;
+ }
+ /* up to fill new non-zero elements may appear in i-th row due
+ * to fill-in; reserve locations for these elements (note that
+ * actual length of i-th row is currently stored in len) */
+ if (vr_cap[i] < len + fill)
+ { if (sva->r_ptr - sva->m_ptr < len + fill)
+ { sva_more_space(sva, len + fill);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_enlarge_cap(sva, vr_ref-1+i, len + fill, 0);
+ }
+ vr_len[i] += fill;
+ /* walk thru p-th row and add new elements to i-th row */
+ for (loc1 = vr_len[p]-1; loc1 >= 0; loc1--)
+ { /* get column index of v[p,j] */
+ j = sv_ind[vr_ptr[p] + loc1];
+ if (!flag[j])
+ { /* restore j-th column flag */
+ flag[j] = 1;
+ /* v[i,j] was computed earlier on transforming existing
+ * elements of i-th row */
+ continue;
+ }
+ /* v[i,j] := 0 - f[i,p] * v[p,j] */
+ vij = - fip * work[j];
+ if (-eps_tol < vij && vij < +eps_tol)
+ { /* new v[i,j] is close to zero; do not add it to the
+ * active submatrix, i.e. replace it by exact zero */
+ continue;
+ }
+ /* add new v[i,j] to i-th row */
+ sv_ind[ptr = vr_ptr[i] + (len++)] = j;
+ sv_val[ptr] = vij;
+ /* add new v[i,j] to j-th column */
+ if (vc_cap[j] == vc_len[j])
+ { /* we reserve extra locations in j-th column to reduce
+ * further relocations of that column */
+#if 1 /* FIXME */
+ /* use control parameter to specify the number of extra
+ * locations reserved */
+ int need = vc_len[j] + 10;
+#endif
+ if (sva->r_ptr - sva->m_ptr < need)
+ { sva_more_space(sva, need);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_enlarge_cap(sva, vc_ref-1+j, need, 1);
+ }
+ sv_ind[vc_ptr[j] + (vc_len[j]++)] = i;
+ }
+ /* set final length of i-th row just transformed */
+ xassert(len <= vr_len[i]);
+ vr_len[i] = len;
+skip: /* return i-th row to the active set with new length */
+ sgf_activate_row(i);
+ /* since i-th row has been changed, largest magnitude of its
+ * elements becomes unknown */
+ vr_max[i] = -1.0;
+ }
+ /* walk thru p-th (pivot) row */
+ for (i_end = (i_ptr = vr_ptr[p]) + vr_len[p];
+ i_ptr < i_end; i_ptr++)
+ { /* get column index of v[p,j] */
+ j = sv_ind[i_ptr];
+ xassert(j != q); /* v[p,q] was removed */
+ /* return j-th column to the active set with new length */
+ if (cs_next[j] == j && vc_len[j] != 1)
+ { /* j-th column was marked by the pivoting routine and it is
+ * still not a column singleton, so leave it incative */
+ xassert(cs_prev[j] == j);
+ }
+ else
+ sgf_activate_col(j);
+ nnz_diff += vc_len[j];
+ /* restore zero content of the working arrays */
+ flag[j] = 0;
+ work[j] = 0.0;
+ }
+ /* return the difference between the numbers of non-zeros in the
+ * active submatrix on entry and on exit, resp. */
+ return nnz_diff;
+}
+
+/***********************************************************************
+* sgf_dense_lu - compute dense LU-factorization with full pivoting
+*
+* This routine performs Gaussian elimination with full pivoting to
+* compute dense LU-factorization of the specified matrix A of order n
+* in the form:
+*
+* A = P * L * U * Q, (1)
+*
+* where L is lower triangular matrix with unit diagonal, U is upper
+* triangular matrix, P and Q are permutation matrices.
+*
+* On entry to the routine elements of matrix A = (a[i,j]) should be
+* placed in the array elements a[0], ..., a[n^2-1] in dense row-wise
+* format. On exit from the routine matrix A is replaced by factors L
+* and U as follows:
+*
+* u[1,1] u[1,2] ... u[1,n-1] u[1,n]
+* l[2,1] u[2,2] ... u[2,n-1] u[2,n]
+* . . . . . . . . . . . . . .
+* l[n-1,1] l[n-1,2] u[n-1,n-1] u[n-1,n]
+* l[n,1] l[n,2] ... l[n,n-1] u[n,n]
+*
+* The unit diagonal elements of L are not stored.
+*
+* Information on permutations of rows and columns of active submatrix
+* during factorization is accumulated by the routine as follows. Every
+* time the routine permutes rows i and i' or columns j and j', it also
+* permutes elements r[i-1] and r[i'-1] or c[j-1] and c[j'-1], resp.
+* Thus, on entry to the routine elements r[0], r[1], ..., r[n-1] and
+* c[0], c[1], ..., c[n-1] should be initialized by some integers that
+* identify rows and columns of the original matrix A.
+*
+* If the factorization has been successfully computed, the routine
+* returns zero. Otherwise, if on k-th elimination step, 1 <= k <= n,
+* all elements of the active submatrix are close to zero, the routine
+* returns k, in which case a partial factorization is stored in the
+* array a. */
+
+int sgf_dense_lu(int n, double a_[], int r[], int c[], double eps)
+{ /* non-optimized version */
+ int i, j, k, p, q, ref;
+ double akk, big, temp;
+# define a(i,j) a_[(i)*n+(j)]
+ /* initially U = A, L = P = Q = I */
+ /* main elimination loop */
+ for (k = 0; k < n; k++)
+ { /* choose pivot u[p,q], k <= p, q <= n */
+ p = q = -1, big = eps;
+ for (i = k; i < n; i++)
+ { for (j = k; j < n; j++)
+ { /* temp = |u[i,j]| */
+ if ((temp = a(i,j)) < 0.0)
+ temp = -temp;
+ if (big < temp)
+ p = i, q = j, big = temp;
+ }
+ }
+ if (p < 0)
+ { /* k-th elimination step failed */
+ return k+1;
+ }
+ /* permute rows k and p */
+ if (k != p)
+ { for (j = 0; j < n; j++)
+ temp = a(k,j), a(k,j) = a(p,j), a(p,j) = temp;
+ ref = r[k], r[k] = r[p], r[p] = ref;
+ }
+ /* permute columns k and q */
+ if (k != q)
+ { for (i = 0; i < n; i++)
+ temp = a(i,k), a(i,k) = a(i,q), a(i,q) = temp;
+ ref = c[k], c[k] = c[q], c[q] = ref;
+ }
+ /* now pivot is in position u[k,k] */
+ akk = a(k,k);
+ /* eliminate subdiagonal elements u[k+1,k], ..., u[n,k] */
+ for (i = k+1; i < n; i++)
+ { if (a(i,k) != 0.0)
+ { /* gaussian multiplier l[i,k] := u[i,k] / u[k,k] */
+ temp = (a(i,k) /= akk);
+ /* (i-th row) := (i-th row) - l[i,k] * (k-th row) */
+ for (j = k+1; j < n; j++)
+ a(i,j) -= temp * a(k,j);
+ }
+ }
+ }
+# undef a
+ return 0;
+}
+
+/***********************************************************************
+* sgf_dense_phase - compute LU-factorization (dense phase)
+*
+* This routine performs dense phase of computing LU-factorization.
+*
+* The aim is two-fold. First, the main factorization routine switches
+* to dense phase when the active submatrix is relatively dense, so
+* using dense format allows significantly reduces overheads needed to
+* maintain sparse data structures. And second, that is more important,
+* on dense phase full pivoting is used (rather than partial pivoting)
+* that allows improving numerical stability, since round-off errors
+* tend to increase on last steps of the elimination process.
+*
+* On entry the routine assumes that elimination steps 1, 2, ..., k-1
+* have been performed, so partially transformed matrices L = P'* F * P
+* and U = P'* V * Q' have the following structure:
+*
+* 1 k n 1 k n
+* 1 1 . . . . . . . . . 1 x x x x x x x x x x
+* x 1 . . . . . . . . . x x x x x x x x x
+* x x 1 . . . . . . . . . x x x x x x x x
+* x x x 1 . . . . . . . . . x x x x x x x
+* k x x x x 1 . . . . . k . . . . * * * * * *
+* x x x x . 1 . . . . . . . . * * * * * *
+* x x x x . . 1 . . . . . . . * * * * * *
+* x x x x . . . 1 . . . . . . * * * * * *
+* x x x x . . . . 1 . . . . . * * * * * *
+* n x x x x . . . . . 1 n . . . . * * * * * *
+*
+* matrix L matrix U
+*
+* where rows and columns k, k+1, ..., n of matrix U constitute the
+* active submatrix A~, whose elements are marked by '*'.
+*
+* The routine copies the active submatrix A~ to a working array in
+* dense format, compute dense factorization A~ = P~* L~* U~* Q~ using
+* full pivoting, and then copies non-zero elements of factors L~ and
+* U~ back to factors L and U (more precisely, to factors F and V).
+*
+* If the factorization has been successfully computed, the routine
+* returns zero. Otherwise, if on k-th elimination step, 1 <= k <= n,
+* all elements of the active submatrix are close to zero, the routine
+* returns k (information on linearly dependent rows/columns in this
+* case is provided by matrices P and Q). */
+
+int sgf_dense_phase(LUF *luf, int k, int updat)
+{ int n = luf->n;
+ SVA *sva = luf->sva;
+ int *sv_ind = sva->ind;
+ double *sv_val = sva->val;
+ int fc_ref = luf->fc_ref;
+ int *fc_ptr = &sva->ptr[fc_ref-1];
+ int *fc_len = &sva->len[fc_ref-1];
+ int *fc_cap = &sva->cap[fc_ref-1];
+ int vr_ref = luf->vr_ref;
+ int *vr_ptr = &sva->ptr[vr_ref-1];
+ int *vr_len = &sva->len[vr_ref-1];
+ int *vr_cap = &sva->cap[vr_ref-1];
+ double *vr_piv = luf->vr_piv;
+ int vc_ref = luf->vc_ref;
+ int *vc_len = &sva->len[vc_ref-1];
+ int *pp_inv = luf->pp_inv;
+ int *pp_ind = luf->pp_ind;
+ int *qq_ind = luf->qq_ind;
+ int *qq_inv = luf->qq_inv;
+ int a_end, a_ptr, end, i, ia, ii, j, ja, jj, ka, len, na, ne,
+ need, ptr;
+ double *a_;
+ xassert(1 <= k && k <= n);
+ /* active columns of V are not longer needed; make them empty */
+ for (jj = k; jj <= n; jj++)
+ { /* jj is number of active column of U = P'* V * Q' */
+ vc_len[qq_ind[jj]] = 0;
+ }
+ /* determine order of active submatrix A~ of matrix U */
+ na = n - k + 1;
+ xassert(1 <= na && na <= n);
+ /* determine number of elements in dense triangular factor (L~ or
+ * U~), except diagonal elements */
+ ne = na * (na - 1) / 2;
+ /* we allocate active submatrix A~ in free (middle) part of SVA;
+ * to avoid defragmentation that could destroy A~ we also should
+ * reserve ne locations to build rows of V from rows of U~ and ne
+ * locations to build columns of F from columns of L~ */
+ need = na * na + ne + ne;
+ if (sva->r_ptr - sva->m_ptr < need)
+ { sva_more_space(sva, need);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ /* free (middle) part of SVA is structured as follows:
+ * end of left (dynamic) part
+ * ne free locations for new rows of V
+ * na free locations for active submatrix A~
+ * unused locations, if any
+ * ne free locations for new columns of F
+ * beginning of right (static) part */
+ a_ptr = sva->m_ptr + ne;
+ a_end = a_ptr + na * na;
+ /* copy active submatrix A~ from matrix V to working array in
+ * dense row-wise format */
+ a_ = &sva->val[a_ptr];
+# define a(ia, ja) a_[((ia) - 1) * na + ((ja) - 1)]
+ for (ia = 1; ia <= na; ia++)
+ { /* clear ia-th row of A~ */
+ for (ja = 1; ja <= na; ja++)
+ a(ia, ja) = 0.0;
+ /* ia-th row of A~ = (k-1+ia)-th row of U = i-th row of V */
+ i = pp_inv[k-1+ia];
+ ptr = vr_ptr[i];
+ end = ptr + vr_len[i];
+ for (; ptr < end; ptr++)
+ a(ia, qq_inv[sv_ind[ptr]]-k+1) = sv_val[ptr];
+ /* i-th row of V is no longer needed; make it empty */
+ vr_len[i] = 0;
+ }
+ /* compute dense factorization A~ = P~* L~* U~* Q~ */
+#if 1 /* FIXME: epsilon tolerance */
+ ka = sgf_dense_lu(na, &a(1, 1), &pp_inv[k], &qq_ind[k], 1e-20);
+#endif
+ /* rows of U with numbers pp_inv[k, k+1, ..., n] were permuted
+ * due to row permutations of A~; update matrix P using P~ */
+ for (ii = k; ii <= n; ii++)
+ pp_ind[pp_inv[ii]] = ii;
+ /* columns of U with numbers qq_ind[k, k+1, ..., n] were permuted
+ * due to column permutations of A~; update matrix Q using Q~ */
+ for (jj = k; jj <= n; jj++)
+ qq_inv[qq_ind[jj]] = jj;
+ /* check if dense factorization is complete */
+ if (ka != 0)
+ { /* A~ is singular to working precision */
+ /* information on linearly dependent rows/columns is provided
+ * by matrices P and Q */
+ xassert(1 <= ka && ka <= na);
+ return k - 1 + ka;
+ }
+ /* build new rows of V from rows of U~ */
+ for (ia = 1; ia <= na; ia++)
+ { /* ia-th row of U~ = (k-1+ia)-th row of U = i-th row of V */
+ i = pp_inv[k-1+ia];
+ xassert(vr_len[i] == 0);
+ /* store diagonal element u~[ia,ia] */
+ vr_piv[i] = a(ia, ia);
+ /* determine number of non-zero non-diagonal elements in ia-th
+ * row of U~ */
+ len = 0;
+ for (ja = ia+1; ja <= na; ja++)
+ { if (a(ia, ja) != 0.0)
+ len++;
+ }
+ /* reserve len locations for i-th row of matrix V in left
+ * (dynamic) part of SVA */
+ if (vr_cap[i] < len)
+ { /* there should be enough room in free part of SVA */
+ xassert(sva->r_ptr - sva->m_ptr >= len);
+ sva_enlarge_cap(sva, vr_ref-1+i, len, 0);
+ /* left part of SVA should not overlap matrix A~ */
+ xassert(sva->m_ptr <= a_ptr);
+ }
+ /* copy non-zero non-diaginal elements of ia-th row of U~ to
+ * i-th row of V */
+ ptr = vr_ptr[i];
+ for (ja = ia+1; ja <= na; ja++)
+ { if (a(ia, ja) != 0.0)
+ { sv_ind[ptr] = qq_ind[k-1+ja];
+ sv_val[ptr] = a(ia, ja);
+ ptr++;
+ }
+ }
+ xassert(ptr - vr_ptr[i] == len);
+ vr_len[i] = len;
+ }
+ /* build new columns of F from columns of L~ */
+ for (ja = 1; ja <= na; ja++)
+ { /* ja-th column of L~ = (k-1+ja)-th column of L = j-th column
+ * of F */
+ j = pp_inv[k-1+ja];
+ xassert(fc_len[j] == 0);
+ xassert(fc_cap[j] == 0);
+ /* determine number of non-zero non-diagonal elements in ja-th
+ * column of L~ */
+ len = 0;
+ for (ia = ja+1; ia <= na; ia++)
+ { if (a(ia, ja) != 0.0)
+ len++;
+ }
+ /* reserve len locations for j-th column of matrix F in right
+ * (static) part of SVA */
+ /* there should be enough room in free part of SVA */
+ xassert(sva->r_ptr - sva->m_ptr >= len);
+ if (len > 0)
+ sva_reserve_cap(sva, fc_ref-1+j, len);
+ /* right part of SVA should not overlap matrix A~ */
+ xassert(a_end <= sva->r_ptr);
+ /* copy non-zero non-diagonal elements of ja-th column of L~
+ * to j-th column of F */
+ ptr = fc_ptr[j];
+ for (ia = ja+1; ia <= na; ia++)
+ { if (a(ia, ja) != 0.0)
+ { sv_ind[ptr] = pp_inv[k-1+ia];
+ sv_val[ptr] = a(ia, ja);
+ ptr++;
+ }
+ }
+ xassert(ptr - fc_ptr[j] == len);
+ fc_len[j] = len;
+ }
+ /* factors L~ and U~ are no longer needed */
+# undef a
+ /* if it is not planned to update matrix V, relocate all its new
+ * rows to the right (static) part of SVA */
+ if (!updat)
+ { for (ia = 1; ia <= na; ia++)
+ { i = pp_inv[k-1+ia];
+ len = vr_len[i];
+ if (sva->r_ptr - sva->m_ptr < len)
+ { sva_more_space(sva, len);
+ sv_ind = sva->ind;
+ sv_val = sva->val;
+ }
+ sva_make_static(sva, vr_ref-1+i);
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* sgf_factorize - compute LU-factorization (main routine)
+*
+* This routine computes sparse LU-factorization of specified matrix A
+* using Gaussian elimination.
+*
+* On entry to the routine matrix V = A should be stored in column-wise
+* format.
+*
+* If the factorization has been successfully computed, the routine
+* returns zero. Otherwise, if on k-th elimination step, 1 <= k <= n,
+* all elements of the active submatrix are close to zero, the routine
+* returns k (information on linearly dependent rows/columns in this
+* case is provided by matrices P and Q). */
+
+#if 1 /* 21/II-2016 */
+/* If the matrix A is structurally singular, the routine returns -1.
+* NOTE: This case can be detected only if the singl flag is set. */
+#endif
+
+int sgf_factorize(SGF *sgf, int singl)
+{ LUF *luf = sgf->luf;
+ int n = luf->n;
+ SVA *sva = luf->sva;
+ int vr_ref = luf->vr_ref;
+ int *vr_len = &sva->len[vr_ref-1];
+ double *vr_piv = luf->vr_piv;
+ int vc_ref = luf->vc_ref;
+ int *vc_len = &sva->len[vc_ref-1];
+ int *pp_ind = luf->pp_ind;
+ int *pp_inv = luf->pp_inv;
+ int *qq_ind = luf->qq_ind;
+ int *qq_inv = luf->qq_inv;
+ int *rs_head = sgf->rs_head;
+ int *rs_prev = sgf->rs_prev;
+ int *rs_next = sgf->rs_next;
+ int *cs_head = sgf->cs_head;
+ int *cs_prev = sgf->cs_prev;
+ int *cs_next = sgf->cs_next;
+ double *vr_max = sgf->vr_max;
+ char *flag = sgf->flag;
+ double *work = sgf->work;
+ int i, j, k, k1, k2, p, q, nnz;
+ /* build matrix V = A in row-wise format */
+ luf_build_v_rows(luf, rs_prev);
+ /* P := Q := I, so V = U = A, F = L = I */
+ for (k = 1; k <= n; k++)
+ { vr_piv[k] = 0.0;
+ pp_ind[k] = pp_inv[k] = qq_ind[k] = qq_inv[k] = k;
+ }
+#ifdef GLP_DEBUG
+ sva_check_area(sva);
+ luf_check_all(luf, 1);
+#endif
+ /* perform singleton phase, if required */
+ if (!singl)
+ { /* assume that nucleus is entire matrix U */
+ k2 = 1;
+ }
+ else
+ { /* minimize nucleus size */
+#if 0 /* 21/II-2016 */
+ sgf_reduce_nuc(luf, &k1, &k2, rs_prev, rs_next);
+#else
+ if (sgf_reduce_nuc(luf, &k1, &k2, rs_prev, rs_next))
+ return -1;
+#endif
+#ifdef GLP_DEBUG
+ xprintf("n = %d; k1 = %d; k2 = %d\n", n, k1, k2);
+#endif
+ /* perform singleton phase */
+ k2 = sgf_singl_phase(luf, k1, k2, sgf->updat, rs_prev, work);
+ }
+#ifdef GLP_DEBUG
+ sva_check_area(sva);
+ luf_check_all(luf, k2);
+#endif
+ /* initialize working arrays */
+ rs_head[0] = cs_head[0] = 0;
+ for (k = 1; k <= n; k++)
+ { rs_head[k] = cs_head[k] = 0;
+ vr_max[k] = -1.0;
+ flag[k] = 0;
+ work[k] = 0.0;
+ }
+ /* build lists of active rows and columns of matrix V; determine
+ * number of non-zeros in initial active submatrix */
+ nnz = 0;
+ for (k = k2; k <= n; k++)
+ { i = pp_inv[k];
+ sgf_activate_row(i);
+ nnz += vr_len[i];
+ j = qq_ind[k];
+ sgf_activate_col(j);
+ }
+ /* main factorization loop */
+ for (k = k2; k <= n; k++)
+ { int na;
+ double den;
+ /* calculate density of active submatrix */
+ na = n - k + 1; /* order of active submatrix */
+#if 0 /* 21/VIII-2014 */
+ den = (double)nnz / (double)(na * na);
+#else
+ den = (double)nnz / ((double)(na) * (double)(na));
+#endif
+ /* if active submatrix is relatively dense, switch to dense
+ * phase */
+#if 1 /* FIXME */
+ if (na >= 5 && den >= 0.71)
+ {
+#ifdef GLP_DEBUG
+ xprintf("na = %d; nnz = %d; den = %g\n", na, nnz, den);
+#endif
+ break;
+ }
+#endif
+ /* choose pivot v[p,q] */
+ if (sgf_choose_pivot(sgf, &p, &q) != 0)
+ return k; /* failure */
+ /* u[i,j] = v[p,q], k <= i, j <= n */
+ i = pp_ind[p];
+ xassert(k <= i && i <= n);
+ j = qq_inv[q];
+ xassert(k <= j && j <= n);
+ /* move u[i,j] to position u[k,k] by implicit permutations of
+ * rows and columns of matrix U */
+ luf_swap_u_rows(k, i);
+ luf_swap_u_cols(k, j);
+ /* perform gaussian elimination */
+ nnz += sgf_eliminate(sgf, p, q);
+ }
+#if 1 /* FIXME */
+ if (k <= n)
+ { /* continue computing factorization in dense mode */
+#ifdef GLP_DEBUG
+ sva_check_area(sva);
+ luf_check_all(luf, k);
+#endif
+ k = sgf_dense_phase(luf, k, sgf->updat);
+ if (k != 0)
+ return k; /* failure */
+ }
+#endif
+#ifdef GLP_DEBUG
+ sva_check_area(sva);
+ luf_check_all(luf, n+1);
+#endif
+ /* defragment SVA; currently all columns of V are empty, so they
+ * will have zero capacity as required by luf_build_v_cols */
+ sva_defrag_area(sva);
+ /* build matrix F in row-wise format */
+ luf_build_f_rows(luf, rs_head);
+ /* build matrix V in column-wise format */
+ luf_build_v_cols(luf, sgf->updat, rs_head);
+ return 0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/sgf.h b/test/monniaux/glpk-4.65/src/bflib/sgf.h
new file mode 100644
index 00000000..4f744610
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/sgf.h
@@ -0,0 +1,203 @@
+/* sgf.h (sparse Gaussian factorizer) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#ifndef SGF_H
+#define SGF_H
+
+#include "luf.h"
+
+typedef struct SGF SGF;
+
+struct SGF
+{ /* sparse Gaussian factorizer workspace */
+ LUF *luf;
+ /* LU-factorization being computed */
+ /*--------------------------------------------------------------*/
+ /* to efficiently choose pivot elements according to Markowitz
+ * strategy, the search technique proposed by Iain Duff is used;
+ * it is based on using two families of sets {R[0], ..., R[n]}
+ * and {C[0], ..., C[n]}, where R[k] and C[k], 0 <= k <= n, are,
+ * respectively, sets of rows and columns of the active submatrix
+ * of matrix V having k non-zeros (i.e. whose length is k); each
+ * set R[k] and C[k] is implemented as a doubly linked list */
+ int *rs_head; /* int rs_head[1+n]; */
+ /* rs_head[k], 0 <= k <= n, is the number of first row, which
+ * has k non-zeros in the active submatrix */
+ int *rs_prev; /* int rs_prev[1+n]; */
+ /* rs_prev[0] is not used;
+ * rs_prev[i], 1 <= i <= n, is the number of previous row, which
+ * has the same number of non-zeros as i-th row;
+ * rs_prev[i] < 0 means that i-th row is inactive */
+ int *rs_next; /* int rs_next[1+n]; */
+ /* rs_next[0] is not used;
+ * rs_next[i], 1 <= i <= n, is the number of next row, which has
+ * the same number of non-zeros as i-th row;
+ * rs_next[i] < 0 means that i-th row is inactive */
+ int *cs_head; /* int cs_head[1+n]; */
+ /* cs_head[k], 0 <= k <= n, is the number of first column, which
+ * has k non-zeros in the active submatrix */
+ int *cs_prev; /* int cs_prev[1+n]; */
+ /* cs_prev[0] is not used;
+ * cs_prev[j], 1 <= j <= n, is the number of previous column,
+ * which has the same number of non-zeros as j-th column;
+ * cs_prev[j] < 0 means that j-th column is inactive */
+ int *cs_next; /* int cs_next[1+n]; */
+ /* cs_next[0] is not used;
+ * cs_next[j], 1 <= j <= n, is the number of next column, which
+ * has the same number of non-zeros as j-th column;
+ * cs_next[j] < 0 means that j-th column is inactive */
+ /* NOTE: cs_prev[j] = cs_next[j] = j means that j-th column was
+ * temporarily removed from corresponding set C[k] by the
+ * pivoting routine according to Uwe Suhl's heuristic */
+ /*--------------------------------------------------------------*/
+ /* working arrays */
+ double *vr_max; /* int vr_max[1+n]; */
+ /* vr_max[0] is not used;
+ * vr_max[i], 1 <= i <= n, is used only if i-th row of matrix V
+ * is active (i.e. belongs to the active submatrix), and is the
+ * largest magnitude of elements in that row; if vr_max[i] < 0,
+ * the largest magnitude is unknown yet */
+ char *flag; /* char flag[1+n]; */
+ /* boolean working array */
+ double *work; /* double work[1+n]; */
+ /* floating-point working array */
+ /*--------------------------------------------------------------*/
+ /* control parameters */
+ int updat;
+ /* if this flag is set, the matrix V is assumed to be updatable;
+ * in this case factorized (non-active) part of V is stored in
+ * the left part of SVA rather than in its right part */
+ double piv_tol;
+ /* threshold pivoting tolerance, 0 < piv_tol < 1; element v[i,j]
+ * of the active submatrix fits to be pivot if it satisfies to
+ * the stability criterion |v[i,j]| >= piv_tol * max |v[i,*]|,
+ * i.e. if it is not very small in the magnitude among other
+ * elements in the same row; decreasing this parameter gives
+ * better sparsity at the expense of numerical accuracy and vice
+ * versa */
+ int piv_lim;
+ /* maximal allowable number of pivot candidates to be considered;
+ * if piv_lim pivot candidates have been considered, the pivoting
+ * routine terminates the search with the best candidate found */
+ int suhl;
+ /* if this flag is set, the pivoting routine applies a heuristic
+ * proposed by Uwe Suhl: if a column of the active submatrix has
+ * no eligible pivot candidates (i.e. all its elements do not
+ * satisfy to the stability criterion), the routine excludes it
+ * from futher consideration until it becomes column singleton;
+ * in many cases this allows reducing the time needed to choose
+ * the pivot */
+ double eps_tol;
+ /* epsilon tolerance; each element of the active submatrix, whose
+ * magnitude is less than eps_tol, is replaced by exact zero */
+#if 0 /* FIXME */
+ double den_lim;
+ /* density limit; if the density of the active submatrix reaches
+ * this limit, the factorization routine switches from sparse to
+ * dense mode */
+#endif
+};
+
+#define sgf_activate_row(i) \
+ do \
+ { int len = vr_len[i]; \
+ rs_prev[i] = 0; \
+ rs_next[i] = rs_head[len]; \
+ if (rs_next[i] != 0) \
+ rs_prev[rs_next[i]] = i; \
+ rs_head[len] = i; \
+ } while (0)
+/* include i-th row of matrix V in active set R[len] */
+
+#define sgf_deactivate_row(i) \
+ do \
+ { if (rs_prev[i] == 0) \
+ rs_head[vr_len[i]] = rs_next[i]; \
+ else \
+ rs_next[rs_prev[i]] = rs_next[i]; \
+ if (rs_next[i] == 0) \
+ ; \
+ else \
+ rs_prev[rs_next[i]] = rs_prev[i]; \
+ rs_prev[i] = rs_next[i] = -1; \
+ } while (0)
+/* remove i-th row of matrix V from active set R[len] */
+
+#define sgf_activate_col(j) \
+ do \
+ { int len = vc_len[j]; \
+ cs_prev[j] = 0; \
+ cs_next[j] = cs_head[len]; \
+ if (cs_next[j] != 0) \
+ cs_prev[cs_next[j]] = j; \
+ cs_head[len] = j; \
+ } while (0)
+/* include j-th column of matrix V in active set C[len] */
+
+#define sgf_deactivate_col(j) \
+ do \
+ { if (cs_prev[j] == 0) \
+ cs_head[vc_len[j]] = cs_next[j]; \
+ else \
+ cs_next[cs_prev[j]] = cs_next[j]; \
+ if (cs_next[j] == 0) \
+ ; \
+ else \
+ cs_prev[cs_next[j]] = cs_prev[j]; \
+ cs_prev[j] = cs_next[j] = -1; \
+ } while (0)
+/* remove j-th column of matrix V from active set C[len] */
+
+#define sgf_reduce_nuc _glp_sgf_reduce_nuc
+int sgf_reduce_nuc(LUF *luf, int *k1, int *k2, int cnt[/*1+n*/],
+ int list[/*1+n*/]);
+/* initial reordering to minimize nucleus size */
+
+#define sgf_singl_phase _glp_sgf_singl_phase
+int sgf_singl_phase(LUF *luf, int k1, int k2, int updat,
+ int ind[/*1+n*/], double val[/*1+n*/]);
+/* compute LU-factorization (singleton phase) */
+
+#define sgf_choose_pivot _glp_sgf_choose_pivot
+int sgf_choose_pivot(SGF *sgf, int *p, int *q);
+/* choose pivot element v[p,q] */
+
+#define sgf_eliminate _glp_sgf_eliminate
+int sgf_eliminate(SGF *sgf, int p, int q);
+/* perform gaussian elimination */
+
+#define sgf_dense_lu _glp_sgf_dense_lu
+int sgf_dense_lu(int n, double a[], int r[], int c[], double eps);
+/* compute dense LU-factorization with full pivoting */
+
+#define sgf_dense_phase _glp_sgf_dense_phase
+int sgf_dense_phase(LUF *luf, int k, int updat);
+/* compute LU-factorization (dense phase) */
+
+#define sgf_factorize _glp_sgf_factorize
+int sgf_factorize(SGF *sgf, int singl);
+/* compute LU-factorization (main routine) */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/sva.c b/test/monniaux/glpk-4.65/src/bflib/sva.c
new file mode 100644
index 00000000..e6a675cc
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/sva.c
@@ -0,0 +1,572 @@
+/* sva.c (sparse vector area) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "sva.h"
+
+/***********************************************************************
+* sva_create_area - create sparse vector area (SVA)
+*
+* This routine creates the sparse vector area (SVA), which initially
+* is empty.
+*
+* The parameter n_max specifies the initial number of vectors that can
+* be allocated in the SVA, n_max > 0.
+*
+* The parameter size specifies the initial number of free locations in
+* the SVA, size > 0.
+*
+* On exit the routine returns a pointer to the SVA created. */
+
+SVA *sva_create_area(int n_max, int size)
+{ SVA *sva;
+ xassert(0 < n_max && n_max < INT_MAX);
+ xassert(0 < size && size < INT_MAX);
+ sva = talloc(1, SVA);
+ sva->n_max = n_max;
+ sva->n = 0;
+ sva->ptr = talloc(1+n_max, int);
+ sva->len = talloc(1+n_max, int);
+ sva->cap = talloc(1+n_max, int);
+ sva->size = size;
+ sva->m_ptr = 1;
+ sva->r_ptr = size+1;
+ sva->head = sva->tail = 0;
+ sva->prev = talloc(1+n_max, int);
+ sva->next = talloc(1+n_max, int);
+ sva->ind = talloc(1+size, int);
+ sva->val = talloc(1+size, double);
+ sva->talky = 0;
+ return sva;
+}
+
+/***********************************************************************
+* sva_alloc_vecs - allocate new vectors in SVA
+*
+* This routine allocates nnn new empty vectors, nnn > 0, in the sparse
+* vector area (SVA).
+*
+* The new vectors are assigned reference numbers k, k+1, ..., k+nnn-1,
+* where k is a reference number assigned to the very first new vector,
+* which is returned by the routine on exit. */
+
+int sva_alloc_vecs(SVA *sva, int nnn)
+{ int n = sva->n;
+ int n_max = sva->n_max;
+ int *ptr = sva->ptr;
+ int *len = sva->len;
+ int *cap = sva->cap;
+ int *prev = sva->prev;
+ int *next = sva->next;
+ int k, new_n;
+#if 1
+ if (sva->talky)
+ xprintf("sva_alloc_vecs: nnn = %d\n", nnn);
+#endif
+ xassert(nnn > 0);
+ /* determine new number of vectors in SVA */
+ new_n = n + nnn;
+ xassert(new_n > n);
+ if (n_max < new_n)
+ { /* enlarge the SVA arrays */
+ while (n_max < new_n)
+ { n_max += n_max;
+ xassert(n_max > 0);
+ }
+ sva->n_max = n_max;
+ sva->ptr = ptr = trealloc(ptr, 1+n_max, int);
+ sva->len = len = trealloc(len, 1+n_max, int);
+ sva->cap = cap = trealloc(cap, 1+n_max, int);
+ sva->prev = prev = trealloc(prev, 1+n_max, int);
+ sva->next = next = trealloc(next, 1+n_max, int);
+ }
+ /* initialize new vectors */
+ sva->n = new_n;
+ for (k = n+1; k <= new_n; k++)
+ { ptr[k] = len[k] = cap[k] = 0;
+ prev[k] = next[k] = -1;
+ }
+#if 1
+ if (sva->talky)
+ xprintf("now sva->n_max = %d, sva->n = %d\n",
+ sva->n_max, sva->n);
+#endif
+ /* return reference number of very first new vector */
+ return n+1;
+}
+
+/***********************************************************************
+* sva_resize_area - change size of SVA storage
+*
+* This routine increases or decrases the size of the SVA storage by
+* reallocating it.
+*
+* The parameter delta specifies the number of location by which the
+* current size of the SVA storage should be increased (if delta > 0)
+* or decreased (if delta < 0). Note that if delta is negative, it
+* should not be less than the current size of the middle part.
+*
+* As a result of this operation the size of the middle part of SVA is
+* increased/decreased by delta locations.
+*
+* NOTE: This operation changes ptr[k] for all vectors stored in the
+* right part of SVA. */
+
+void sva_resize_area(SVA *sva, int delta)
+{ int n = sva->n;
+ int *ptr = sva->ptr;
+ int size = sva->size;
+ int m_ptr = sva->m_ptr;
+ int r_ptr = sva->r_ptr;
+ int k, r_size;
+#if 1
+ if (sva->talky)
+ xprintf("sva_resize_area: delta = %d\n", delta);
+#endif
+ xassert(delta != 0);
+ /* determine size of the right part, in locations */
+ r_size = size - r_ptr + 1;
+ /* relocate the right part in case of negative delta */
+ if (delta < 0)
+ { xassert(delta >= m_ptr - r_ptr);
+ sva->r_ptr += delta;
+ memmove(&sva->ind[sva->r_ptr], &sva->ind[r_ptr],
+ r_size * sizeof(int));
+ memmove(&sva->val[sva->r_ptr], &sva->val[r_ptr],
+ r_size * sizeof(double));
+ }
+ /* reallocate the storage arrays */
+ xassert(delta < INT_MAX - sva->size);
+ sva->size += delta;
+ sva->ind = trealloc(sva->ind, 1+sva->size, int);
+ sva->val = trealloc(sva->val, 1+sva->size, double);
+ /* relocate the right part in case of positive delta */
+ if (delta > 0)
+ { sva->r_ptr += delta;
+ memmove(&sva->ind[sva->r_ptr], &sva->ind[r_ptr],
+ r_size * sizeof(int));
+ memmove(&sva->val[sva->r_ptr], &sva->val[r_ptr],
+ r_size * sizeof(double));
+ }
+ /* update pointers to vectors stored in the right part */
+ for (k = 1; k <= n; k++)
+ { if (ptr[k] >= r_ptr)
+ ptr[k] += delta;
+ }
+#if 1
+ if (sva->talky)
+ xprintf("now sva->size = %d\n", sva->size);
+#endif
+ return;
+}
+
+/***********************************************************************
+* sva_defrag_area - defragment left part of SVA
+*
+* This routine performs "garbage" collection to defragment the left
+* part of SVA.
+*
+* NOTE: This operation may change ptr[k] and cap[k] for all vectors
+* stored in the left part of SVA. */
+
+void sva_defrag_area(SVA *sva)
+{ int *ptr = sva->ptr;
+ int *len = sva->len;
+ int *cap = sva->cap;
+ int *prev = sva->prev;
+ int *next = sva->next;
+ int *ind = sva->ind;
+ double *val = sva->val;
+ int k, next_k, ptr_k, len_k, m_ptr, head, tail;
+#if 1
+ if (sva->talky)
+ { xprintf("sva_defrag_area:\n");
+ xprintf("before defragmenting = %d %d %d\n", sva->m_ptr - 1,
+ sva->r_ptr - sva->m_ptr, sva->size + 1 - sva->r_ptr);
+ }
+#endif
+ m_ptr = 1;
+ head = tail = 0;
+ /* walk through the linked list of vectors stored in the left
+ * part of SVA */
+ for (k = sva->head; k != 0; k = next_k)
+ { /* save number of next vector in the list */
+ next_k = next[k];
+ /* determine length of k-th vector */
+ len_k = len[k];
+ if (len_k == 0)
+ { /* k-th vector is empty; remove it from the left part */
+ ptr[k] = cap[k] = 0;
+ prev[k] = next[k] = -1;
+ }
+ else
+ { /* determine pointer to first location of k-th vector */
+ ptr_k = ptr[k];
+ xassert(m_ptr <= ptr_k);
+ /* relocate k-th vector to the beginning of the left part,
+ * if necessary */
+ if (m_ptr < ptr_k)
+ { memmove(&ind[m_ptr], &ind[ptr_k],
+ len_k * sizeof(int));
+ memmove(&val[m_ptr], &val[ptr_k],
+ len_k * sizeof(double));
+ ptr[k] = m_ptr;
+ }
+ /* remove unused locations from k-th vector */
+ cap[k] = len_k;
+ /* the left part of SVA has been enlarged */
+ m_ptr += len_k;
+ /* add k-th vector to the end of the new linked list */
+ prev[k] = tail;
+ next[k] = 0;
+ if (head == 0)
+ head = k;
+ else
+ next[tail] = k;
+ tail = k;
+ }
+ }
+ /* set new pointer to the middle part of SVA */
+ xassert(m_ptr <= sva->r_ptr);
+ sva->m_ptr = m_ptr;
+ /* set new head and tail of the linked list */
+ sva->head = head;
+ sva->tail = tail;
+#if 1
+ if (sva->talky)
+ xprintf("after defragmenting = %d %d %d\n", sva->m_ptr - 1,
+ sva->r_ptr - sva->m_ptr, sva->size + 1 - sva->r_ptr);
+#endif
+ return;
+}
+
+/***********************************************************************
+* sva_more_space - increase size of middle (free) part of SVA
+*
+* This routine increases the size of the middle (free) part of the
+* sparse vector area (SVA).
+*
+* The parameter m_size specifies the minimal size, in locations, of
+* the middle part to be provided. This new size should be greater than
+* the current size of the middle part.
+*
+* First, the routine defragments the left part of SVA. Then, if the
+* size of the left part has not sufficiently increased, the routine
+* increases the total size of the SVA storage by reallocating it. */
+
+void sva_more_space(SVA *sva, int m_size)
+{ int size, delta;
+#if 1
+ if (sva->talky)
+ xprintf("sva_more_space: m_size = %d\n", m_size);
+#endif
+ xassert(m_size > sva->r_ptr - sva->m_ptr);
+ /* defragment the left part */
+ sva_defrag_area(sva);
+ /* set, heuristically, the minimal size of the middle part to be
+ * not less than the size of the defragmented left part */
+ if (m_size < sva->m_ptr - 1)
+ m_size = sva->m_ptr - 1;
+ /* if there is still not enough room, increase the total size of
+ * the SVA storage */
+ if (sva->r_ptr - sva->m_ptr < m_size)
+ { size = sva->size; /* new sva size */
+ for (;;)
+ { delta = size - sva->size;
+ if (sva->r_ptr - sva->m_ptr + delta >= m_size)
+ break;
+ size += size;
+ xassert(size > 0);
+ }
+ sva_resize_area(sva, delta);
+ xassert(sva->r_ptr - sva->m_ptr >= m_size);
+ }
+ return;
+}
+
+/***********************************************************************
+* sva_enlarge_cap - enlarge capacity of specified vector
+*
+* This routine enlarges the current capacity of the specified vector
+* by relocating its content.
+*
+* The parameter k specifies the reference number of the vector whose
+* capacity should be enlarged, 1 <= k <= n. This vector should either
+* have zero capacity or be stored in the left (dynamic) part of SVA.
+*
+* The parameter new_cap specifies the new capacity of the vector,
+* in locations. This new capacity should be greater than the current
+* capacity of the vector.
+*
+* The parameter skip is a flag. If this flag is set, the routine does
+* *not* copy numerical values of elements of the vector on relocating
+* its content, i.e. only element indices are copied.
+*
+* NOTE: On entry to the routine the middle part of SVA should have at
+* least new_cap free locations. */
+
+void sva_enlarge_cap(SVA *sva, int k, int new_cap, int skip)
+{ int *ptr = sva->ptr;
+ int *len = sva->len;
+ int *cap = sva->cap;
+ int *prev = sva->prev;
+ int *next = sva->next;
+ int *ind = sva->ind;
+ double *val = sva->val;
+ xassert(1 <= k && k <= sva->n);
+ xassert(new_cap > cap[k]);
+ /* there should be at least new_cap free locations */
+ xassert(sva->r_ptr - sva->m_ptr >= new_cap);
+ /* relocate the vector */
+ if (cap[k] == 0)
+ { /* the vector is empty */
+ xassert(ptr[k] == 0);
+ xassert(len[k] == 0);
+ }
+ else
+ { /* the vector has non-zero capacity */
+ xassert(ptr[k] + len[k] <= sva->m_ptr);
+ /* copy the current vector content to the beginning of the
+ * middle part */
+ if (len[k] > 0)
+ { memcpy(&ind[sva->m_ptr], &ind[ptr[k]],
+ len[k] * sizeof(int));
+ if (!skip)
+ memcpy(&val[sva->m_ptr], &val[ptr[k]],
+ len[k] * sizeof(double));
+ }
+ /* remove the vector from the linked list */
+ if (prev[k] == 0)
+ sva->head = next[k];
+ else
+ { /* preceding vector exists; increase its capacity */
+ cap[prev[k]] += cap[k];
+ next[prev[k]] = next[k];
+ }
+ if (next[k] == 0)
+ sva->tail = prev[k];
+ else
+ prev[next[k]] = prev[k];
+ }
+ /* set new pointer and capacity of the vector */
+ ptr[k] = sva->m_ptr;
+ cap[k] = new_cap;
+ /* add the vector to the end of the linked list */
+ prev[k] = sva->tail;
+ next[k] = 0;
+ if (sva->head == 0)
+ sva->head = k;
+ else
+ next[sva->tail] = k;
+ sva->tail = k;
+ /* new_cap free locations have been consumed */
+ sva->m_ptr += new_cap;
+ xassert(sva->m_ptr <= sva->r_ptr);
+ return;
+}
+
+/***********************************************************************
+* sva_reserve_cap - reserve locations for specified vector
+*
+* This routine reserves locations for the specified vector in the
+* right (static) part of SVA.
+*
+* The parameter k specifies the reference number of the vector (this
+* vector should have zero capacity), 1 <= k <= n.
+*
+* The parameter new_cap specifies a non-zero capacity of the vector,
+* in locations.
+*
+* NOTE: On entry to the routine the middle part of SVA should have at
+* least new_cap free locations. */
+
+void sva_reserve_cap(SVA *sva, int k, int new_cap)
+{ int *ptr = sva->ptr;
+ int *len = sva->len;
+ int *cap = sva->cap;
+ xassert(1 <= k && k <= sva->n);
+ xassert(new_cap > 0);
+ xassert(ptr[k] == 0 && len[k] == 0 && cap[k] == 0);
+ /* there should be at least new_cap free locations */
+ xassert(sva->r_ptr - sva->m_ptr >= new_cap);
+ /* set the pointer and capacity of the vector */
+ ptr[k] = sva->r_ptr - new_cap;
+ cap[k] = new_cap;
+ /* new_cap free locations have been consumed */
+ sva->r_ptr -= new_cap;
+ return;
+}
+
+/***********************************************************************
+* sva_make_static - relocate specified vector to right part of SVA
+*
+* Assuming that the specified vector is stored in the left (dynamic)
+* part of SVA, this routine makes the vector static by relocating its
+* content to the right (static) part of SVA. However, if the specified
+* vector has zero capacity, the routine does nothing.
+*
+* The parameter k specifies the reference number of the vector to be
+* relocated, 1 <= k <= n.
+*
+* NOTE: On entry to the routine the middle part of SVA should have at
+* least len[k] free locations, where len[k] is the length of the
+* vector to be relocated. */
+
+void sva_make_static(SVA *sva, int k)
+{ int *ptr = sva->ptr;
+ int *len = sva->len;
+ int *cap = sva->cap;
+ int *prev = sva->prev;
+ int *next = sva->next;
+ int *ind = sva->ind;
+ double *val = sva->val;
+ int ptr_k, len_k;
+ xassert(1 <= k && k <= sva->n);
+ /* if the vector has zero capacity, do nothing */
+ if (cap[k] == 0)
+ { xassert(ptr[k] == 0);
+ xassert(len[k] == 0);
+ goto done;
+ }
+ /* there should be at least len[k] free locations */
+ len_k = len[k];
+ xassert(sva->r_ptr - sva->m_ptr >= len_k);
+ /* remove the vector from the linked list */
+ if (prev[k] == 0)
+ sva->head = next[k];
+ else
+ { /* preceding vector exists; increase its capacity */
+ cap[prev[k]] += cap[k];
+ next[prev[k]] = next[k];
+ }
+ if (next[k] == 0)
+ sva->tail = prev[k];
+ else
+ prev[next[k]] = prev[k];
+ /* if the vector has zero length, make it empty */
+ if (len_k == 0)
+ { ptr[k] = cap[k] = 0;
+ goto done;
+ }
+ /* copy the vector content to the beginning of the right part */
+ ptr_k = sva->r_ptr - len_k;
+ memcpy(&ind[ptr_k], &ind[ptr[k]], len_k * sizeof(int));
+ memcpy(&val[ptr_k], &val[ptr[k]], len_k * sizeof(double));
+ /* set new pointer and capacity of the vector */
+ ptr[k] = ptr_k;
+ cap[k] = len_k;
+ /* len[k] free locations have been consumed */
+ sva->r_ptr -= len_k;
+done: return;
+}
+
+/***********************************************************************
+* sva_check_area - check sparse vector area (SVA)
+*
+* This routine checks the SVA data structures for correctness.
+*
+* NOTE: For testing/debugging only. */
+
+void sva_check_area(SVA *sva)
+{ int n_max = sva->n_max;
+ int n = sva->n;
+ int *ptr = sva->ptr;
+ int *len = sva->len;
+ int *cap = sva->cap;
+ int size = sva->size;
+ int m_ptr = sva->m_ptr;
+ int r_ptr = sva->r_ptr;
+ int head = sva->head;
+ int tail = sva->tail;
+ int *prev = sva->prev;
+ int *next = sva->next;
+ int k;
+#if 0 /* 16/II-2004; SVA may be empty */
+ xassert(1 <= n && n <= n_max);
+#else
+ xassert(0 <= n && n <= n_max);
+#endif
+ xassert(1 <= m_ptr && m_ptr <= r_ptr && r_ptr <= size+1);
+ /* all vectors included the linked list should have non-zero
+ * capacity and be stored in the left part */
+ for (k = head; k != 0; k = next[k])
+ { xassert(1 <= k && k <= n);
+ xassert(cap[k] > 0);
+ xassert(0 <= len[k] && len[k] <= cap[k]);
+ if (prev[k] == 0)
+ xassert(k == head);
+ else
+ { xassert(1 <= prev[k] && prev[k] <= n);
+ xassert(next[prev[k]] == k);
+ }
+ if (next[k] == 0)
+ { xassert(k == tail);
+ xassert(ptr[k] + cap[k] <= m_ptr);
+ }
+ else
+ { xassert(1 <= next[k] && next[k] <= n);
+ xassert(prev[next[k]] == k);
+ xassert(ptr[k] + cap[k] <= ptr[next[k]]);
+ }
+ cap[k] = -cap[k];
+ }
+ /* all other vectors should either have zero capacity or be
+ * stored in the right part */
+ for (k = 1; k <= n; k++)
+ { if (cap[k] < 0)
+ { /* k-th vector is stored in the left part */
+ cap[k] = -cap[k];
+ }
+ else if (cap[k] == 0)
+ { /* k-th vector has zero capacity */
+ xassert(ptr[k] == 0);
+ xassert(len[k] == 0);
+ }
+ else /* cap[k] > 0 */
+ { /* k-th vector is stored in the right part */
+ xassert(0 <= len[k] && len[k] <= cap[k]);
+ xassert(r_ptr <= ptr[k] && ptr[k] + cap[k] <= size+1);
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* sva_delete_area - delete sparse vector area (SVA)
+*
+* This routine deletes the sparse vector area (SVA) freeing all the
+* memory allocated to it. */
+
+void sva_delete_area(SVA *sva)
+{ tfree(sva->ptr);
+ tfree(sva->len);
+ tfree(sva->cap);
+ tfree(sva->prev);
+ tfree(sva->next);
+ tfree(sva->ind);
+ tfree(sva->val);
+ tfree(sva);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/bflib/sva.h b/test/monniaux/glpk-4.65/src/bflib/sva.h
new file mode 100644
index 00000000..0eab317b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/bflib/sva.h
@@ -0,0 +1,161 @@
+/* sva.h (sparse vector area) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#ifndef SVA_H
+#define SVA_H
+
+/***********************************************************************
+* Sparse Vector Area (SVA) is a container for sparse vectors. This
+* program object is used mainly on computing factorization, where the
+* sparse vectors are rows and columns of sparse matrices.
+*
+* The SVA storage is a set of locations numbered 1, 2, ..., size,
+* where size is the size of SVA, which is the total number of
+* locations currently allocated. Each location is identified by its
+* pointer p, 1 <= p <= size, and is the pair (ind[p], val[p]), where
+* ind[p] and val[p] are, respectively, the index and value fields used
+* to store the index and numeric value of a particular vector element.
+*
+* Each sparse vector is identified by its reference number k,
+* 1 <= k <= n, where n is the total number of vectors currently stored
+* in SVA, and defined by the triplet (ptr[k], len[k], cap[k]), where:
+* ptr[k] is a pointer to the first location of the vector; len[k] is
+* the vector length, which is the number of its non-zero elements,
+* len[k] >= 0; and cap[k] is the capacity of the vector, which is the
+* total number of adjacent locations allocated to that vector,
+* cap[k] >= len[k]. Thus, non-zero elements of k-th vector are stored
+* in locations ptr[k], ptr[k]+1, ..., ptr[k]+len[k]-1, and locations
+* ptr[k]+len[k], ptr[k]+len[k]+1, ..., ptr[k]+cap[k]-1 are reserved.
+*
+* The SVA storage is divided into three parts as follows:
+*
+* Locations 1, 2, ..., m_ptr-1 constitute the left (dynamic) part of
+* SVA. This part is used to store vectors, whose capacity may change.
+* Note that all vectors stored in the left part are also included in
+* a doubly linked list, where they are ordered by increasing their
+* pointers ptr[k] (this list is needed for efficient implementation
+* of the garbage collector used to defragment the left part of SVA);
+*
+* Locations m_ptr, m_ptr+1, ..., r_ptr-1 are free and constitute the
+* middle (free) part of SVA.
+*
+* Locations r_ptr, r_ptr+1, ..., size constitute the right (static)
+* part of SVA. This part is used to store vectors, whose capacity is
+* not changed. */
+
+typedef struct SVA SVA;
+
+struct SVA
+{ /* sparse vector area */
+ int n_max;
+ /* maximal value of n (enlarged automatically) */
+ int n;
+ /* number of currently allocated vectors, 0 <= n <= n_max */
+ int *ptr; /* int ptr[1+n_max]; */
+ /* ptr[0] is not used;
+ * ptr[k], 1 <= i <= n, is pointer to first location of k-th
+ * vector in the arrays ind and val */
+ int *len; /* int len[1+n_max]; */
+ /* len[0] is not used;
+ * len[k], 1 <= k <= n, is length of k-th vector, len[k] >= 0 */
+ int *cap; /* int cap[1+n_max]; */
+ /* cap[0] is not used;
+ * cap[k], 1 <= k <= n, is capacity of k-th vector (the number
+ * of adjacent locations allocated to it), cap[k] >= len[k] */
+ /* NOTE: if cap[k] = 0, then ptr[k] = 0 and len[k] = 0 */
+ int size;
+ /* total number of locations in SVA */
+ int m_ptr, r_ptr;
+ /* partitioning pointers that define the left, middle, and right
+ * parts of SVA (see above); 1 <= m_ptr <= r_ptr <= size+1 */
+ int head;
+ /* number of first (leftmost) vector in the linked list */
+ int tail;
+ /* number of last (rightmost) vector in the linked list */
+ int *prev; /* int prev[1+n_max]; */
+ /* prev[0] is not used;
+ * prev[k] is number of vector which precedes k-th vector in the
+ * linked list;
+ * prev[k] < 0 means that k-th vector is not in the list */
+ int *next; /* int next[1+n_max]; */
+ /* next[0] is not used;
+ * next[k] is number of vector which succedes k-th vector in the
+ * linked list;
+ * next[k] < 0 means that k-th vector is not in the list */
+ /* NOTE: only vectors having non-zero capacity and stored in the
+ * left part of SVA are included in this linked list */
+ int *ind; /* int ind[1+size]; */
+ /* ind[0] is not used;
+ * ind[p], 1 <= p <= size, is index field of location p */
+ double *val; /* double val[1+size]; */
+ /* val[0] is not used;
+ * val[p], 1 <= p <= size, is value field of location p */
+#if 1
+ int talky;
+ /* option to enable talky mode */
+#endif
+};
+
+#define sva_create_area _glp_sva_create_area
+SVA *sva_create_area(int n_max, int size);
+/* create sparse vector area (SVA) */
+
+#define sva_alloc_vecs _glp_sva_alloc_vecs
+int sva_alloc_vecs(SVA *sva, int nnn);
+/* allocate new vectors in SVA */
+
+#define sva_resize_area _glp_sva_resize_area
+void sva_resize_area(SVA *sva, int delta);
+/* change size of SVA storage */
+
+#define sva_defrag_area _glp_sva_defrag_area
+void sva_defrag_area(SVA *sva);
+/* defragment left part of SVA */
+
+#define sva_more_space _glp_sva_more_space
+void sva_more_space(SVA *sva, int m_size);
+/* increase size of middle (free) part of SVA */
+
+#define sva_enlarge_cap _glp_sva_enlarge_cap
+void sva_enlarge_cap(SVA *sva, int k, int new_cap, int skip);
+/* enlarge capacity of specified vector */
+
+#define sva_reserve_cap _glp_sva_reserve_cap
+void sva_reserve_cap(SVA *sva, int k, int new_cap);
+/* reserve locations for specified vector */
+
+#define sva_make_static _glp_sva_make_static
+void sva_make_static(SVA *sva, int k);
+/* relocate specified vector to right part of SVA */
+
+#define sva_check_area _glp_sva_check_area
+void sva_check_area(SVA *sva);
+/* check sparse vector area (SVA) */
+
+#define sva_delete_area _glp_sva_delete_area
+void sva_delete_area(SVA *sva);
+/* delete sparse vector area (SVA) */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/colamd/COPYING b/test/monniaux/glpk-4.65/src/colamd/COPYING
new file mode 100644
index 00000000..84bba36d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/colamd/COPYING
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/test/monniaux/glpk-4.65/src/colamd/README b/test/monniaux/glpk-4.65/src/colamd/README
new file mode 100644
index 00000000..a365059f
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/colamd/README
@@ -0,0 +1,98 @@
+NOTE: Files in this subdirectory are NOT part of the GLPK package, but
+ are used with GLPK.
+
+ The original code was modified according to GLPK requirements by
+ Andrew Makhorin <mao@gnu.org>.
+************************************************************************
+COLAMD/SYMAMD Version 2.7, Copyright (C) 1998-2007, Timothy A. Davis,
+All Rights Reserved.
+
+Description:
+
+ colamd: an approximate minimum degree column ordering algorithm,
+ for LU factorization of symmetric or unsymmetric matrices,
+ QR factorization, least squares, interior point methods for
+ linear programming problems, and other related problems.
+
+ symamd: an approximate minimum degree ordering algorithm for
+ Cholesky factorization of symmetric matrices.
+
+Purpose:
+
+ Colamd computes a permutation Q such that the Cholesky factorization
+ of (AQ)'(AQ) has less fill-in and requires fewer floating point
+ operations than A'A. This also provides a good ordering for sparse
+ partial pivoting methods, P(AQ) = LU, where Q is computed prior to
+ numerical factorization, and P is computed during numerical
+ factorization via conventional partial pivoting with row
+ interchanges. Colamd is the column ordering method used in SuperLU,
+ part of the ScaLAPACK library. It is also available as built-in
+ function in MATLAB Version 6, available from MathWorks, Inc.
+ (http://www.mathworks.com). This routine can be used in place of
+ colmmd in MATLAB.
+
+ Symamd computes a permutation P of a symmetric matrix A such that
+ the Cholesky factorization of PAP' has less fill-in and requires
+ fewer floating point operations than A. Symamd constructs a matrix
+ M such that M'M has the same nonzero pattern of A, and then orders
+ the columns of M using colmmd. The column ordering of M is then
+ returned as the row and column ordering P of A.
+
+Authors:
+
+ The authors of the code itself are Stefan I. Larimore and Timothy A.
+ Davis (davis at cise.ufl.edu), University of Florida. The algorithm
+ was developed in collaboration with John Gilbert, Xerox PARC, and
+ Esmond Ng, Oak Ridge National Laboratory.
+
+Acknowledgements:
+
+ This work was supported by the National Science Foundation, under
+ grants DMS-9504974 and DMS-9803599.
+
+License:
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License
+ as published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ USA.
+
+ Permission is hereby granted to use or copy this program under the
+ terms of the GNU LGPL, provided that the Copyright, this License,
+ and the Availability of the original version is retained on all
+ copies. User documentation of any code that uses this code or any
+ modified version of this code must cite the Copyright, this License,
+ the Availability note, and "Used by permission." Permission to
+ modify the code and to distribute modified code is granted, provided
+ the Copyright, this License, and the Availability note are retained,
+ and a notice that the code was modified is included.
+
+ COLAMD is also available under alternate licenses, contact T. Davis
+ for details.
+
+Availability:
+
+ The colamd/symamd library is available at:
+
+ http://www.cise.ufl.edu/research/sparse/colamd/
+
+References:
+
+ T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate
+ column minimum degree ordering algorithm, ACM Transactions on
+ Mathematical Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+ T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836:
+ COLAMD, an approximate column minimum degree ordering algorithm, ACM
+ Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+ 2004.
diff --git a/test/monniaux/glpk-4.65/src/colamd/colamd.c b/test/monniaux/glpk-4.65/src/colamd/colamd.c
new file mode 100644
index 00000000..86ddd6b7
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/colamd/colamd.c
@@ -0,0 +1,3622 @@
+/* ========================================================================== */
+/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */
+/* ========================================================================== */
+
+/* COLAMD / SYMAMD
+
+ colamd: an approximate minimum degree column ordering algorithm,
+ for LU factorization of symmetric or unsymmetric matrices,
+ QR factorization, least squares, interior point methods for
+ linear programming problems, and other related problems.
+
+ symamd: an approximate minimum degree ordering algorithm for Cholesky
+ factorization of symmetric matrices.
+
+ Purpose:
+
+ Colamd computes a permutation Q such that the Cholesky factorization of
+ (AQ)'(AQ) has less fill-in and requires fewer floating point operations
+ than A'A. This also provides a good ordering for sparse partial
+ pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
+ factorization, and P is computed during numerical factorization via
+ conventional partial pivoting with row interchanges. Colamd is the
+ column ordering method used in SuperLU, part of the ScaLAPACK library.
+ It is also available as built-in function in MATLAB Version 6,
+ available from MathWorks, Inc. (http://www.mathworks.com). This
+ routine can be used in place of colmmd in MATLAB.
+
+ Symamd computes a permutation P of a symmetric matrix A such that the
+ Cholesky factorization of PAP' has less fill-in and requires fewer
+ floating point operations than A. Symamd constructs a matrix M such
+ that M'M has the same nonzero pattern of A, and then orders the columns
+ of M using colmmd. The column ordering of M is then returned as the
+ row and column ordering P of A.
+
+ Authors:
+
+ The authors of the code itself are Stefan I. Larimore and Timothy A.
+ Davis (davis at cise.ufl.edu), University of Florida. The algorithm was
+ developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+ Ng, Oak Ridge National Laboratory.
+
+ Acknowledgements:
+
+ This work was supported by the National Science Foundation, under
+ grants DMS-9504974 and DMS-9803599.
+
+ Copyright and License:
+
+ Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
+ COLAMD is also available under alternate licenses, contact T. Davis
+ for details.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ USA
+
+ Permission is hereby granted to use or copy this program under the
+ terms of the GNU LGPL, provided that the Copyright, this License,
+ and the Availability of the original version is retained on all copies.
+ User documentation of any code that uses this code or any modified
+ version of this code must cite the Copyright, this License, the
+ Availability note, and "Used by permission." Permission to modify
+ the code and to distribute modified code is granted, provided the
+ Copyright, this License, and the Availability note are retained,
+ and a notice that the code was modified is included.
+
+ Availability:
+
+ The colamd/symamd library is available at
+
+ http://www.cise.ufl.edu/research/sparse/colamd/
+
+ This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c
+ file. It requires the colamd.h file. It is required by the colamdmex.c
+ and symamdmex.c files, for the MATLAB interface to colamd and symamd.
+ Appears as ACM Algorithm 836.
+
+ See the ChangeLog file for changes since Version 1.0.
+
+ References:
+
+ T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
+ minimum degree ordering algorithm, ACM Transactions on Mathematical
+ Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+ T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
+ an approximate column minimum degree ordering algorithm, ACM
+ Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+ 2004.
+
+*/
+
+/* ========================================================================== */
+/* === Description of user-callable routines ================================ */
+/* ========================================================================== */
+
+/* COLAMD includes both int and UF_long versions of all its routines. The
+ * description below is for the int version. For UF_long, all int arguments
+ * become UF_long. UF_long is normally defined as long, except for WIN64.
+
+ ----------------------------------------------------------------------------
+ colamd_recommended:
+ ----------------------------------------------------------------------------
+
+ C syntax:
+
+ #include "colamd.h"
+ size_t colamd_recommended (int nnz, int n_row, int n_col) ;
+ size_t colamd_l_recommended (UF_long nnz, UF_long n_row,
+ UF_long n_col) ;
+
+ Purpose:
+
+ Returns recommended value of Alen for use by colamd. Returns 0
+ if any input argument is negative. The use of this routine
+ is optional. Not needed for symamd, which dynamically allocates
+ its own memory.
+
+ Note that in v2.4 and earlier, these routines returned int or long.
+ They now return a value of type size_t.
+
+ Arguments (all input arguments):
+
+ int nnz ; Number of nonzeros in the matrix A. This must
+ be the same value as p [n_col] in the call to
+ colamd - otherwise you will get a wrong value
+ of the recommended memory to use.
+
+ int n_row ; Number of rows in the matrix A.
+
+ int n_col ; Number of columns in the matrix A.
+
+ ----------------------------------------------------------------------------
+ colamd_set_defaults:
+ ----------------------------------------------------------------------------
+
+ C syntax:
+
+ #include "colamd.h"
+ colamd_set_defaults (double knobs [COLAMD_KNOBS]) ;
+ colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ;
+
+ Purpose:
+
+ Sets the default parameters. The use of this routine is optional.
+
+ Arguments:
+
+ double knobs [COLAMD_KNOBS] ; Output only.
+
+ NOTE: the meaning of the dense row/col knobs has changed in v2.4
+
+ knobs [0] and knobs [1] control dense row and col detection:
+
+ Colamd: rows with more than
+ max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col))
+ entries are removed prior to ordering. Columns with more than
+ max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col)))
+ entries are removed prior to
+ ordering, and placed last in the output column ordering.
+
+ Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0].
+ Rows and columns with more than
+ max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n))
+ entries are removed prior to ordering, and placed last in the
+ output ordering.
+
+ COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
+ respectively, in colamd.h. Default values of these two knobs
+ are both 10. Currently, only knobs [0] and knobs [1] are
+ used, but future versions may use more knobs. If so, they will
+ be properly set to their defaults by the future version of
+ colamd_set_defaults, so that the code that calls colamd will
+ not need to change, assuming that you either use
+ colamd_set_defaults, or pass a (double *) NULL pointer as the
+ knobs array to colamd or symamd.
+
+ knobs [2]: aggressive absorption
+
+ knobs [COLAMD_AGGRESSIVE] controls whether or not to do
+ aggressive absorption during the ordering. Default is TRUE.
+
+
+ ----------------------------------------------------------------------------
+ colamd:
+ ----------------------------------------------------------------------------
+
+ C syntax:
+
+ #include "colamd.h"
+ int colamd (int n_row, int n_col, int Alen, int *A, int *p,
+ double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ;
+ UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen,
+ UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS],
+ UF_long stats [COLAMD_STATS]) ;
+
+ Purpose:
+
+ Computes a column ordering (Q) of A such that P(AQ)=LU or
+ (AQ)'AQ=LL' have less fill-in and require fewer floating point
+ operations than factorizing the unpermuted matrix A or A'A,
+ respectively.
+
+ Returns:
+
+ TRUE (1) if successful, FALSE (0) otherwise.
+
+ Arguments:
+
+ int n_row ; Input argument.
+
+ Number of rows in the matrix A.
+ Restriction: n_row >= 0.
+ Colamd returns FALSE if n_row is negative.
+
+ int n_col ; Input argument.
+
+ Number of columns in the matrix A.
+ Restriction: n_col >= 0.
+ Colamd returns FALSE if n_col is negative.
+
+ int Alen ; Input argument.
+
+ Restriction (see note):
+ Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col
+ Colamd returns FALSE if these conditions are not met.
+
+ Note: this restriction makes an modest assumption regarding
+ the size of the two typedef's structures in colamd.h.
+ We do, however, guarantee that
+
+ Alen >= colamd_recommended (nnz, n_row, n_col)
+
+ will be sufficient. Note: the macro version does not check
+ for integer overflow, and thus is not recommended. Use
+ the colamd_recommended routine instead.
+
+ int A [Alen] ; Input argument, undefined on output.
+
+ A is an integer array of size Alen. Alen must be at least as
+ large as the bare minimum value given above, but this is very
+ low, and can result in excessive run time. For best
+ performance, we recommend that Alen be greater than or equal to
+ colamd_recommended (nnz, n_row, n_col), which adds
+ nnz/5 to the bare minimum value given above.
+
+ On input, the row indices of the entries in column c of the
+ matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices
+ in a given column c need not be in ascending order, and
+ duplicate row indices may be be present. However, colamd will
+ work a little faster if both of these conditions are met
+ (Colamd puts the matrix into this format, if it finds that the
+ the conditions are not met).
+
+ The matrix is 0-based. That is, rows are in the range 0 to
+ n_row-1, and columns are in the range 0 to n_col-1. Colamd
+ returns FALSE if any row index is out of range.
+
+ The contents of A are modified during ordering, and are
+ undefined on output.
+
+ int p [n_col+1] ; Both input and output argument.
+
+ p is an integer array of size n_col+1. On input, it holds the
+ "pointers" for the column form of the matrix A. Column c of
+ the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
+ entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+ for all c in the range 0 to n_col-1. The value p [n_col] is
+ thus the total number of entries in the pattern of the matrix A.
+ Colamd returns FALSE if these conditions are not met.
+
+ On output, if colamd returns TRUE, the array p holds the column
+ permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
+ the first column index in the new ordering, and p [n_col-1] is
+ the last. That is, p [k] = j means that column j of A is the
+ kth pivot column, in AQ, where k is in the range 0 to n_col-1
+ (p [0] = j means that column j of A is the first column in AQ).
+
+ If colamd returns FALSE, then no permutation is returned, and
+ p is undefined on output.
+
+ double knobs [COLAMD_KNOBS] ; Input argument.
+
+ See colamd_set_defaults for a description.
+
+ int stats [COLAMD_STATS] ; Output argument.
+
+ Statistics on the ordering, and error status.
+ See colamd.h for related definitions.
+ Colamd returns FALSE if stats is not present.
+
+ stats [0]: number of dense or empty rows ignored.
+
+ stats [1]: number of dense or empty columns ignored (and
+ ordered last in the output permutation p)
+ Note that a row can become "empty" if it
+ contains only "dense" and/or "empty" columns,
+ and similarly a column can become "empty" if it
+ only contains "dense" and/or "empty" rows.
+
+ stats [2]: number of garbage collections performed.
+ This can be excessively high if Alen is close
+ to the minimum required value.
+
+ stats [3]: status code. < 0 is an error code.
+ > 1 is a warning or notice.
+
+ 0 OK. Each column of the input matrix contained
+ row indices in increasing order, with no
+ duplicates.
+
+ 1 OK, but columns of input matrix were jumbled
+ (unsorted columns or duplicate entries). Colamd
+ had to do some extra work to sort the matrix
+ first and remove duplicate entries, but it
+ still was able to return a valid permutation
+ (return value of colamd was TRUE).
+
+ stats [4]: highest numbered column that
+ is unsorted or has duplicate
+ entries.
+ stats [5]: last seen duplicate or
+ unsorted row index.
+ stats [6]: number of duplicate or
+ unsorted row indices.
+
+ -1 A is a null pointer
+
+ -2 p is a null pointer
+
+ -3 n_row is negative
+
+ stats [4]: n_row
+
+ -4 n_col is negative
+
+ stats [4]: n_col
+
+ -5 number of nonzeros in matrix is negative
+
+ stats [4]: number of nonzeros, p [n_col]
+
+ -6 p [0] is nonzero
+
+ stats [4]: p [0]
+
+ -7 A is too small
+
+ stats [4]: required size
+ stats [5]: actual size (Alen)
+
+ -8 a column has a negative number of entries
+
+ stats [4]: column with < 0 entries
+ stats [5]: number of entries in col
+
+ -9 a row index is out of bounds
+
+ stats [4]: column with bad row index
+ stats [5]: bad row index
+ stats [6]: n_row, # of rows of matrx
+
+ -10 (unused; see symamd.c)
+
+ -999 (unused; see symamd.c)
+
+ Future versions may return more statistics in the stats array.
+
+ Example:
+
+ See http://www.cise.ufl.edu/research/sparse/colamd/example.c
+ for a complete example.
+
+ To order the columns of a 5-by-4 matrix with 11 nonzero entries in
+ the following nonzero pattern
+
+ x 0 x 0
+ x 0 x x
+ 0 x x 0
+ 0 0 x x
+ x x 0 0
+
+ with default knobs and no output statistics, do the following:
+
+ #include "colamd.h"
+ #define ALEN 100
+ int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ;
+ int p [ ] = {0, 3, 5, 9, 11} ;
+ int stats [COLAMD_STATS] ;
+ colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
+
+ The permutation is returned in the array p, and A is destroyed.
+
+ ----------------------------------------------------------------------------
+ symamd:
+ ----------------------------------------------------------------------------
+
+ C syntax:
+
+ #include "colamd.h"
+ int symamd (int n, int *A, int *p, int *perm,
+ double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS],
+ void (*allocate) (size_t, size_t), void (*release) (void *)) ;
+ UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm,
+ double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS],
+ void (*allocate) (size_t, size_t), void (*release) (void *)) ;
+
+ Purpose:
+
+ The symamd routine computes an ordering P of a symmetric sparse
+ matrix A such that the Cholesky factorization PAP' = LL' remains
+ sparse. It is based on a column ordering of a matrix M constructed
+ so that the nonzero pattern of M'M is the same as A. The matrix A
+ is assumed to be symmetric; only the strictly lower triangular part
+ is accessed. You must pass your selected memory allocator (usually
+ calloc/free or mxCalloc/mxFree) to symamd, for it to allocate
+ memory for the temporary matrix M.
+
+ Returns:
+
+ TRUE (1) if successful, FALSE (0) otherwise.
+
+ Arguments:
+
+ int n ; Input argument.
+
+ Number of rows and columns in the symmetrix matrix A.
+ Restriction: n >= 0.
+ Symamd returns FALSE if n is negative.
+
+ int A [nnz] ; Input argument.
+
+ A is an integer array of size nnz, where nnz = p [n].
+
+ The row indices of the entries in column c of the matrix are
+ held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a
+ given column c need not be in ascending order, and duplicate
+ row indices may be present. However, symamd will run faster
+ if the columns are in sorted order with no duplicate entries.
+
+ The matrix is 0-based. That is, rows are in the range 0 to
+ n-1, and columns are in the range 0 to n-1. Symamd
+ returns FALSE if any row index is out of range.
+
+ The contents of A are not modified.
+
+ int p [n+1] ; Input argument.
+
+ p is an integer array of size n+1. On input, it holds the
+ "pointers" for the column form of the matrix A. Column c of
+ the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
+ entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+ for all c in the range 0 to n-1. The value p [n] is
+ thus the total number of entries in the pattern of the matrix A.
+ Symamd returns FALSE if these conditions are not met.
+
+ The contents of p are not modified.
+
+ int perm [n+1] ; Output argument.
+
+ On output, if symamd returns TRUE, the array perm holds the
+ permutation P, where perm [0] is the first index in the new
+ ordering, and perm [n-1] is the last. That is, perm [k] = j
+ means that row and column j of A is the kth column in PAP',
+ where k is in the range 0 to n-1 (perm [0] = j means
+ that row and column j of A are the first row and column in
+ PAP'). The array is used as a workspace during the ordering,
+ which is why it must be of length n+1, not just n.
+
+ double knobs [COLAMD_KNOBS] ; Input argument.
+
+ See colamd_set_defaults for a description.
+
+ int stats [COLAMD_STATS] ; Output argument.
+
+ Statistics on the ordering, and error status.
+ See colamd.h for related definitions.
+ Symamd returns FALSE if stats is not present.
+
+ stats [0]: number of dense or empty row and columns ignored
+ (and ordered last in the output permutation
+ perm). Note that a row/column can become
+ "empty" if it contains only "dense" and/or
+ "empty" columns/rows.
+
+ stats [1]: (same as stats [0])
+
+ stats [2]: number of garbage collections performed.
+
+ stats [3]: status code. < 0 is an error code.
+ > 1 is a warning or notice.
+
+ 0 OK. Each column of the input matrix contained
+ row indices in increasing order, with no
+ duplicates.
+
+ 1 OK, but columns of input matrix were jumbled
+ (unsorted columns or duplicate entries). Symamd
+ had to do some extra work to sort the matrix
+ first and remove duplicate entries, but it
+ still was able to return a valid permutation
+ (return value of symamd was TRUE).
+
+ stats [4]: highest numbered column that
+ is unsorted or has duplicate
+ entries.
+ stats [5]: last seen duplicate or
+ unsorted row index.
+ stats [6]: number of duplicate or
+ unsorted row indices.
+
+ -1 A is a null pointer
+
+ -2 p is a null pointer
+
+ -3 (unused, see colamd.c)
+
+ -4 n is negative
+
+ stats [4]: n
+
+ -5 number of nonzeros in matrix is negative
+
+ stats [4]: # of nonzeros (p [n]).
+
+ -6 p [0] is nonzero
+
+ stats [4]: p [0]
+
+ -7 (unused)
+
+ -8 a column has a negative number of entries
+
+ stats [4]: column with < 0 entries
+ stats [5]: number of entries in col
+
+ -9 a row index is out of bounds
+
+ stats [4]: column with bad row index
+ stats [5]: bad row index
+ stats [6]: n_row, # of rows of matrx
+
+ -10 out of memory (unable to allocate temporary
+ workspace for M or count arrays using the
+ "allocate" routine passed into symamd).
+
+ Future versions may return more statistics in the stats array.
+
+ void * (*allocate) (size_t, size_t)
+
+ A pointer to a function providing memory allocation. The
+ allocated memory must be returned initialized to zero. For a
+ C application, this argument should normally be a pointer to
+ calloc. For a MATLAB mexFunction, the routine mxCalloc is
+ passed instead.
+
+ void (*release) (size_t, size_t)
+
+ A pointer to a function that frees memory allocated by the
+ memory allocation routine above. For a C application, this
+ argument should normally be a pointer to free. For a MATLAB
+ mexFunction, the routine mxFree is passed instead.
+
+
+ ----------------------------------------------------------------------------
+ colamd_report:
+ ----------------------------------------------------------------------------
+
+ C syntax:
+
+ #include "colamd.h"
+ colamd_report (int stats [COLAMD_STATS]) ;
+ colamd_l_report (UF_long stats [COLAMD_STATS]) ;
+
+ Purpose:
+
+ Prints the error status and statistics recorded in the stats
+ array on the standard error output (for a standard C routine)
+ or on the MATLAB output (for a mexFunction).
+
+ Arguments:
+
+ int stats [COLAMD_STATS] ; Input only. Statistics from colamd.
+
+
+ ----------------------------------------------------------------------------
+ symamd_report:
+ ----------------------------------------------------------------------------
+
+ C syntax:
+
+ #include "colamd.h"
+ symamd_report (int stats [COLAMD_STATS]) ;
+ symamd_l_report (UF_long stats [COLAMD_STATS]) ;
+
+ Purpose:
+
+ Prints the error status and statistics recorded in the stats
+ array on the standard error output (for a standard C routine)
+ or on the MATLAB output (for a mexFunction).
+
+ Arguments:
+
+ int stats [COLAMD_STATS] ; Input only. Statistics from symamd.
+
+
+*/
+
+/* ========================================================================== */
+/* === Scaffolding code definitions ======================================== */
+/* ========================================================================== */
+
+/* Ensure that debugging is turned off: */
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/* turn on debugging by uncommenting the following line
+ #undef NDEBUG
+*/
+
+/*
+ Our "scaffolding code" philosophy: In our opinion, well-written library
+ code should keep its "debugging" code, and just normally have it turned off
+ by the compiler so as not to interfere with performance. This serves
+ several purposes:
+
+ (1) assertions act as comments to the reader, telling you what the code
+ expects at that point. All assertions will always be true (unless
+ there really is a bug, of course).
+
+ (2) leaving in the scaffolding code assists anyone who would like to modify
+ the code, or understand the algorithm (by reading the debugging output,
+ one can get a glimpse into what the code is doing).
+
+ (3) (gasp!) for actually finding bugs. This code has been heavily tested
+ and "should" be fully functional and bug-free ... but you never know...
+
+ The code will become outrageously slow when debugging is
+ enabled. To control the level of debugging output, set an environment
+ variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging,
+ you should see the following message on the standard output:
+
+ colamd: debug version, D = 1 (THIS WILL BE SLOW!)
+
+ or a similar message for symamd. If you don't, then debugging has not
+ been enabled.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include "colamd.h"
+
+#if 0 /* by mao */
+#include <limits.h>
+#include <math.h>
+
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+#include "matrix.h"
+#endif /* MATLAB_MEX_FILE */
+
+#if !defined (NPRINT) || !defined (NDEBUG)
+#include <stdio.h>
+#endif
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+#endif
+
+/* ========================================================================== */
+/* === int or UF_long ======================================================= */
+/* ========================================================================== */
+
+#if 0 /* by mao */
+/* define UF_long */
+#include "UFconfig.h"
+#endif
+
+#ifdef DLONG
+
+#define Int UF_long
+#define ID UF_long_id
+#define Int_MAX UF_long_max
+
+#define COLAMD_recommended colamd_l_recommended
+#define COLAMD_set_defaults colamd_l_set_defaults
+#define COLAMD_MAIN colamd_l
+#define SYMAMD_MAIN symamd_l
+#define COLAMD_report colamd_l_report
+#define SYMAMD_report symamd_l_report
+
+#else
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+
+#define COLAMD_recommended colamd_recommended
+#define COLAMD_set_defaults colamd_set_defaults
+#define COLAMD_MAIN colamd
+#define SYMAMD_MAIN symamd
+#define COLAMD_report colamd_report
+#define SYMAMD_report symamd_report
+
+#endif
+
+/* ========================================================================== */
+/* === Row and Column structures ============================================ */
+/* ========================================================================== */
+
+/* User code that makes use of the colamd/symamd routines need not directly */
+/* reference these structures. They are used only for colamd_recommended. */
+
+typedef struct Colamd_Col_struct
+{
+ Int start ; /* index for A of first row in this column, or DEAD */
+ /* if column is dead */
+ Int length ; /* number of rows in this column */
+ union
+ {
+ Int thickness ; /* number of original columns represented by this */
+ /* col, if the column is alive */
+ Int parent ; /* parent in parent tree super-column structure, if */
+ /* the column is dead */
+ } shared1 ;
+ union
+ {
+ Int score ; /* the score used to maintain heap, if col is alive */
+ Int order ; /* pivot ordering of this column, if col is dead */
+ } shared2 ;
+ union
+ {
+ Int headhash ; /* head of a hash bucket, if col is at the head of */
+ /* a degree list */
+ Int hash ; /* hash value, if col is not in a degree list */
+ Int prev ; /* previous column in degree list, if col is in a */
+ /* degree list (but not at the head of a degree list) */
+ } shared3 ;
+ union
+ {
+ Int degree_next ; /* next column, if col is in a degree list */
+ Int hash_next ; /* next column, if col is in a hash list */
+ } shared4 ;
+
+} Colamd_Col ;
+
+typedef struct Colamd_Row_struct
+{
+ Int start ; /* index for A of first col in this row */
+ Int length ; /* number of principal columns in this row */
+ union
+ {
+ Int degree ; /* number of principal & non-principal columns in row */
+ Int p ; /* used as a row pointer in init_rows_cols () */
+ } shared1 ;
+ union
+ {
+ Int mark ; /* for computing set differences and marking dead rows*/
+ Int first_column ;/* first column in row (used in garbage collection) */
+ } shared2 ;
+
+} Colamd_Row ;
+
+/* ========================================================================== */
+/* === Definitions ========================================================== */
+/* ========================================================================== */
+
+/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */
+#define PUBLIC
+#define PRIVATE static
+
+#define DENSE_DEGREE(alpha,n) \
+ ((Int) MAX (16.0, (alpha) * sqrt ((double) (n))))
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define ONES_COMPLEMENT(r) (-(r)-1)
+
+/* -------------------------------------------------------------------------- */
+/* Change for version 2.1: define TRUE and FALSE only if not yet defined */
+/* -------------------------------------------------------------------------- */
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+#define EMPTY (-1)
+
+/* Row and column status */
+#define ALIVE (0)
+#define DEAD (-1)
+
+/* Column status */
+#define DEAD_PRINCIPAL (-1)
+#define DEAD_NON_PRINCIPAL (-2)
+
+/* Macros for row and column status update and checking. */
+#define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
+#define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE)
+#define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE)
+#define COL_IS_DEAD(c) (Col [c].start < ALIVE)
+#define COL_IS_ALIVE(c) (Col [c].start >= ALIVE)
+#define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL)
+#define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; }
+#define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; }
+#define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; }
+
+/* ========================================================================== */
+/* === Colamd reporting mechanism =========================================== */
+/* ========================================================================== */
+
+#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
+/* In MATLAB, matrices are 1-based to the user, but 0-based internally */
+#define INDEX(i) ((i)+1)
+#else
+/* In C, matrices are 0-based and indices are reported as such in *_report */
+#define INDEX(i) (i)
+#endif
+
+/* All output goes through the PRINTF macro. */
+#define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; }
+
+/* ========================================================================== */
+/* === Prototypes of PRIVATE routines ======================================= */
+/* ========================================================================== */
+
+PRIVATE Int init_rows_cols
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int p [],
+ Int stats [COLAMD_STATS]
+) ;
+
+PRIVATE void init_scoring
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int head [],
+ double knobs [COLAMD_KNOBS],
+ Int *p_n_row2,
+ Int *p_n_col2,
+ Int *p_max_deg
+) ;
+
+PRIVATE Int find_ordering
+(
+ Int n_row,
+ Int n_col,
+ Int Alen,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int head [],
+ Int n_col2,
+ Int max_deg,
+ Int pfree,
+ Int aggressive
+) ;
+
+PRIVATE void order_children
+(
+ Int n_col,
+ Colamd_Col Col [],
+ Int p []
+) ;
+
+PRIVATE void detect_super_cols
+(
+
+#ifndef NDEBUG
+ Int n_col,
+ Colamd_Row Row [],
+#endif /* NDEBUG */
+
+ Colamd_Col Col [],
+ Int A [],
+ Int head [],
+ Int row_start,
+ Int row_length
+) ;
+
+PRIVATE Int garbage_collection
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int *pfree
+) ;
+
+PRIVATE Int clear_mark
+(
+ Int tag_mark,
+ Int max_mark,
+ Int n_row,
+ Colamd_Row Row []
+) ;
+
+PRIVATE void print_report
+(
+ char *method,
+ Int stats [COLAMD_STATS]
+) ;
+
+/* ========================================================================== */
+/* === Debugging prototypes and definitions ================================= */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+#if 0 /* by mao */
+#include <assert.h>
+#endif
+
+/* colamd_debug is the *ONLY* global variable, and is only */
+/* present when debugging */
+
+PRIVATE Int colamd_debug = 0 ; /* debug print level */
+
+#define DEBUG0(params) { PRINTF (params) ; }
+#define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; }
+#define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; }
+#define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; }
+#define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; }
+
+#if 0 /* by mao */
+#ifdef MATLAB_MEX_FILE
+#define ASSERT(expression) (mxAssert ((expression), ""))
+#else
+#define ASSERT(expression) (assert (expression))
+#endif /* MATLAB_MEX_FILE */
+#else
+#define ASSERT xassert
+#endif
+
+PRIVATE void colamd_get_debug /* gets the debug print level from getenv */
+(
+ char *method
+) ;
+
+PRIVATE void debug_deg_lists
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int head [],
+ Int min_score,
+ Int should,
+ Int max_deg
+) ;
+
+PRIVATE void debug_mark
+(
+ Int n_row,
+ Colamd_Row Row [],
+ Int tag_mark,
+ Int max_mark
+) ;
+
+PRIVATE void debug_matrix
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A []
+) ;
+
+PRIVATE void debug_structures
+(
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int n_col2
+) ;
+
+#else /* NDEBUG */
+
+/* === No debugging ========================================================= */
+
+#define DEBUG0(params) ;
+#define DEBUG1(params) ;
+#define DEBUG2(params) ;
+#define DEBUG3(params) ;
+#define DEBUG4(params) ;
+
+#define ASSERT(expression)
+
+#endif /* NDEBUG */
+
+/* ========================================================================== */
+/* === USER-CALLABLE ROUTINES: ============================================== */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* === colamd_recommended =================================================== */
+/* ========================================================================== */
+
+/*
+ The colamd_recommended routine returns the suggested size for Alen. This
+ value has been determined to provide good balance between the number of
+ garbage collections and the memory requirements for colamd. If any
+ argument is negative, or if integer overflow occurs, a 0 is returned as an
+ error condition. 2*nnz space is required for the row and column
+ indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is
+ required for the Col and Row arrays, respectively, which are internal to
+ colamd (roughly 6*n_col + 4*n_row). An additional n_col space is the
+ minimal amount of "elbow room", and nnz/5 more space is recommended for
+ run time efficiency.
+
+ Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10.
+
+ This function is not needed when using symamd.
+*/
+
+/* add two values of type size_t, and check for integer overflow */
+static size_t t_add (size_t a, size_t b, int *ok)
+{
+ (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
+ return ((*ok) ? (a + b) : 0) ;
+}
+
+/* compute a*k where k is a small integer, and check for integer overflow */
+static size_t t_mult (size_t a, size_t k, int *ok)
+{
+ size_t i, s = 0 ;
+ for (i = 0 ; i < k ; i++)
+ {
+ s = t_add (s, a, ok) ;
+ }
+ return (s) ;
+}
+
+/* size of the Col and Row structures */
+#define COLAMD_C(n_col,ok) \
+ ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int)))
+
+#define COLAMD_R(n_row,ok) \
+ ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int)))
+
+
+PUBLIC size_t COLAMD_recommended /* returns recommended value of Alen. */
+(
+ /* === Parameters ======================================================= */
+
+ Int nnz, /* number of nonzeros in A */
+ Int n_row, /* number of rows in A */
+ Int n_col /* number of columns in A */
+)
+{
+ size_t s, c, r ;
+ int ok = TRUE ;
+ if (nnz < 0 || n_row < 0 || n_col < 0)
+ {
+ return (0) ;
+ }
+ s = t_mult (nnz, 2, &ok) ; /* 2*nnz */
+ c = COLAMD_C (n_col, &ok) ; /* size of column structures */
+ r = COLAMD_R (n_row, &ok) ; /* size of row structures */
+ s = t_add (s, c, &ok) ;
+ s = t_add (s, r, &ok) ;
+ s = t_add (s, n_col, &ok) ; /* elbow room */
+ s = t_add (s, nnz/5, &ok) ; /* elbow room */
+ ok = ok && (s < Int_MAX) ;
+ return (ok ? s : 0) ;
+}
+
+
+/* ========================================================================== */
+/* === colamd_set_defaults ================================================== */
+/* ========================================================================== */
+
+/*
+ The colamd_set_defaults routine sets the default values of the user-
+ controllable parameters for colamd and symamd:
+
+ Colamd: rows with more than max (16, knobs [0] * sqrt (n_col))
+ entries are removed prior to ordering. Columns with more than
+ max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed
+ prior to ordering, and placed last in the output column ordering.
+
+ Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n))
+ entries are removed prior to ordering, and placed last in the
+ output ordering.
+
+ knobs [0] dense row control
+
+ knobs [1] dense column control
+
+ knobs [2] if nonzero, do aggresive absorption
+
+ knobs [3..19] unused, but future versions might use this
+
+*/
+
+PUBLIC void COLAMD_set_defaults
+(
+ /* === Parameters ======================================================= */
+
+ double knobs [COLAMD_KNOBS] /* knob array */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int i ;
+
+ if (!knobs)
+ {
+ return ; /* no knobs to initialize */
+ }
+ for (i = 0 ; i < COLAMD_KNOBS ; i++)
+ {
+ knobs [i] = 0 ;
+ }
+ knobs [COLAMD_DENSE_ROW] = 10 ;
+ knobs [COLAMD_DENSE_COL] = 10 ;
+ knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/
+}
+
+
+/* ========================================================================== */
+/* === symamd =============================================================== */
+/* ========================================================================== */
+
+PUBLIC Int SYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */
+(
+ /* === Parameters ======================================================= */
+
+ Int n, /* number of rows and columns of A */
+ Int A [], /* row indices of A */
+ Int p [], /* column pointers of A */
+ Int perm [], /* output permutation, size n+1 */
+ double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */
+ Int stats [COLAMD_STATS], /* output statistics and error codes */
+ void * (*allocate) (size_t, size_t),
+ /* pointer to calloc (ANSI C) or */
+ /* mxCalloc (for MATLAB mexFunction) */
+ void (*release) (void *)
+ /* pointer to free (ANSI C) or */
+ /* mxFree (for MATLAB mexFunction) */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int *count ; /* length of each column of M, and col pointer*/
+ Int *mark ; /* mark array for finding duplicate entries */
+ Int *M ; /* row indices of matrix M */
+ size_t Mlen ; /* length of M */
+ Int n_row ; /* number of rows in M */
+ Int nnz ; /* number of entries in A */
+ Int i ; /* row index of A */
+ Int j ; /* column index of A */
+ Int k ; /* row index of M */
+ Int mnz ; /* number of nonzeros in M */
+ Int pp ; /* index into a column of A */
+ Int last_row ; /* last row seen in the current column */
+ Int length ; /* number of nonzeros in a column */
+
+ double cknobs [COLAMD_KNOBS] ; /* knobs for colamd */
+ double default_knobs [COLAMD_KNOBS] ; /* default knobs for colamd */
+
+#ifndef NDEBUG
+ colamd_get_debug ("symamd") ;
+#endif /* NDEBUG */
+
+ /* === Check the input arguments ======================================== */
+
+ if (!stats)
+ {
+ DEBUG0 (("symamd: stats not present\n")) ;
+ return (FALSE) ;
+ }
+ for (i = 0 ; i < COLAMD_STATS ; i++)
+ {
+ stats [i] = 0 ;
+ }
+ stats [COLAMD_STATUS] = COLAMD_OK ;
+ stats [COLAMD_INFO1] = -1 ;
+ stats [COLAMD_INFO2] = -1 ;
+
+ if (!A)
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+ DEBUG0 (("symamd: A not present\n")) ;
+ return (FALSE) ;
+ }
+
+ if (!p) /* p is not present */
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+ DEBUG0 (("symamd: p not present\n")) ;
+ return (FALSE) ;
+ }
+
+ if (n < 0) /* n must be >= 0 */
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+ stats [COLAMD_INFO1] = n ;
+ DEBUG0 (("symamd: n negative %d\n", n)) ;
+ return (FALSE) ;
+ }
+
+ nnz = p [n] ;
+ if (nnz < 0) /* nnz must be >= 0 */
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+ stats [COLAMD_INFO1] = nnz ;
+ DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ;
+ return (FALSE) ;
+ }
+
+ if (p [0] != 0)
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
+ stats [COLAMD_INFO1] = p [0] ;
+ DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ;
+ return (FALSE) ;
+ }
+
+ /* === If no knobs, set default knobs =================================== */
+
+ if (!knobs)
+ {
+ COLAMD_set_defaults (default_knobs) ;
+ knobs = default_knobs ;
+ }
+
+ /* === Allocate count and mark ========================================== */
+
+ count = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
+ if (!count)
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+ DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ;
+ return (FALSE) ;
+ }
+
+ mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
+ if (!mark)
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+ (*release) ((void *) count) ;
+ DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ;
+ return (FALSE) ;
+ }
+
+ /* === Compute column counts of M, check if A is valid ================== */
+
+ stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
+
+ for (i = 0 ; i < n ; i++)
+ {
+ mark [i] = -1 ;
+ }
+
+ for (j = 0 ; j < n ; j++)
+ {
+ last_row = -1 ;
+
+ length = p [j+1] - p [j] ;
+ if (length < 0)
+ {
+ /* column pointers must be non-decreasing */
+ stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+ stats [COLAMD_INFO1] = j ;
+ stats [COLAMD_INFO2] = length ;
+ (*release) ((void *) count) ;
+ (*release) ((void *) mark) ;
+ DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ;
+ return (FALSE) ;
+ }
+
+ for (pp = p [j] ; pp < p [j+1] ; pp++)
+ {
+ i = A [pp] ;
+ if (i < 0 || i >= n)
+ {
+ /* row index i, in column j, is out of bounds */
+ stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+ stats [COLAMD_INFO1] = j ;
+ stats [COLAMD_INFO2] = i ;
+ stats [COLAMD_INFO3] = n ;
+ (*release) ((void *) count) ;
+ (*release) ((void *) mark) ;
+ DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ;
+ return (FALSE) ;
+ }
+
+ if (i <= last_row || mark [i] == j)
+ {
+ /* row index is unsorted or repeated (or both), thus col */
+ /* is jumbled. This is a notice, not an error condition. */
+ stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
+ stats [COLAMD_INFO1] = j ;
+ stats [COLAMD_INFO2] = i ;
+ (stats [COLAMD_INFO3]) ++ ;
+ DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ;
+ }
+
+ if (i > j && mark [i] != j)
+ {
+ /* row k of M will contain column indices i and j */
+ count [i]++ ;
+ count [j]++ ;
+ }
+
+ /* mark the row as having been seen in this column */
+ mark [i] = j ;
+
+ last_row = i ;
+ }
+ }
+
+ /* v2.4: removed free(mark) */
+
+ /* === Compute column pointers of M ===================================== */
+
+ /* use output permutation, perm, for column pointers of M */
+ perm [0] = 0 ;
+ for (j = 1 ; j <= n ; j++)
+ {
+ perm [j] = perm [j-1] + count [j-1] ;
+ }
+ for (j = 0 ; j < n ; j++)
+ {
+ count [j] = perm [j] ;
+ }
+
+ /* === Construct M ====================================================== */
+
+ mnz = perm [n] ;
+ n_row = mnz / 2 ;
+ Mlen = COLAMD_recommended (mnz, n_row, n) ;
+ M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ;
+ DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n",
+ n_row, n, mnz, (double) Mlen)) ;
+
+ if (!M)
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+ (*release) ((void *) count) ;
+ (*release) ((void *) mark) ;
+ DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ;
+ return (FALSE) ;
+ }
+
+ k = 0 ;
+
+ if (stats [COLAMD_STATUS] == COLAMD_OK)
+ {
+ /* Matrix is OK */
+ for (j = 0 ; j < n ; j++)
+ {
+ ASSERT (p [j+1] - p [j] >= 0) ;
+ for (pp = p [j] ; pp < p [j+1] ; pp++)
+ {
+ i = A [pp] ;
+ ASSERT (i >= 0 && i < n) ;
+ if (i > j)
+ {
+ /* row k of M contains column indices i and j */
+ M [count [i]++] = k ;
+ M [count [j]++] = k ;
+ k++ ;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */
+ DEBUG0 (("symamd: Duplicates in A.\n")) ;
+ for (i = 0 ; i < n ; i++)
+ {
+ mark [i] = -1 ;
+ }
+ for (j = 0 ; j < n ; j++)
+ {
+ ASSERT (p [j+1] - p [j] >= 0) ;
+ for (pp = p [j] ; pp < p [j+1] ; pp++)
+ {
+ i = A [pp] ;
+ ASSERT (i >= 0 && i < n) ;
+ if (i > j && mark [i] != j)
+ {
+ /* row k of M contains column indices i and j */
+ M [count [i]++] = k ;
+ M [count [j]++] = k ;
+ k++ ;
+ mark [i] = j ;
+ }
+ }
+ }
+ /* v2.4: free(mark) moved below */
+ }
+
+ /* count and mark no longer needed */
+ (*release) ((void *) count) ;
+ (*release) ((void *) mark) ; /* v2.4: free (mark) moved here */
+ ASSERT (k == n_row) ;
+
+ /* === Adjust the knobs for M =========================================== */
+
+ for (i = 0 ; i < COLAMD_KNOBS ; i++)
+ {
+ cknobs [i] = knobs [i] ;
+ }
+
+ /* there are no dense rows in M */
+ cknobs [COLAMD_DENSE_ROW] = -1 ;
+ cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ;
+
+ /* === Order the columns of M =========================================== */
+
+ /* v2.4: colamd cannot fail here, so the error check is removed */
+ (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ;
+
+ /* Note that the output permutation is now in perm */
+
+ /* === get the statistics for symamd from colamd ======================== */
+
+ /* a dense column in colamd means a dense row and col in symamd */
+ stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ;
+
+ /* === Free M =========================================================== */
+
+ (*release) ((void *) M) ;
+ DEBUG0 (("symamd: done.\n")) ;
+ return (TRUE) ;
+
+}
+
+/* ========================================================================== */
+/* === colamd =============================================================== */
+/* ========================================================================== */
+
+/*
+ The colamd routine computes a column ordering Q of a sparse matrix
+ A such that the LU factorization P(AQ) = LU remains sparse, where P is
+ selected via partial pivoting. The routine can also be viewed as
+ providing a permutation Q such that the Cholesky factorization
+ (AQ)'(AQ) = LL' remains sparse.
+*/
+
+PUBLIC Int COLAMD_MAIN /* returns TRUE if successful, FALSE otherwise*/
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows in A */
+ Int n_col, /* number of columns in A */
+ Int Alen, /* length of A */
+ Int A [], /* row indices of A */
+ Int p [], /* pointers to columns in A */
+ double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
+ Int stats [COLAMD_STATS] /* output statistics and error codes */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int i ; /* loop index */
+ Int nnz ; /* nonzeros in A */
+ size_t Row_size ; /* size of Row [], in integers */
+ size_t Col_size ; /* size of Col [], in integers */
+ size_t need ; /* minimum required length of A */
+ Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */
+ Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */
+ Int n_col2 ; /* number of non-dense, non-empty columns */
+ Int n_row2 ; /* number of non-dense, non-empty rows */
+ Int ngarbage ; /* number of garbage collections performed */
+ Int max_deg ; /* maximum row degree */
+ double default_knobs [COLAMD_KNOBS] ; /* default knobs array */
+ Int aggressive ; /* do aggressive absorption */
+ int ok ;
+
+#ifndef NDEBUG
+ colamd_get_debug ("colamd") ;
+#endif /* NDEBUG */
+
+ /* === Check the input arguments ======================================== */
+
+ if (!stats)
+ {
+ DEBUG0 (("colamd: stats not present\n")) ;
+ return (FALSE) ;
+ }
+ for (i = 0 ; i < COLAMD_STATS ; i++)
+ {
+ stats [i] = 0 ;
+ }
+ stats [COLAMD_STATUS] = COLAMD_OK ;
+ stats [COLAMD_INFO1] = -1 ;
+ stats [COLAMD_INFO2] = -1 ;
+
+ if (!A) /* A is not present */
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+ DEBUG0 (("colamd: A not present\n")) ;
+ return (FALSE) ;
+ }
+
+ if (!p) /* p is not present */
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+ DEBUG0 (("colamd: p not present\n")) ;
+ return (FALSE) ;
+ }
+
+ if (n_row < 0) /* n_row must be >= 0 */
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
+ stats [COLAMD_INFO1] = n_row ;
+ DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
+ return (FALSE) ;
+ }
+
+ if (n_col < 0) /* n_col must be >= 0 */
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+ stats [COLAMD_INFO1] = n_col ;
+ DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
+ return (FALSE) ;
+ }
+
+ nnz = p [n_col] ;
+ if (nnz < 0) /* nnz must be >= 0 */
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+ stats [COLAMD_INFO1] = nnz ;
+ DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
+ return (FALSE) ;
+ }
+
+ if (p [0] != 0)
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
+ stats [COLAMD_INFO1] = p [0] ;
+ DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
+ return (FALSE) ;
+ }
+
+ /* === If no knobs, set default knobs =================================== */
+
+ if (!knobs)
+ {
+ COLAMD_set_defaults (default_knobs) ;
+ knobs = default_knobs ;
+ }
+
+ aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ;
+
+ /* === Allocate the Row and Col arrays from array A ===================== */
+
+ ok = TRUE ;
+ Col_size = COLAMD_C (n_col, &ok) ; /* size of Col array of structs */
+ Row_size = COLAMD_R (n_row, &ok) ; /* size of Row array of structs */
+
+ /* need = 2*nnz + n_col + Col_size + Row_size ; */
+ need = t_mult (nnz, 2, &ok) ;
+ need = t_add (need, n_col, &ok) ;
+ need = t_add (need, Col_size, &ok) ;
+ need = t_add (need, Row_size, &ok) ;
+
+ if (!ok || need > (size_t) Alen || need > Int_MAX)
+ {
+ /* not enough space in array A to perform the ordering */
+ stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
+ stats [COLAMD_INFO1] = need ;
+ stats [COLAMD_INFO2] = Alen ;
+ DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
+ return (FALSE) ;
+ }
+
+ Alen -= Col_size + Row_size ;
+ Col = (Colamd_Col *) &A [Alen] ;
+ Row = (Colamd_Row *) &A [Alen + Col_size] ;
+
+ /* === Construct the row and column data structures ===================== */
+
+ if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
+ {
+ /* input matrix is invalid */
+ DEBUG0 (("colamd: Matrix invalid\n")) ;
+ return (FALSE) ;
+ }
+
+ /* === Initialize scores, kill dense rows/columns ======================= */
+
+ init_scoring (n_row, n_col, Row, Col, A, p, knobs,
+ &n_row2, &n_col2, &max_deg) ;
+
+ /* === Order the supercolumns =========================================== */
+
+ ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
+ n_col2, max_deg, 2*nnz, aggressive) ;
+
+ /* === Order the non-principal columns ================================== */
+
+ order_children (n_col, Col, p) ;
+
+ /* === Return statistics in stats ======================================= */
+
+ stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
+ stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
+ stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
+ DEBUG0 (("colamd: done.\n")) ;
+ return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === colamd_report ======================================================== */
+/* ========================================================================== */
+
+PUBLIC void COLAMD_report
+(
+ Int stats [COLAMD_STATS]
+)
+{
+ print_report ("colamd", stats) ;
+}
+
+
+/* ========================================================================== */
+/* === symamd_report ======================================================== */
+/* ========================================================================== */
+
+PUBLIC void SYMAMD_report
+(
+ Int stats [COLAMD_STATS]
+)
+{
+ print_report ("symamd", stats) ;
+}
+
+
+
+/* ========================================================================== */
+/* === NON-USER-CALLABLE ROUTINES: ========================================== */
+/* ========================================================================== */
+
+/* There are no user-callable routines beyond this point in the file */
+
+
+/* ========================================================================== */
+/* === init_rows_cols ======================================================= */
+/* ========================================================================== */
+
+/*
+ Takes the column form of the matrix in A and creates the row form of the
+ matrix. Also, row and column attributes are stored in the Col and Row
+ structs. If the columns are un-sorted or contain duplicate row indices,
+ this routine will also sort and remove duplicate row indices from the
+ column form of the matrix. Returns FALSE if the matrix is invalid,
+ TRUE otherwise. Not user-callable.
+*/
+
+PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows of A */
+ Int n_col, /* number of columns of A */
+ Colamd_Row Row [], /* of size n_row+1 */
+ Colamd_Col Col [], /* of size n_col+1 */
+ Int A [], /* row indices of A, of size Alen */
+ Int p [], /* pointers to columns in A, of size n_col+1 */
+ Int stats [COLAMD_STATS] /* colamd statistics */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int col ; /* a column index */
+ Int row ; /* a row index */
+ Int *cp ; /* a column pointer */
+ Int *cp_end ; /* a pointer to the end of a column */
+ Int *rp ; /* a row pointer */
+ Int *rp_end ; /* a pointer to the end of a row */
+ Int last_row ; /* previous row */
+
+ /* === Initialize columns, and check column pointers ==================== */
+
+ for (col = 0 ; col < n_col ; col++)
+ {
+ Col [col].start = p [col] ;
+ Col [col].length = p [col+1] - p [col] ;
+
+ if (Col [col].length < 0)
+ {
+ /* column pointers must be non-decreasing */
+ stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+ stats [COLAMD_INFO1] = col ;
+ stats [COLAMD_INFO2] = Col [col].length ;
+ DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
+ return (FALSE) ;
+ }
+
+ Col [col].shared1.thickness = 1 ;
+ Col [col].shared2.score = 0 ;
+ Col [col].shared3.prev = EMPTY ;
+ Col [col].shared4.degree_next = EMPTY ;
+ }
+
+ /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
+
+ /* === Scan columns, compute row degrees, and check row indices ========= */
+
+ stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ Row [row].length = 0 ;
+ Row [row].shared2.mark = -1 ;
+ }
+
+ for (col = 0 ; col < n_col ; col++)
+ {
+ last_row = -1 ;
+
+ cp = &A [p [col]] ;
+ cp_end = &A [p [col+1]] ;
+
+ while (cp < cp_end)
+ {
+ row = *cp++ ;
+
+ /* make sure row indices within range */
+ if (row < 0 || row >= n_row)
+ {
+ stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+ stats [COLAMD_INFO1] = col ;
+ stats [COLAMD_INFO2] = row ;
+ stats [COLAMD_INFO3] = n_row ;
+ DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
+ return (FALSE) ;
+ }
+
+ if (row <= last_row || Row [row].shared2.mark == col)
+ {
+ /* row index are unsorted or repeated (or both), thus col */
+ /* is jumbled. This is a notice, not an error condition. */
+ stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
+ stats [COLAMD_INFO1] = col ;
+ stats [COLAMD_INFO2] = row ;
+ (stats [COLAMD_INFO3]) ++ ;
+ DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
+ }
+
+ if (Row [row].shared2.mark != col)
+ {
+ Row [row].length++ ;
+ }
+ else
+ {
+ /* this is a repeated entry in the column, */
+ /* it will be removed */
+ Col [col].length-- ;
+ }
+
+ /* mark the row as having been seen in this column */
+ Row [row].shared2.mark = col ;
+
+ last_row = row ;
+ }
+ }
+
+ /* === Compute row pointers ============================================= */
+
+ /* row form of the matrix starts directly after the column */
+ /* form of matrix in A */
+ Row [0].start = p [n_col] ;
+ Row [0].shared1.p = Row [0].start ;
+ Row [0].shared2.mark = -1 ;
+ for (row = 1 ; row < n_row ; row++)
+ {
+ Row [row].start = Row [row-1].start + Row [row-1].length ;
+ Row [row].shared1.p = Row [row].start ;
+ Row [row].shared2.mark = -1 ;
+ }
+
+ /* === Create row form ================================================== */
+
+ if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
+ {
+ /* if cols jumbled, watch for repeated row indices */
+ for (col = 0 ; col < n_col ; col++)
+ {
+ cp = &A [p [col]] ;
+ cp_end = &A [p [col+1]] ;
+ while (cp < cp_end)
+ {
+ row = *cp++ ;
+ if (Row [row].shared2.mark != col)
+ {
+ A [(Row [row].shared1.p)++] = col ;
+ Row [row].shared2.mark = col ;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* if cols not jumbled, we don't need the mark (this is faster) */
+ for (col = 0 ; col < n_col ; col++)
+ {
+ cp = &A [p [col]] ;
+ cp_end = &A [p [col+1]] ;
+ while (cp < cp_end)
+ {
+ A [(Row [*cp++].shared1.p)++] = col ;
+ }
+ }
+ }
+
+ /* === Clear the row marks and set row degrees ========================== */
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ Row [row].shared2.mark = 0 ;
+ Row [row].shared1.degree = Row [row].length ;
+ }
+
+ /* === See if we need to re-create columns ============================== */
+
+ if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
+ {
+ DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
+
+#ifndef NDEBUG
+ /* make sure column lengths are correct */
+ for (col = 0 ; col < n_col ; col++)
+ {
+ p [col] = Col [col].length ;
+ }
+ for (row = 0 ; row < n_row ; row++)
+ {
+ rp = &A [Row [row].start] ;
+ rp_end = rp + Row [row].length ;
+ while (rp < rp_end)
+ {
+ p [*rp++]-- ;
+ }
+ }
+ for (col = 0 ; col < n_col ; col++)
+ {
+ ASSERT (p [col] == 0) ;
+ }
+ /* now p is all zero (different than when debugging is turned off) */
+#endif /* NDEBUG */
+
+ /* === Compute col pointers ========================================= */
+
+ /* col form of the matrix starts at A [0]. */
+ /* Note, we may have a gap between the col form and the row */
+ /* form if there were duplicate entries, if so, it will be */
+ /* removed upon the first garbage collection */
+ Col [0].start = 0 ;
+ p [0] = Col [0].start ;
+ for (col = 1 ; col < n_col ; col++)
+ {
+ /* note that the lengths here are for pruned columns, i.e. */
+ /* no duplicate row indices will exist for these columns */
+ Col [col].start = Col [col-1].start + Col [col-1].length ;
+ p [col] = Col [col].start ;
+ }
+
+ /* === Re-create col form =========================================== */
+
+ for (row = 0 ; row < n_row ; row++)
+ {
+ rp = &A [Row [row].start] ;
+ rp_end = rp + Row [row].length ;
+ while (rp < rp_end)
+ {
+ A [(p [*rp++])++] = row ;
+ }
+ }
+ }
+
+ /* === Done. Matrix is not (or no longer) jumbled ====================== */
+
+ return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === init_scoring ========================================================= */
+/* ========================================================================== */
+
+/*
+ Kills dense or empty columns and rows, calculates an initial score for
+ each column, and places all columns in the degree lists. Not user-callable.
+*/
+
+PRIVATE void init_scoring
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows of A */
+ Int n_col, /* number of columns of A */
+ Colamd_Row Row [], /* of size n_row+1 */
+ Colamd_Col Col [], /* of size n_col+1 */
+ Int A [], /* column form and row form of A */
+ Int head [], /* of size n_col+1 */
+ double knobs [COLAMD_KNOBS],/* parameters */
+ Int *p_n_row2, /* number of non-dense, non-empty rows */
+ Int *p_n_col2, /* number of non-dense, non-empty columns */
+ Int *p_max_deg /* maximum row degree */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int c ; /* a column index */
+ Int r, row ; /* a row index */
+ Int *cp ; /* a column pointer */
+ Int deg ; /* degree of a row or column */
+ Int *cp_end ; /* a pointer to the end of a column */
+ Int *new_cp ; /* new column pointer */
+ Int col_length ; /* length of pruned column */
+ Int score ; /* current column score */
+ Int n_col2 ; /* number of non-dense, non-empty columns */
+ Int n_row2 ; /* number of non-dense, non-empty rows */
+ Int dense_row_count ; /* remove rows with more entries than this */
+ Int dense_col_count ; /* remove cols with more entries than this */
+ Int min_score ; /* smallest column score */
+ Int max_deg ; /* maximum row degree */
+ Int next_col ; /* Used to add to degree list.*/
+
+#ifndef NDEBUG
+ Int debug_count ; /* debug only. */
+#endif /* NDEBUG */
+
+ /* === Extract knobs ==================================================== */
+
+ /* Note: if knobs contains a NaN, this is undefined: */
+ if (knobs [COLAMD_DENSE_ROW] < 0)
+ {
+ /* only remove completely dense rows */
+ dense_row_count = n_col-1 ;
+ }
+ else
+ {
+ dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ;
+ }
+ if (knobs [COLAMD_DENSE_COL] < 0)
+ {
+ /* only remove completely dense columns */
+ dense_col_count = n_row-1 ;
+ }
+ else
+ {
+ dense_col_count =
+ DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ;
+ }
+
+ DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
+ max_deg = 0 ;
+ n_col2 = n_col ;
+ n_row2 = n_row ;
+
+ /* === Kill empty columns =============================================== */
+
+ /* Put the empty columns at the end in their natural order, so that LU */
+ /* factorization can proceed as far as possible. */
+ for (c = n_col-1 ; c >= 0 ; c--)
+ {
+ deg = Col [c].length ;
+ if (deg == 0)
+ {
+ /* this is a empty column, kill and order it last */
+ Col [c].shared2.order = --n_col2 ;
+ KILL_PRINCIPAL_COL (c) ;
+ }
+ }
+ DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
+
+ /* === Kill dense columns =============================================== */
+
+ /* Put the dense columns at the end, in their natural order */
+ for (c = n_col-1 ; c >= 0 ; c--)
+ {
+ /* skip any dead columns */
+ if (COL_IS_DEAD (c))
+ {
+ continue ;
+ }
+ deg = Col [c].length ;
+ if (deg > dense_col_count)
+ {
+ /* this is a dense column, kill and order it last */
+ Col [c].shared2.order = --n_col2 ;
+ /* decrement the row degrees */
+ cp = &A [Col [c].start] ;
+ cp_end = cp + Col [c].length ;
+ while (cp < cp_end)
+ {
+ Row [*cp++].shared1.degree-- ;
+ }
+ KILL_PRINCIPAL_COL (c) ;
+ }
+ }
+ DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
+
+ /* === Kill dense and empty rows ======================================== */
+
+ for (r = 0 ; r < n_row ; r++)
+ {
+ deg = Row [r].shared1.degree ;
+ ASSERT (deg >= 0 && deg <= n_col) ;
+ if (deg > dense_row_count || deg == 0)
+ {
+ /* kill a dense or empty row */
+ KILL_ROW (r) ;
+ --n_row2 ;
+ }
+ else
+ {
+ /* keep track of max degree of remaining rows */
+ max_deg = MAX (max_deg, deg) ;
+ }
+ }
+ DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
+
+ /* === Compute initial column scores ==================================== */
+
+ /* At this point the row degrees are accurate. They reflect the number */
+ /* of "live" (non-dense) columns in each row. No empty rows exist. */
+ /* Some "live" columns may contain only dead rows, however. These are */
+ /* pruned in the code below. */
+
+ /* now find the initial matlab score for each column */
+ for (c = n_col-1 ; c >= 0 ; c--)
+ {
+ /* skip dead column */
+ if (COL_IS_DEAD (c))
+ {
+ continue ;
+ }
+ score = 0 ;
+ cp = &A [Col [c].start] ;
+ new_cp = cp ;
+ cp_end = cp + Col [c].length ;
+ while (cp < cp_end)
+ {
+ /* get a row */
+ row = *cp++ ;
+ /* skip if dead */
+ if (ROW_IS_DEAD (row))
+ {
+ continue ;
+ }
+ /* compact the column */
+ *new_cp++ = row ;
+ /* add row's external degree */
+ score += Row [row].shared1.degree - 1 ;
+ /* guard against integer overflow */
+ score = MIN (score, n_col) ;
+ }
+ /* determine pruned column length */
+ col_length = (Int) (new_cp - &A [Col [c].start]) ;
+ if (col_length == 0)
+ {
+ /* a newly-made null column (all rows in this col are "dense" */
+ /* and have already been killed) */
+ DEBUG2 (("Newly null killed: %d\n", c)) ;
+ Col [c].shared2.order = --n_col2 ;
+ KILL_PRINCIPAL_COL (c) ;
+ }
+ else
+ {
+ /* set column length and set score */
+ ASSERT (score >= 0) ;
+ ASSERT (score <= n_col) ;
+ Col [c].length = col_length ;
+ Col [c].shared2.score = score ;
+ }
+ }
+ DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
+ n_col-n_col2)) ;
+
+ /* At this point, all empty rows and columns are dead. All live columns */
+ /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
+ /* yet). Rows may contain dead columns, but all live rows contain at */
+ /* least one live column. */
+
+#ifndef NDEBUG
+ debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
+#endif /* NDEBUG */
+
+ /* === Initialize degree lists ========================================== */
+
+#ifndef NDEBUG
+ debug_count = 0 ;
+#endif /* NDEBUG */
+
+ /* clear the hash buckets */
+ for (c = 0 ; c <= n_col ; c++)
+ {
+ head [c] = EMPTY ;
+ }
+ min_score = n_col ;
+ /* place in reverse order, so low column indices are at the front */
+ /* of the lists. This is to encourage natural tie-breaking */
+ for (c = n_col-1 ; c >= 0 ; c--)
+ {
+ /* only add principal columns to degree lists */
+ if (COL_IS_ALIVE (c))
+ {
+ DEBUG4 (("place %d score %d minscore %d ncol %d\n",
+ c, Col [c].shared2.score, min_score, n_col)) ;
+
+ /* === Add columns score to DList =============================== */
+
+ score = Col [c].shared2.score ;
+
+ ASSERT (min_score >= 0) ;
+ ASSERT (min_score <= n_col) ;
+ ASSERT (score >= 0) ;
+ ASSERT (score <= n_col) ;
+ ASSERT (head [score] >= EMPTY) ;
+
+ /* now add this column to dList at proper score location */
+ next_col = head [score] ;
+ Col [c].shared3.prev = EMPTY ;
+ Col [c].shared4.degree_next = next_col ;
+
+ /* if there already was a column with the same score, set its */
+ /* previous pointer to this new column */
+ if (next_col != EMPTY)
+ {
+ Col [next_col].shared3.prev = c ;
+ }
+ head [score] = c ;
+
+ /* see if this score is less than current min */
+ min_score = MIN (min_score, score) ;
+
+#ifndef NDEBUG
+ debug_count++ ;
+#endif /* NDEBUG */
+
+ }
+ }
+
+#ifndef NDEBUG
+ DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n",
+ debug_count, n_col, n_col-debug_count)) ;
+ ASSERT (debug_count == n_col2) ;
+ debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
+#endif /* NDEBUG */
+
+ /* === Return number of remaining columns, and max row degree =========== */
+
+ *p_n_col2 = n_col2 ;
+ *p_n_row2 = n_row2 ;
+ *p_max_deg = max_deg ;
+}
+
+
+/* ========================================================================== */
+/* === find_ordering ======================================================== */
+/* ========================================================================== */
+
+/*
+ Order the principal columns of the supercolumn form of the matrix
+ (no supercolumns on input). Uses a minimum approximate column minimum
+ degree ordering method. Not user-callable.
+*/
+
+PRIVATE Int find_ordering /* return the number of garbage collections */
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows of A */
+ Int n_col, /* number of columns of A */
+ Int Alen, /* size of A, 2*nnz + n_col or larger */
+ Colamd_Row Row [], /* of size n_row+1 */
+ Colamd_Col Col [], /* of size n_col+1 */
+ Int A [], /* column form and row form of A */
+ Int head [], /* of size n_col+1 */
+ Int n_col2, /* Remaining columns to order */
+ Int max_deg, /* Maximum row degree */
+ Int pfree, /* index of first free slot (2*nnz on entry) */
+ Int aggressive
+)
+{
+ /* === Local variables ================================================== */
+
+ Int k ; /* current pivot ordering step */
+ Int pivot_col ; /* current pivot column */
+ Int *cp ; /* a column pointer */
+ Int *rp ; /* a row pointer */
+ Int pivot_row ; /* current pivot row */
+ Int *new_cp ; /* modified column pointer */
+ Int *new_rp ; /* modified row pointer */
+ Int pivot_row_start ; /* pointer to start of pivot row */
+ Int pivot_row_degree ; /* number of columns in pivot row */
+ Int pivot_row_length ; /* number of supercolumns in pivot row */
+ Int pivot_col_score ; /* score of pivot column */
+ Int needed_memory ; /* free space needed for pivot row */
+ Int *cp_end ; /* pointer to the end of a column */
+ Int *rp_end ; /* pointer to the end of a row */
+ Int row ; /* a row index */
+ Int col ; /* a column index */
+ Int max_score ; /* maximum possible score */
+ Int cur_score ; /* score of current column */
+ unsigned Int hash ; /* hash value for supernode detection */
+ Int head_column ; /* head of hash bucket */
+ Int first_col ; /* first column in hash bucket */
+ Int tag_mark ; /* marker value for mark array */
+ Int row_mark ; /* Row [row].shared2.mark */
+ Int set_difference ; /* set difference size of row with pivot row */
+ Int min_score ; /* smallest column score */
+ Int col_thickness ; /* "thickness" (no. of columns in a supercol) */
+ Int max_mark ; /* maximum value of tag_mark */
+ Int pivot_col_thickness ; /* number of columns represented by pivot col */
+ Int prev_col ; /* Used by Dlist operations. */
+ Int next_col ; /* Used by Dlist operations. */
+ Int ngarbage ; /* number of garbage collections performed */
+
+#ifndef NDEBUG
+ Int debug_d ; /* debug loop counter */
+ Int debug_step = 0 ; /* debug loop counter */
+#endif /* NDEBUG */
+
+ /* === Initialization and clear mark ==================================== */
+
+ max_mark = INT_MAX - n_col ; /* INT_MAX defined in <limits.h> */
+ tag_mark = clear_mark (0, max_mark, n_row, Row) ;
+ min_score = 0 ;
+ ngarbage = 0 ;
+ DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
+
+ /* === Order the columns ================================================ */
+
+ for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
+ {
+
+#ifndef NDEBUG
+ if (debug_step % 100 == 0)
+ {
+ DEBUG2 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ;
+ }
+ else
+ {
+ DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ;
+ }
+ debug_step++ ;
+ debug_deg_lists (n_row, n_col, Row, Col, head,
+ min_score, n_col2-k, max_deg) ;
+ debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+
+ /* === Select pivot column, and order it ============================ */
+
+ /* make sure degree list isn't empty */
+ ASSERT (min_score >= 0) ;
+ ASSERT (min_score <= n_col) ;
+ ASSERT (head [min_score] >= EMPTY) ;
+
+#ifndef NDEBUG
+ for (debug_d = 0 ; debug_d < min_score ; debug_d++)
+ {
+ ASSERT (head [debug_d] == EMPTY) ;
+ }
+#endif /* NDEBUG */
+
+ /* get pivot column from head of minimum degree list */
+ while (head [min_score] == EMPTY && min_score < n_col)
+ {
+ min_score++ ;
+ }
+ pivot_col = head [min_score] ;
+ ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
+ next_col = Col [pivot_col].shared4.degree_next ;
+ head [min_score] = next_col ;
+ if (next_col != EMPTY)
+ {
+ Col [next_col].shared3.prev = EMPTY ;
+ }
+
+ ASSERT (COL_IS_ALIVE (pivot_col)) ;
+
+ /* remember score for defrag check */
+ pivot_col_score = Col [pivot_col].shared2.score ;
+
+ /* the pivot column is the kth column in the pivot order */
+ Col [pivot_col].shared2.order = k ;
+
+ /* increment order count by column thickness */
+ pivot_col_thickness = Col [pivot_col].shared1.thickness ;
+ k += pivot_col_thickness ;
+ ASSERT (pivot_col_thickness > 0) ;
+ DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ;
+
+ /* === Garbage_collection, if necessary ============================= */
+
+ needed_memory = MIN (pivot_col_score, n_col - k) ;
+ if (pfree + needed_memory >= Alen)
+ {
+ pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
+ ngarbage++ ;
+ /* after garbage collection we will have enough */
+ ASSERT (pfree + needed_memory < Alen) ;
+ /* garbage collection has wiped out the Row[].shared2.mark array */
+ tag_mark = clear_mark (0, max_mark, n_row, Row) ;
+
+#ifndef NDEBUG
+ debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+ }
+
+ /* === Compute pivot row pattern ==================================== */
+
+ /* get starting location for this new merged row */
+ pivot_row_start = pfree ;
+
+ /* initialize new row counts to zero */
+ pivot_row_degree = 0 ;
+
+ /* tag pivot column as having been visited so it isn't included */
+ /* in merged pivot row */
+ Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
+
+ /* pivot row is the union of all rows in the pivot column pattern */
+ cp = &A [Col [pivot_col].start] ;
+ cp_end = cp + Col [pivot_col].length ;
+ while (cp < cp_end)
+ {
+ /* get a row */
+ row = *cp++ ;
+ DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
+ /* skip if row is dead */
+ if (ROW_IS_ALIVE (row))
+ {
+ rp = &A [Row [row].start] ;
+ rp_end = rp + Row [row].length ;
+ while (rp < rp_end)
+ {
+ /* get a column */
+ col = *rp++ ;
+ /* add the column, if alive and untagged */
+ col_thickness = Col [col].shared1.thickness ;
+ if (col_thickness > 0 && COL_IS_ALIVE (col))
+ {
+ /* tag column in pivot row */
+ Col [col].shared1.thickness = -col_thickness ;
+ ASSERT (pfree < Alen) ;
+ /* place column in pivot row */
+ A [pfree++] = col ;
+ pivot_row_degree += col_thickness ;
+ }
+ }
+ }
+ }
+
+ /* clear tag on pivot column */
+ Col [pivot_col].shared1.thickness = pivot_col_thickness ;
+ max_deg = MAX (max_deg, pivot_row_degree) ;
+
+#ifndef NDEBUG
+ DEBUG3 (("check2\n")) ;
+ debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+ /* === Kill all rows used to construct pivot row ==================== */
+
+ /* also kill pivot row, temporarily */
+ cp = &A [Col [pivot_col].start] ;
+ cp_end = cp + Col [pivot_col].length ;
+ while (cp < cp_end)
+ {
+ /* may be killing an already dead row */
+ row = *cp++ ;
+ DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
+ KILL_ROW (row) ;
+ }
+
+ /* === Select a row index to use as the new pivot row =============== */
+
+ pivot_row_length = pfree - pivot_row_start ;
+ if (pivot_row_length > 0)
+ {
+ /* pick the "pivot" row arbitrarily (first row in col) */
+ pivot_row = A [Col [pivot_col].start] ;
+ DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
+ }
+ else
+ {
+ /* there is no pivot row, since it is of zero length */
+ pivot_row = EMPTY ;
+ ASSERT (pivot_row_length == 0) ;
+ }
+ ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
+
+ /* === Approximate degree computation =============================== */
+
+ /* Here begins the computation of the approximate degree. The column */
+ /* score is the sum of the pivot row "length", plus the size of the */
+ /* set differences of each row in the column minus the pattern of the */
+ /* pivot row itself. The column ("thickness") itself is also */
+ /* excluded from the column score (we thus use an approximate */
+ /* external degree). */
+
+ /* The time taken by the following code (compute set differences, and */
+ /* add them up) is proportional to the size of the data structure */
+ /* being scanned - that is, the sum of the sizes of each column in */
+ /* the pivot row. Thus, the amortized time to compute a column score */
+ /* is proportional to the size of that column (where size, in this */
+ /* context, is the column "length", or the number of row indices */
+ /* in that column). The number of row indices in a column is */
+ /* monotonically non-decreasing, from the length of the original */
+ /* column on input to colamd. */
+
+ /* === Compute set differences ====================================== */
+
+ DEBUG3 (("** Computing set differences phase. **\n")) ;
+
+ /* pivot row is currently dead - it will be revived later. */
+
+ DEBUG3 (("Pivot row: ")) ;
+ /* for each column in pivot row */
+ rp = &A [pivot_row_start] ;
+ rp_end = rp + pivot_row_length ;
+ while (rp < rp_end)
+ {
+ col = *rp++ ;
+ ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+ DEBUG3 (("Col: %d\n", col)) ;
+
+ /* clear tags used to construct pivot row pattern */
+ col_thickness = -Col [col].shared1.thickness ;
+ ASSERT (col_thickness > 0) ;
+ Col [col].shared1.thickness = col_thickness ;
+
+ /* === Remove column from degree list =========================== */
+
+ cur_score = Col [col].shared2.score ;
+ prev_col = Col [col].shared3.prev ;
+ next_col = Col [col].shared4.degree_next ;
+ ASSERT (cur_score >= 0) ;
+ ASSERT (cur_score <= n_col) ;
+ ASSERT (cur_score >= EMPTY) ;
+ if (prev_col == EMPTY)
+ {
+ head [cur_score] = next_col ;
+ }
+ else
+ {
+ Col [prev_col].shared4.degree_next = next_col ;
+ }
+ if (next_col != EMPTY)
+ {
+ Col [next_col].shared3.prev = prev_col ;
+ }
+
+ /* === Scan the column ========================================== */
+
+ cp = &A [Col [col].start] ;
+ cp_end = cp + Col [col].length ;
+ while (cp < cp_end)
+ {
+ /* get a row */
+ row = *cp++ ;
+ row_mark = Row [row].shared2.mark ;
+ /* skip if dead */
+ if (ROW_IS_MARKED_DEAD (row_mark))
+ {
+ continue ;
+ }
+ ASSERT (row != pivot_row) ;
+ set_difference = row_mark - tag_mark ;
+ /* check if the row has been seen yet */
+ if (set_difference < 0)
+ {
+ ASSERT (Row [row].shared1.degree <= max_deg) ;
+ set_difference = Row [row].shared1.degree ;
+ }
+ /* subtract column thickness from this row's set difference */
+ set_difference -= col_thickness ;
+ ASSERT (set_difference >= 0) ;
+ /* absorb this row if the set difference becomes zero */
+ if (set_difference == 0 && aggressive)
+ {
+ DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
+ KILL_ROW (row) ;
+ }
+ else
+ {
+ /* save the new mark */
+ Row [row].shared2.mark = set_difference + tag_mark ;
+ }
+ }
+ }
+
+#ifndef NDEBUG
+ debug_deg_lists (n_row, n_col, Row, Col, head,
+ min_score, n_col2-k-pivot_row_degree, max_deg) ;
+#endif /* NDEBUG */
+
+ /* === Add up set differences for each column ======================= */
+
+ DEBUG3 (("** Adding set differences phase. **\n")) ;
+
+ /* for each column in pivot row */
+ rp = &A [pivot_row_start] ;
+ rp_end = rp + pivot_row_length ;
+ while (rp < rp_end)
+ {
+ /* get a column */
+ col = *rp++ ;
+ ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+ hash = 0 ;
+ cur_score = 0 ;
+ cp = &A [Col [col].start] ;
+ /* compact the column */
+ new_cp = cp ;
+ cp_end = cp + Col [col].length ;
+
+ DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
+
+ while (cp < cp_end)
+ {
+ /* get a row */
+ row = *cp++ ;
+ ASSERT(row >= 0 && row < n_row) ;
+ row_mark = Row [row].shared2.mark ;
+ /* skip if dead */
+ if (ROW_IS_MARKED_DEAD (row_mark))
+ {
+ DEBUG4 ((" Row %d, dead\n", row)) ;
+ continue ;
+ }
+ DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark));
+ ASSERT (row_mark >= tag_mark) ;
+ /* compact the column */
+ *new_cp++ = row ;
+ /* compute hash function */
+ hash += row ;
+ /* add set difference */
+ cur_score += row_mark - tag_mark ;
+ /* integer overflow... */
+ cur_score = MIN (cur_score, n_col) ;
+ }
+
+ /* recompute the column's length */
+ Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
+
+ /* === Further mass elimination ================================= */
+
+ if (Col [col].length == 0)
+ {
+ DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
+ /* nothing left but the pivot row in this column */
+ KILL_PRINCIPAL_COL (col) ;
+ pivot_row_degree -= Col [col].shared1.thickness ;
+ ASSERT (pivot_row_degree >= 0) ;
+ /* order it */
+ Col [col].shared2.order = k ;
+ /* increment order count by column thickness */
+ k += Col [col].shared1.thickness ;
+ }
+ else
+ {
+ /* === Prepare for supercolumn detection ==================== */
+
+ DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
+
+ /* save score so far */
+ Col [col].shared2.score = cur_score ;
+
+ /* add column to hash table, for supercolumn detection */
+ hash %= n_col + 1 ;
+
+ DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
+ ASSERT (((Int) hash) <= n_col) ;
+
+ head_column = head [hash] ;
+ if (head_column > EMPTY)
+ {
+ /* degree list "hash" is non-empty, use prev (shared3) of */
+ /* first column in degree list as head of hash bucket */
+ first_col = Col [head_column].shared3.headhash ;
+ Col [head_column].shared3.headhash = col ;
+ }
+ else
+ {
+ /* degree list "hash" is empty, use head as hash bucket */
+ first_col = - (head_column + 2) ;
+ head [hash] = - (col + 2) ;
+ }
+ Col [col].shared4.hash_next = first_col ;
+
+ /* save hash function in Col [col].shared3.hash */
+ Col [col].shared3.hash = (Int) hash ;
+ ASSERT (COL_IS_ALIVE (col)) ;
+ }
+ }
+
+ /* The approximate external column degree is now computed. */
+
+ /* === Supercolumn detection ======================================== */
+
+ DEBUG3 (("** Supercolumn detection phase. **\n")) ;
+
+ detect_super_cols (
+
+#ifndef NDEBUG
+ n_col, Row,
+#endif /* NDEBUG */
+
+ Col, A, head, pivot_row_start, pivot_row_length) ;
+
+ /* === Kill the pivotal column ====================================== */
+
+ KILL_PRINCIPAL_COL (pivot_col) ;
+
+ /* === Clear mark =================================================== */
+
+ tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ;
+
+#ifndef NDEBUG
+ DEBUG3 (("check3\n")) ;
+ debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+ /* === Finalize the new pivot row, and column scores ================ */
+
+ DEBUG3 (("** Finalize scores phase. **\n")) ;
+
+ /* for each column in pivot row */
+ rp = &A [pivot_row_start] ;
+ /* compact the pivot row */
+ new_rp = rp ;
+ rp_end = rp + pivot_row_length ;
+ while (rp < rp_end)
+ {
+ col = *rp++ ;
+ /* skip dead columns */
+ if (COL_IS_DEAD (col))
+ {
+ continue ;
+ }
+ *new_rp++ = col ;
+ /* add new pivot row to column */
+ A [Col [col].start + (Col [col].length++)] = pivot_row ;
+
+ /* retrieve score so far and add on pivot row's degree. */
+ /* (we wait until here for this in case the pivot */
+ /* row's degree was reduced due to mass elimination). */
+ cur_score = Col [col].shared2.score + pivot_row_degree ;
+
+ /* calculate the max possible score as the number of */
+ /* external columns minus the 'k' value minus the */
+ /* columns thickness */
+ max_score = n_col - k - Col [col].shared1.thickness ;
+
+ /* make the score the external degree of the union-of-rows */
+ cur_score -= Col [col].shared1.thickness ;
+
+ /* make sure score is less or equal than the max score */
+ cur_score = MIN (cur_score, max_score) ;
+ ASSERT (cur_score >= 0) ;
+
+ /* store updated score */
+ Col [col].shared2.score = cur_score ;
+
+ /* === Place column back in degree list ========================= */
+
+ ASSERT (min_score >= 0) ;
+ ASSERT (min_score <= n_col) ;
+ ASSERT (cur_score >= 0) ;
+ ASSERT (cur_score <= n_col) ;
+ ASSERT (head [cur_score] >= EMPTY) ;
+ next_col = head [cur_score] ;
+ Col [col].shared4.degree_next = next_col ;
+ Col [col].shared3.prev = EMPTY ;
+ if (next_col != EMPTY)
+ {
+ Col [next_col].shared3.prev = col ;
+ }
+ head [cur_score] = col ;
+
+ /* see if this score is less than current min */
+ min_score = MIN (min_score, cur_score) ;
+
+ }
+
+#ifndef NDEBUG
+ debug_deg_lists (n_row, n_col, Row, Col, head,
+ min_score, n_col2-k, max_deg) ;
+#endif /* NDEBUG */
+
+ /* === Resurrect the new pivot row ================================== */
+
+ if (pivot_row_degree > 0)
+ {
+ /* update pivot row length to reflect any cols that were killed */
+ /* during super-col detection and mass elimination */
+ Row [pivot_row].start = pivot_row_start ;
+ Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
+ ASSERT (Row [pivot_row].length > 0) ;
+ Row [pivot_row].shared1.degree = pivot_row_degree ;
+ Row [pivot_row].shared2.mark = 0 ;
+ /* pivot row is no longer dead */
+
+ DEBUG1 (("Resurrect Pivot_row %d deg: %d\n",
+ pivot_row, pivot_row_degree)) ;
+ }
+ }
+
+ /* === All principal columns have now been ordered ====================== */
+
+ return (ngarbage) ;
+}
+
+
+/* ========================================================================== */
+/* === order_children ======================================================= */
+/* ========================================================================== */
+
+/*
+ The find_ordering routine has ordered all of the principal columns (the
+ representatives of the supercolumns). The non-principal columns have not
+ yet been ordered. This routine orders those columns by walking up the
+ parent tree (a column is a child of the column which absorbed it). The
+ final permutation vector is then placed in p [0 ... n_col-1], with p [0]
+ being the first column, and p [n_col-1] being the last. It doesn't look
+ like it at first glance, but be assured that this routine takes time linear
+ in the number of columns. Although not immediately obvious, the time
+ taken by this routine is O (n_col), that is, linear in the number of
+ columns. Not user-callable.
+*/
+
+PRIVATE void order_children
+(
+ /* === Parameters ======================================================= */
+
+ Int n_col, /* number of columns of A */
+ Colamd_Col Col [], /* of size n_col+1 */
+ Int p [] /* p [0 ... n_col-1] is the column permutation*/
+)
+{
+ /* === Local variables ================================================== */
+
+ Int i ; /* loop counter for all columns */
+ Int c ; /* column index */
+ Int parent ; /* index of column's parent */
+ Int order ; /* column's order */
+
+ /* === Order each non-principal column ================================== */
+
+ for (i = 0 ; i < n_col ; i++)
+ {
+ /* find an un-ordered non-principal column */
+ ASSERT (COL_IS_DEAD (i)) ;
+ if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY)
+ {
+ parent = i ;
+ /* once found, find its principal parent */
+ do
+ {
+ parent = Col [parent].shared1.parent ;
+ } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
+
+ /* now, order all un-ordered non-principal columns along path */
+ /* to this parent. collapse tree at the same time */
+ c = i ;
+ /* get order of parent */
+ order = Col [parent].shared2.order ;
+
+ do
+ {
+ ASSERT (Col [c].shared2.order == EMPTY) ;
+
+ /* order this column */
+ Col [c].shared2.order = order++ ;
+ /* collaps tree */
+ Col [c].shared1.parent = parent ;
+
+ /* get immediate parent of this column */
+ c = Col [c].shared1.parent ;
+
+ /* continue until we hit an ordered column. There are */
+ /* guarranteed not to be anymore unordered columns */
+ /* above an ordered column */
+ } while (Col [c].shared2.order == EMPTY) ;
+
+ /* re-order the super_col parent to largest order for this group */
+ Col [parent].shared2.order = order ;
+ }
+ }
+
+ /* === Generate the permutation ========================================= */
+
+ for (c = 0 ; c < n_col ; c++)
+ {
+ p [Col [c].shared2.order] = c ;
+ }
+}
+
+
+/* ========================================================================== */
+/* === detect_super_cols ==================================================== */
+/* ========================================================================== */
+
+/*
+ Detects supercolumns by finding matches between columns in the hash buckets.
+ Check amongst columns in the set A [row_start ... row_start + row_length-1].
+ The columns under consideration are currently *not* in the degree lists,
+ and have already been placed in the hash buckets.
+
+ The hash bucket for columns whose hash function is equal to h is stored
+ as follows:
+
+ if head [h] is >= 0, then head [h] contains a degree list, so:
+
+ head [h] is the first column in degree bucket h.
+ Col [head [h]].headhash gives the first column in hash bucket h.
+
+ otherwise, the degree list is empty, and:
+
+ -(head [h] + 2) is the first column in hash bucket h.
+
+ For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
+ column" pointer. Col [c].shared3.hash is used instead as the hash number
+ for that column. The value of Col [c].shared4.hash_next is the next column
+ in the same hash bucket.
+
+ Assuming no, or "few" hash collisions, the time taken by this routine is
+ linear in the sum of the sizes (lengths) of each column whose score has
+ just been computed in the approximate degree computation.
+ Not user-callable.
+*/
+
+PRIVATE void detect_super_cols
+(
+ /* === Parameters ======================================================= */
+
+#ifndef NDEBUG
+ /* these two parameters are only needed when debugging is enabled: */
+ Int n_col, /* number of columns of A */
+ Colamd_Row Row [], /* of size n_row+1 */
+#endif /* NDEBUG */
+
+ Colamd_Col Col [], /* of size n_col+1 */
+ Int A [], /* row indices of A */
+ Int head [], /* head of degree lists and hash buckets */
+ Int row_start, /* pointer to set of columns to check */
+ Int row_length /* number of columns to check */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int hash ; /* hash value for a column */
+ Int *rp ; /* pointer to a row */
+ Int c ; /* a column index */
+ Int super_c ; /* column index of the column to absorb into */
+ Int *cp1 ; /* column pointer for column super_c */
+ Int *cp2 ; /* column pointer for column c */
+ Int length ; /* length of column super_c */
+ Int prev_c ; /* column preceding c in hash bucket */
+ Int i ; /* loop counter */
+ Int *rp_end ; /* pointer to the end of the row */
+ Int col ; /* a column index in the row to check */
+ Int head_column ; /* first column in hash bucket or degree list */
+ Int first_col ; /* first column in hash bucket */
+
+ /* === Consider each column in the row ================================== */
+
+ rp = &A [row_start] ;
+ rp_end = rp + row_length ;
+ while (rp < rp_end)
+ {
+ col = *rp++ ;
+ if (COL_IS_DEAD (col))
+ {
+ continue ;
+ }
+
+ /* get hash number for this column */
+ hash = Col [col].shared3.hash ;
+ ASSERT (hash <= n_col) ;
+
+ /* === Get the first column in this hash bucket ===================== */
+
+ head_column = head [hash] ;
+ if (head_column > EMPTY)
+ {
+ first_col = Col [head_column].shared3.headhash ;
+ }
+ else
+ {
+ first_col = - (head_column + 2) ;
+ }
+
+ /* === Consider each column in the hash bucket ====================== */
+
+ for (super_c = first_col ; super_c != EMPTY ;
+ super_c = Col [super_c].shared4.hash_next)
+ {
+ ASSERT (COL_IS_ALIVE (super_c)) ;
+ ASSERT (Col [super_c].shared3.hash == hash) ;
+ length = Col [super_c].length ;
+
+ /* prev_c is the column preceding column c in the hash bucket */
+ prev_c = super_c ;
+
+ /* === Compare super_c with all columns after it ================ */
+
+ for (c = Col [super_c].shared4.hash_next ;
+ c != EMPTY ; c = Col [c].shared4.hash_next)
+ {
+ ASSERT (c != super_c) ;
+ ASSERT (COL_IS_ALIVE (c)) ;
+ ASSERT (Col [c].shared3.hash == hash) ;
+
+ /* not identical if lengths or scores are different */
+ if (Col [c].length != length ||
+ Col [c].shared2.score != Col [super_c].shared2.score)
+ {
+ prev_c = c ;
+ continue ;
+ }
+
+ /* compare the two columns */
+ cp1 = &A [Col [super_c].start] ;
+ cp2 = &A [Col [c].start] ;
+
+ for (i = 0 ; i < length ; i++)
+ {
+ /* the columns are "clean" (no dead rows) */
+ ASSERT (ROW_IS_ALIVE (*cp1)) ;
+ ASSERT (ROW_IS_ALIVE (*cp2)) ;
+ /* row indices will same order for both supercols, */
+ /* no gather scatter nessasary */
+ if (*cp1++ != *cp2++)
+ {
+ break ;
+ }
+ }
+
+ /* the two columns are different if the for-loop "broke" */
+ if (i != length)
+ {
+ prev_c = c ;
+ continue ;
+ }
+
+ /* === Got it! two columns are identical =================== */
+
+ ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
+
+ Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
+ Col [c].shared1.parent = super_c ;
+ KILL_NON_PRINCIPAL_COL (c) ;
+ /* order c later, in order_children() */
+ Col [c].shared2.order = EMPTY ;
+ /* remove c from hash bucket */
+ Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
+ }
+ }
+
+ /* === Empty this hash bucket ======================================= */
+
+ if (head_column > EMPTY)
+ {
+ /* corresponding degree list "hash" is not empty */
+ Col [head_column].shared3.headhash = EMPTY ;
+ }
+ else
+ {
+ /* corresponding degree list "hash" is empty */
+ head [hash] = EMPTY ;
+ }
+ }
+}
+
+
+/* ========================================================================== */
+/* === garbage_collection =================================================== */
+/* ========================================================================== */
+
+/*
+ Defragments and compacts columns and rows in the workspace A. Used when
+ all avaliable memory has been used while performing row merging. Returns
+ the index of the first free position in A, after garbage collection. The
+ time taken by this routine is linear is the size of the array A, which is
+ itself linear in the number of nonzeros in the input matrix.
+ Not user-callable.
+*/
+
+PRIVATE Int garbage_collection /* returns the new value of pfree */
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row, /* number of rows */
+ Int n_col, /* number of columns */
+ Colamd_Row Row [], /* row info */
+ Colamd_Col Col [], /* column info */
+ Int A [], /* A [0 ... Alen-1] holds the matrix */
+ Int *pfree /* &A [0] ... pfree is in use */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int *psrc ; /* source pointer */
+ Int *pdest ; /* destination pointer */
+ Int j ; /* counter */
+ Int r ; /* a row index */
+ Int c ; /* a column index */
+ Int length ; /* length of a row or column */
+
+#ifndef NDEBUG
+ Int debug_rows ;
+ DEBUG2 (("Defrag..\n")) ;
+ for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
+ debug_rows = 0 ;
+#endif /* NDEBUG */
+
+ /* === Defragment the columns =========================================== */
+
+ pdest = &A[0] ;
+ for (c = 0 ; c < n_col ; c++)
+ {
+ if (COL_IS_ALIVE (c))
+ {
+ psrc = &A [Col [c].start] ;
+
+ /* move and compact the column */
+ ASSERT (pdest <= psrc) ;
+ Col [c].start = (Int) (pdest - &A [0]) ;
+ length = Col [c].length ;
+ for (j = 0 ; j < length ; j++)
+ {
+ r = *psrc++ ;
+ if (ROW_IS_ALIVE (r))
+ {
+ *pdest++ = r ;
+ }
+ }
+ Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
+ }
+ }
+
+ /* === Prepare to defragment the rows =================================== */
+
+ for (r = 0 ; r < n_row ; r++)
+ {
+ if (ROW_IS_DEAD (r) || (Row [r].length == 0))
+ {
+ /* This row is already dead, or is of zero length. Cannot compact
+ * a row of zero length, so kill it. NOTE: in the current version,
+ * there are no zero-length live rows. Kill the row (for the first
+ * time, or again) just to be safe. */
+ KILL_ROW (r) ;
+ }
+ else
+ {
+ /* save first column index in Row [r].shared2.first_column */
+ psrc = &A [Row [r].start] ;
+ Row [r].shared2.first_column = *psrc ;
+ ASSERT (ROW_IS_ALIVE (r)) ;
+ /* flag the start of the row with the one's complement of row */
+ *psrc = ONES_COMPLEMENT (r) ;
+#ifndef NDEBUG
+ debug_rows++ ;
+#endif /* NDEBUG */
+ }
+ }
+
+ /* === Defragment the rows ============================================== */
+
+ psrc = pdest ;
+ while (psrc < pfree)
+ {
+ /* find a negative number ... the start of a row */
+ if (*psrc++ < 0)
+ {
+ psrc-- ;
+ /* get the row index */
+ r = ONES_COMPLEMENT (*psrc) ;
+ ASSERT (r >= 0 && r < n_row) ;
+ /* restore first column index */
+ *psrc = Row [r].shared2.first_column ;
+ ASSERT (ROW_IS_ALIVE (r)) ;
+ ASSERT (Row [r].length > 0) ;
+ /* move and compact the row */
+ ASSERT (pdest <= psrc) ;
+ Row [r].start = (Int) (pdest - &A [0]) ;
+ length = Row [r].length ;
+ for (j = 0 ; j < length ; j++)
+ {
+ c = *psrc++ ;
+ if (COL_IS_ALIVE (c))
+ {
+ *pdest++ = c ;
+ }
+ }
+ Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
+ ASSERT (Row [r].length > 0) ;
+#ifndef NDEBUG
+ debug_rows-- ;
+#endif /* NDEBUG */
+ }
+ }
+ /* ensure we found all the rows */
+ ASSERT (debug_rows == 0) ;
+
+ /* === Return the new value of pfree ==================================== */
+
+ return ((Int) (pdest - &A [0])) ;
+}
+
+
+/* ========================================================================== */
+/* === clear_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+ Clears the Row [].shared2.mark array, and returns the new tag_mark.
+ Return value is the new tag_mark. Not user-callable.
+*/
+
+PRIVATE Int clear_mark /* return the new value for tag_mark */
+(
+ /* === Parameters ======================================================= */
+
+ Int tag_mark, /* new value of tag_mark */
+ Int max_mark, /* max allowed value of tag_mark */
+
+ Int n_row, /* number of rows in A */
+ Colamd_Row Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */
+)
+{
+ /* === Local variables ================================================== */
+
+ Int r ;
+
+ if (tag_mark <= 0 || tag_mark >= max_mark)
+ {
+ for (r = 0 ; r < n_row ; r++)
+ {
+ if (ROW_IS_ALIVE (r))
+ {
+ Row [r].shared2.mark = 0 ;
+ }
+ }
+ tag_mark = 1 ;
+ }
+
+ return (tag_mark) ;
+}
+
+
+/* ========================================================================== */
+/* === print_report ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void print_report
+(
+ char *method,
+ Int stats [COLAMD_STATS]
+)
+{
+
+ Int i1, i2, i3 ;
+
+ PRINTF (("\n%s version %d.%d, %s: ", method,
+ COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ;
+
+ if (!stats)
+ {
+ PRINTF (("No statistics available.\n")) ;
+ return ;
+ }
+
+ i1 = stats [COLAMD_INFO1] ;
+ i2 = stats [COLAMD_INFO2] ;
+ i3 = stats [COLAMD_INFO3] ;
+
+ if (stats [COLAMD_STATUS] >= 0)
+ {
+ PRINTF (("OK. ")) ;
+ }
+ else
+ {
+ PRINTF (("ERROR. ")) ;
+ }
+
+ switch (stats [COLAMD_STATUS])
+ {
+
+ case COLAMD_OK_BUT_JUMBLED:
+
+ PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ;
+
+ PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n",
+ method, i3)) ;
+
+ PRINTF(("%s: last seen duplicate or out-of-order row index: %d\n",
+ method, INDEX (i2))) ;
+
+ PRINTF(("%s: last seen in column: %d",
+ method, INDEX (i1))) ;
+
+ /* no break - fall through to next case instead */
+
+ case COLAMD_OK:
+
+ PRINTF(("\n")) ;
+
+ PRINTF(("%s: number of dense or empty rows ignored: %d\n",
+ method, stats [COLAMD_DENSE_ROW])) ;
+
+ PRINTF(("%s: number of dense or empty columns ignored: %d\n",
+ method, stats [COLAMD_DENSE_COL])) ;
+
+ PRINTF(("%s: number of garbage collections performed: %d\n",
+ method, stats [COLAMD_DEFRAG_COUNT])) ;
+ break ;
+
+ case COLAMD_ERROR_A_not_present:
+
+ PRINTF(("Array A (row indices of matrix) not present.\n")) ;
+ break ;
+
+ case COLAMD_ERROR_p_not_present:
+
+ PRINTF(("Array p (column pointers for matrix) not present.\n")) ;
+ break ;
+
+ case COLAMD_ERROR_nrow_negative:
+
+ PRINTF(("Invalid number of rows (%d).\n", i1)) ;
+ break ;
+
+ case COLAMD_ERROR_ncol_negative:
+
+ PRINTF(("Invalid number of columns (%d).\n", i1)) ;
+ break ;
+
+ case COLAMD_ERROR_nnz_negative:
+
+ PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ;
+ break ;
+
+ case COLAMD_ERROR_p0_nonzero:
+
+ PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1));
+ break ;
+
+ case COLAMD_ERROR_A_too_small:
+
+ PRINTF(("Array A too small.\n")) ;
+ PRINTF((" Need Alen >= %d, but given only Alen = %d.\n",
+ i1, i2)) ;
+ break ;
+
+ case COLAMD_ERROR_col_length_negative:
+
+ PRINTF
+ (("Column %d has a negative number of nonzero entries (%d).\n",
+ INDEX (i1), i2)) ;
+ break ;
+
+ case COLAMD_ERROR_row_index_out_of_bounds:
+
+ PRINTF
+ (("Row index (row %d) out of bounds (%d to %d) in column %d.\n",
+ INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ;
+ break ;
+
+ case COLAMD_ERROR_out_of_memory:
+
+ PRINTF(("Out of memory.\n")) ;
+ break ;
+
+ /* v2.4: internal-error case deleted */
+ }
+}
+
+
+
+
+/* ========================================================================== */
+/* === colamd debugging routines ============================================ */
+/* ========================================================================== */
+
+/* When debugging is disabled, the remainder of this file is ignored. */
+
+#ifndef NDEBUG
+
+
+/* ========================================================================== */
+/* === debug_structures ===================================================== */
+/* ========================================================================== */
+
+/*
+ At this point, all empty rows and columns are dead. All live columns
+ are "clean" (containing no dead rows) and simplicial (no supercolumns
+ yet). Rows may contain dead columns, but all live rows contain at
+ least one live column.
+*/
+
+PRIVATE void debug_structures
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A [],
+ Int n_col2
+)
+{
+ /* === Local variables ================================================== */
+
+ Int i ;
+ Int c ;
+ Int *cp ;
+ Int *cp_end ;
+ Int len ;
+ Int score ;
+ Int r ;
+ Int *rp ;
+ Int *rp_end ;
+ Int deg ;
+
+ /* === Check A, Row, and Col ============================================ */
+
+ for (c = 0 ; c < n_col ; c++)
+ {
+ if (COL_IS_ALIVE (c))
+ {
+ len = Col [c].length ;
+ score = Col [c].shared2.score ;
+ DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ;
+ ASSERT (len > 0) ;
+ ASSERT (score >= 0) ;
+ ASSERT (Col [c].shared1.thickness == 1) ;
+ cp = &A [Col [c].start] ;
+ cp_end = cp + len ;
+ while (cp < cp_end)
+ {
+ r = *cp++ ;
+ ASSERT (ROW_IS_ALIVE (r)) ;
+ }
+ }
+ else
+ {
+ i = Col [c].shared2.order ;
+ ASSERT (i >= n_col2 && i < n_col) ;
+ }
+ }
+
+ for (r = 0 ; r < n_row ; r++)
+ {
+ if (ROW_IS_ALIVE (r))
+ {
+ i = 0 ;
+ len = Row [r].length ;
+ deg = Row [r].shared1.degree ;
+ ASSERT (len > 0) ;
+ ASSERT (deg > 0) ;
+ rp = &A [Row [r].start] ;
+ rp_end = rp + len ;
+ while (rp < rp_end)
+ {
+ c = *rp++ ;
+ if (COL_IS_ALIVE (c))
+ {
+ i++ ;
+ }
+ }
+ ASSERT (i > 0) ;
+ }
+ }
+}
+
+
+/* ========================================================================== */
+/* === debug_deg_lists ====================================================== */
+/* ========================================================================== */
+
+/*
+ Prints the contents of the degree lists. Counts the number of columns
+ in the degree list and compares it to the total it should have. Also
+ checks the row degrees.
+*/
+
+PRIVATE void debug_deg_lists
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int head [],
+ Int min_score,
+ Int should,
+ Int max_deg
+)
+{
+ /* === Local variables ================================================== */
+
+ Int deg ;
+ Int col ;
+ Int have ;
+ Int row ;
+
+ /* === Check the degree lists =========================================== */
+
+ if (n_col > 10000 && colamd_debug <= 0)
+ {
+ return ;
+ }
+ have = 0 ;
+ DEBUG4 (("Degree lists: %d\n", min_score)) ;
+ for (deg = 0 ; deg <= n_col ; deg++)
+ {
+ col = head [deg] ;
+ if (col == EMPTY)
+ {
+ continue ;
+ }
+ DEBUG4 (("%d:", deg)) ;
+ while (col != EMPTY)
+ {
+ DEBUG4 ((" %d", col)) ;
+ have += Col [col].shared1.thickness ;
+ ASSERT (COL_IS_ALIVE (col)) ;
+ col = Col [col].shared4.degree_next ;
+ }
+ DEBUG4 (("\n")) ;
+ }
+ DEBUG4 (("should %d have %d\n", should, have)) ;
+ ASSERT (should == have) ;
+
+ /* === Check the row degrees ============================================ */
+
+ if (n_row > 10000 && colamd_debug <= 0)
+ {
+ return ;
+ }
+ for (row = 0 ; row < n_row ; row++)
+ {
+ if (ROW_IS_ALIVE (row))
+ {
+ ASSERT (Row [row].shared1.degree <= max_deg) ;
+ }
+ }
+}
+
+
+/* ========================================================================== */
+/* === debug_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+ Ensures that the tag_mark is less that the maximum and also ensures that
+ each entry in the mark array is less than the tag mark.
+*/
+
+PRIVATE void debug_mark
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row,
+ Colamd_Row Row [],
+ Int tag_mark,
+ Int max_mark
+)
+{
+ /* === Local variables ================================================== */
+
+ Int r ;
+
+ /* === Check the Row marks ============================================== */
+
+ ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
+ if (n_row > 10000 && colamd_debug <= 0)
+ {
+ return ;
+ }
+ for (r = 0 ; r < n_row ; r++)
+ {
+ ASSERT (Row [r].shared2.mark < tag_mark) ;
+ }
+}
+
+
+/* ========================================================================== */
+/* === debug_matrix ========================================================= */
+/* ========================================================================== */
+
+/*
+ Prints out the contents of the columns and the rows.
+*/
+
+PRIVATE void debug_matrix
+(
+ /* === Parameters ======================================================= */
+
+ Int n_row,
+ Int n_col,
+ Colamd_Row Row [],
+ Colamd_Col Col [],
+ Int A []
+)
+{
+ /* === Local variables ================================================== */
+
+ Int r ;
+ Int c ;
+ Int *rp ;
+ Int *rp_end ;
+ Int *cp ;
+ Int *cp_end ;
+
+ /* === Dump the rows and columns of the matrix ========================== */
+
+ if (colamd_debug < 3)
+ {
+ return ;
+ }
+ DEBUG3 (("DUMP MATRIX:\n")) ;
+ for (r = 0 ; r < n_row ; r++)
+ {
+ DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ;
+ if (ROW_IS_DEAD (r))
+ {
+ continue ;
+ }
+ DEBUG3 (("start %d length %d degree %d\n",
+ Row [r].start, Row [r].length, Row [r].shared1.degree)) ;
+ rp = &A [Row [r].start] ;
+ rp_end = rp + Row [r].length ;
+ while (rp < rp_end)
+ {
+ c = *rp++ ;
+ DEBUG4 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ;
+ }
+ }
+
+ for (c = 0 ; c < n_col ; c++)
+ {
+ DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ;
+ if (COL_IS_DEAD (c))
+ {
+ continue ;
+ }
+ DEBUG3 (("start %d length %d shared1 %d shared2 %d\n",
+ Col [c].start, Col [c].length,
+ Col [c].shared1.thickness, Col [c].shared2.score)) ;
+ cp = &A [Col [c].start] ;
+ cp_end = cp + Col [c].length ;
+ while (cp < cp_end)
+ {
+ r = *cp++ ;
+ DEBUG4 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ;
+ }
+ }
+}
+
+PRIVATE void colamd_get_debug
+(
+ char *method
+)
+{
+ FILE *f ;
+ colamd_debug = 0 ; /* no debug printing */
+ f = fopen ("debug", "r") ;
+ if (f == (FILE *) NULL)
+ {
+ colamd_debug = 0 ;
+ }
+ else
+ {
+ fscanf (f, "%d", &colamd_debug) ;
+ fclose (f) ;
+ }
+ DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n",
+ method, colamd_debug)) ;
+}
+
+#endif /* NDEBUG */
diff --git a/test/monniaux/glpk-4.65/src/colamd/colamd.h b/test/monniaux/glpk-4.65/src/colamd/colamd.h
new file mode 100644
index 00000000..511735e5
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/colamd/colamd.h
@@ -0,0 +1,69 @@
+/* colamd.h */
+
+/* Written by Andrew Makhorin <mao@gnu.org>. */
+
+#ifndef COLAMD_H
+#define COLAMD_H
+
+#define _GLPSTD_STDIO
+#include "env.h"
+
+#define COLAMD_DATE "Nov 1, 2007"
+#define COLAMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub))
+#define COLAMD_MAIN_VERSION 2
+#define COLAMD_SUB_VERSION 7
+#define COLAMD_SUBSUB_VERSION 1
+#define COLAMD_VERSION \
+ COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION)
+
+#define COLAMD_KNOBS 20
+#define COLAMD_STATS 20
+#define COLAMD_DENSE_ROW 0
+#define COLAMD_DENSE_COL 1
+#define COLAMD_AGGRESSIVE 2
+#define COLAMD_DEFRAG_COUNT 2
+#define COLAMD_STATUS 3
+#define COLAMD_INFO1 4
+#define COLAMD_INFO2 5
+#define COLAMD_INFO3 6
+
+#define COLAMD_OK (0)
+#define COLAMD_OK_BUT_JUMBLED (1)
+#define COLAMD_ERROR_A_not_present (-1)
+#define COLAMD_ERROR_p_not_present (-2)
+#define COLAMD_ERROR_nrow_negative (-3)
+#define COLAMD_ERROR_ncol_negative (-4)
+#define COLAMD_ERROR_nnz_negative (-5)
+#define COLAMD_ERROR_p0_nonzero (-6)
+#define COLAMD_ERROR_A_too_small (-7)
+#define COLAMD_ERROR_col_length_negative (-8)
+#define COLAMD_ERROR_row_index_out_of_bounds (-9)
+#define COLAMD_ERROR_out_of_memory (-10)
+#define COLAMD_ERROR_internal_error (-999)
+
+#define colamd_recommended _glp_colamd_recommended
+size_t colamd_recommended(int nnz, int n_row, int n_col);
+
+#define colamd_set_defaults _glp_colamd_set_defaults
+void colamd_set_defaults(double knobs [COLAMD_KNOBS]);
+
+#define colamd _glp_colamd
+int colamd(int n_row, int n_col, int Alen, int A[], int p[],
+ double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS]);
+
+#define symamd _glp_symamd
+int symamd(int n, int A[], int p[], int perm[],
+ double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS],
+ void *(*allocate)(size_t, size_t), void(*release)(void *));
+
+#define colamd_report _glp_colamd_report
+void colamd_report(int stats[COLAMD_STATS]);
+
+#define symamd_report _glp_symamd_report
+void symamd_report(int stats[COLAMD_STATS]);
+
+#define colamd_printf xprintf
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/bfd.c b/test/monniaux/glpk-4.65/src/draft/bfd.c
new file mode 100644
index 00000000..dece376c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/bfd.c
@@ -0,0 +1,544 @@
+/* bfd.c (LP basis factorization driver) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2007, 2014 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/>.
+***********************************************************************/
+
+#include "glpk.h"
+#include "env.h"
+#include "bfd.h"
+#include "fhvint.h"
+#include "scfint.h"
+#ifdef GLP_DEBUG
+#include "glpspm.h"
+#endif
+
+struct BFD
+{ /* LP basis factorization driver */
+ int valid;
+ /* factorization is valid only if this flag is set */
+ int type;
+ /* type of factorization used:
+ 0 - interface not established yet
+ 1 - FHV-factorization
+ 2 - Schur-complement-based factorization */
+ union
+ { void *none; /* type = 0 */
+ FHVINT *fhvi; /* type = 1 */
+ SCFINT *scfi; /* type = 2 */
+ } u;
+ /* interface to factorization of LP basis */
+ glp_bfcp parm;
+ /* factorization control parameters */
+#ifdef GLP_DEBUG
+ SPM *B;
+ /* current basis (for testing/debugging only) */
+#endif
+ int upd_cnt;
+ /* factorization update count */
+#if 1 /* 21/IV-2014 */
+ double b_norm;
+ /* 1-norm of matrix B */
+ double i_norm;
+ /* estimated 1-norm of matrix inv(B) */
+#endif
+};
+
+BFD *bfd_create_it(void)
+{ /* create LP basis factorization */
+ BFD *bfd;
+#ifdef GLP_DEBUG
+ xprintf("bfd_create_it: warning: debugging version used\n");
+#endif
+ bfd = talloc(1, BFD);
+ bfd->valid = 0;
+ bfd->type = 0;
+ bfd->u.none = NULL;
+ bfd_set_bfcp(bfd, NULL);
+#ifdef GLP_DEBUG
+ bfd->B = NULL;
+#endif
+ bfd->upd_cnt = 0;
+ return bfd;
+}
+
+#if 0 /* 08/III-2014 */
+void bfd_set_parm(BFD *bfd, const void *parm)
+{ /* change LP basis factorization control parameters */
+ memcpy(&bfd->parm, parm, sizeof(glp_bfcp));
+ return;
+}
+#endif
+
+void bfd_get_bfcp(BFD *bfd, void /* glp_bfcp */ *parm)
+{ /* retrieve LP basis factorization control parameters */
+ memcpy(parm, &bfd->parm, sizeof(glp_bfcp));
+ return;
+}
+
+void bfd_set_bfcp(BFD *bfd, const void /* glp_bfcp */ *parm)
+{ /* change LP basis factorization control parameters */
+ if (parm == NULL)
+ { /* reset to default */
+ memset(&bfd->parm, 0, sizeof(glp_bfcp));
+ bfd->parm.type = GLP_BF_LUF + GLP_BF_FT;
+ bfd->parm.piv_tol = 0.10;
+ bfd->parm.piv_lim = 4;
+ bfd->parm.suhl = 1;
+ bfd->parm.eps_tol = DBL_EPSILON;
+ bfd->parm.nfs_max = 100;
+ bfd->parm.nrs_max = 70;
+ }
+ else
+ memcpy(&bfd->parm, parm, sizeof(glp_bfcp));
+ return;
+}
+
+#if 1 /* 21/IV-2014 */
+struct bfd_info
+{ BFD *bfd;
+ int (*col)(void *info, int j, int ind[], double val[]);
+ void *info;
+};
+
+static int bfd_col(void *info_, int j, int ind[], double val[])
+{ struct bfd_info *info = info_;
+ int t, len;
+ double sum;
+ len = info->col(info->info, j, ind, val);
+ sum = 0.0;
+ for (t = 1; t <= len; t++)
+ { if (val[t] >= 0.0)
+ sum += val[t];
+ else
+ sum -= val[t];
+ }
+ if (info->bfd->b_norm < sum)
+ info->bfd->b_norm = sum;
+ return len;
+}
+#endif
+
+int bfd_factorize(BFD *bfd, int m, /*const int bh[],*/ int (*col1)
+ (void *info, int j, int ind[], double val[]), void *info1)
+{ /* compute LP basis factorization */
+#if 1 /* 21/IV-2014 */
+ struct bfd_info info;
+#endif
+ int type, ret;
+ /*xassert(bh == bh);*/
+ /* invalidate current factorization */
+ bfd->valid = 0;
+ /* determine required factorization type */
+ switch (bfd->parm.type)
+ { case GLP_BF_LUF + GLP_BF_FT:
+ type = 1;
+ break;
+ case GLP_BF_LUF + GLP_BF_BG:
+ case GLP_BF_LUF + GLP_BF_GR:
+ case GLP_BF_BTF + GLP_BF_BG:
+ case GLP_BF_BTF + GLP_BF_GR:
+ type = 2;
+ break;
+ default:
+ xassert(bfd != bfd);
+ }
+ /* delete factorization interface, if necessary */
+ switch (bfd->type)
+ { case 0:
+ break;
+ case 1:
+ if (type != 1)
+ { bfd->type = 0;
+ fhvint_delete(bfd->u.fhvi);
+ bfd->u.fhvi = NULL;
+ }
+ break;
+ case 2:
+ if (type != 2)
+ { bfd->type = 0;
+ scfint_delete(bfd->u.scfi);
+ bfd->u.scfi = NULL;
+ }
+ break;
+ default:
+ xassert(bfd != bfd);
+ }
+ /* establish factorization interface, if necessary */
+ if (bfd->type == 0)
+ { switch (type)
+ { case 1:
+ bfd->type = 1;
+ xassert(bfd->u.fhvi == NULL);
+ bfd->u.fhvi = fhvint_create();
+ break;
+ case 2:
+ bfd->type = 2;
+ xassert(bfd->u.scfi == NULL);
+ if (!(bfd->parm.type & GLP_BF_BTF))
+ bfd->u.scfi = scfint_create(1);
+ else
+ bfd->u.scfi = scfint_create(2);
+ break;
+ default:
+ xassert(type != type);
+ }
+ }
+ /* try to compute factorization */
+#if 1 /* 21/IV-2014 */
+ bfd->b_norm = bfd->i_norm = 0.0;
+ info.bfd = bfd;
+ info.col = col1;
+ info.info = info1;
+#endif
+ switch (bfd->type)
+ { case 1:
+ bfd->u.fhvi->lufi->sgf_piv_tol = bfd->parm.piv_tol;
+ bfd->u.fhvi->lufi->sgf_piv_lim = bfd->parm.piv_lim;
+ bfd->u.fhvi->lufi->sgf_suhl = bfd->parm.suhl;
+ bfd->u.fhvi->lufi->sgf_eps_tol = bfd->parm.eps_tol;
+ bfd->u.fhvi->nfs_max = bfd->parm.nfs_max;
+ ret = fhvint_factorize(bfd->u.fhvi, m, bfd_col, &info);
+#if 1 /* FIXME */
+ if (ret == 0)
+ bfd->i_norm = fhvint_estimate(bfd->u.fhvi);
+ else
+ ret = BFD_ESING;
+#endif
+ break;
+ case 2:
+ if (bfd->u.scfi->scf.type == 1)
+ { bfd->u.scfi->u.lufi->sgf_piv_tol = bfd->parm.piv_tol;
+ bfd->u.scfi->u.lufi->sgf_piv_lim = bfd->parm.piv_lim;
+ bfd->u.scfi->u.lufi->sgf_suhl = bfd->parm.suhl;
+ bfd->u.scfi->u.lufi->sgf_eps_tol = bfd->parm.eps_tol;
+ }
+ else if (bfd->u.scfi->scf.type == 2)
+ { bfd->u.scfi->u.btfi->sgf_piv_tol = bfd->parm.piv_tol;
+ bfd->u.scfi->u.btfi->sgf_piv_lim = bfd->parm.piv_lim;
+ bfd->u.scfi->u.btfi->sgf_suhl = bfd->parm.suhl;
+ bfd->u.scfi->u.btfi->sgf_eps_tol = bfd->parm.eps_tol;
+ }
+ else
+ xassert(bfd != bfd);
+ bfd->u.scfi->nn_max = bfd->parm.nrs_max;
+ ret = scfint_factorize(bfd->u.scfi, m, bfd_col, &info);
+#if 1 /* FIXME */
+ if (ret == 0)
+ bfd->i_norm = scfint_estimate(bfd->u.scfi);
+ else
+ ret = BFD_ESING;
+#endif
+ break;
+ default:
+ xassert(bfd != bfd);
+ }
+#ifdef GLP_DEBUG
+ /* save specified LP basis */
+ if (bfd->B != NULL)
+ spm_delete_mat(bfd->B);
+ bfd->B = spm_create_mat(m, m);
+ { int *ind = talloc(1+m, int);
+ double *val = talloc(1+m, double);
+ int j, k, len;
+ for (j = 1; j <= m; j++)
+ { len = col(info, j, ind, val);
+ for (k = 1; k <= len; k++)
+ spm_new_elem(bfd->B, ind[k], j, val[k]);
+ }
+ tfree(ind);
+ tfree(val);
+ }
+#endif
+ if (ret == 0)
+ { /* factorization has been successfully computed */
+ double cond;
+ bfd->valid = 1;
+#ifdef GLP_DEBUG
+ cond = bfd_condest(bfd);
+ if (cond > 1e9)
+ xprintf("bfd_factorize: warning: cond(B) = %g\n", cond);
+#endif
+ }
+#ifdef GLP_DEBUG
+ xprintf("bfd_factorize: m = %d; ret = %d\n", m, ret);
+#endif
+ bfd->upd_cnt = 0;
+ return ret;
+}
+
+#if 0 /* 21/IV-2014 */
+double bfd_estimate(BFD *bfd)
+{ /* estimate 1-norm of inv(B) */
+ double norm;
+ xassert(bfd->valid);
+ xassert(bfd->upd_cnt == 0);
+ switch (bfd->type)
+ { case 1:
+ norm = fhvint_estimate(bfd->u.fhvi);
+ break;
+ case 2:
+ norm = scfint_estimate(bfd->u.scfi);
+ break;
+ default:
+ xassert(bfd != bfd);
+ }
+ return norm;
+}
+#endif
+
+#if 1 /* 21/IV-2014 */
+double bfd_condest(BFD *bfd)
+{ /* estimate condition of B */
+ double cond;
+ xassert(bfd->valid);
+ /*xassert(bfd->upd_cnt == 0);*/
+ cond = bfd->b_norm * bfd->i_norm;
+ if (cond < 1.0)
+ cond = 1.0;
+ return cond;
+}
+#endif
+
+void bfd_ftran(BFD *bfd, double x[])
+{ /* perform forward transformation (solve system B * x = b) */
+#ifdef GLP_DEBUG
+ SPM *B = bfd->B;
+ int m = B->m;
+ double *b = talloc(1+m, double);
+ SPME *e;
+ int k;
+ double s, relerr, maxerr;
+ for (k = 1; k <= m; k++)
+ b[k] = x[k];
+#endif
+ xassert(bfd->valid);
+ switch (bfd->type)
+ { case 1:
+ fhvint_ftran(bfd->u.fhvi, x);
+ break;
+ case 2:
+ scfint_ftran(bfd->u.scfi, x);
+ break;
+ default:
+ xassert(bfd != bfd);
+ }
+#ifdef GLP_DEBUG
+ maxerr = 0.0;
+ for (k = 1; k <= m; k++)
+ { s = 0.0;
+ for (e = B->row[k]; e != NULL; e = e->r_next)
+ s += e->val * x[e->j];
+ relerr = (b[k] - s) / (1.0 + fabs(b[k]));
+ if (maxerr < relerr)
+ maxerr = relerr;
+ }
+ if (maxerr > 1e-8)
+ xprintf("bfd_ftran: maxerr = %g; relative error too large\n",
+ maxerr);
+ tfree(b);
+#endif
+ return;
+}
+
+#if 1 /* 30/III-2016 */
+void bfd_ftran_s(BFD *bfd, FVS *x)
+{ /* sparse version of bfd_ftran */
+ /* (sparse mode is not implemented yet) */
+ int n = x->n;
+ int *ind = x->ind;
+ double *vec = x->vec;
+ int j, nnz = 0;
+ bfd_ftran(bfd, vec);
+ for (j = n; j >= 1; j--)
+ { if (vec[j] != 0.0)
+ ind[++nnz] = j;
+ }
+ x->nnz = nnz;
+ return;
+}
+#endif
+
+void bfd_btran(BFD *bfd, double x[])
+{ /* perform backward transformation (solve system B'* x = b) */
+#ifdef GLP_DEBUG
+ SPM *B = bfd->B;
+ int m = B->m;
+ double *b = talloc(1+m, double);
+ SPME *e;
+ int k;
+ double s, relerr, maxerr;
+ for (k = 1; k <= m; k++)
+ b[k] = x[k];
+#endif
+ xassert(bfd->valid);
+ switch (bfd->type)
+ { case 1:
+ fhvint_btran(bfd->u.fhvi, x);
+ break;
+ case 2:
+ scfint_btran(bfd->u.scfi, x);
+ break;
+ default:
+ xassert(bfd != bfd);
+ }
+#ifdef GLP_DEBUG
+ maxerr = 0.0;
+ for (k = 1; k <= m; k++)
+ { s = 0.0;
+ for (e = B->col[k]; e != NULL; e = e->c_next)
+ s += e->val * x[e->i];
+ relerr = (b[k] - s) / (1.0 + fabs(b[k]));
+ if (maxerr < relerr)
+ maxerr = relerr;
+ }
+ if (maxerr > 1e-8)
+ xprintf("bfd_btran: maxerr = %g; relative error too large\n",
+ maxerr);
+ tfree(b);
+#endif
+ return;
+}
+
+#if 1 /* 30/III-2016 */
+void bfd_btran_s(BFD *bfd, FVS *x)
+{ /* sparse version of bfd_btran */
+ /* (sparse mode is not implemented yet) */
+ int n = x->n;
+ int *ind = x->ind;
+ double *vec = x->vec;
+ int j, nnz = 0;
+ bfd_btran(bfd, vec);
+ for (j = n; j >= 1; j--)
+ { if (vec[j] != 0.0)
+ ind[++nnz] = j;
+ }
+ x->nnz = nnz;
+ return;
+}
+#endif
+
+int bfd_update(BFD *bfd, int j, int len, const int ind[], const double
+ val[])
+{ /* update LP basis factorization */
+ int ret;
+ xassert(bfd->valid);
+ switch (bfd->type)
+ { case 1:
+ ret = fhvint_update(bfd->u.fhvi, j, len, ind, val);
+#if 1 /* FIXME */
+ switch (ret)
+ { case 0:
+ break;
+ case 1:
+ ret = BFD_ESING;
+ break;
+ case 2:
+ case 3:
+ ret = BFD_ECOND;
+ break;
+ case 4:
+ ret = BFD_ELIMIT;
+ break;
+ case 5:
+ ret = BFD_ECHECK;
+ break;
+ default:
+ xassert(ret != ret);
+ }
+#endif
+ break;
+ case 2:
+ switch (bfd->parm.type & 0x0F)
+ { case GLP_BF_BG:
+ ret = scfint_update(bfd->u.scfi, 1, j, len, ind, val);
+ break;
+ case GLP_BF_GR:
+ ret = scfint_update(bfd->u.scfi, 2, j, len, ind, val);
+ break;
+ default:
+ xassert(bfd != bfd);
+ }
+#if 1 /* FIXME */
+ switch (ret)
+ { case 0:
+ break;
+ case 1:
+ ret = BFD_ELIMIT;
+ break;
+ case 2:
+ ret = BFD_ECOND;
+ break;
+ default:
+ xassert(ret != ret);
+ }
+#endif
+ break;
+ default:
+ xassert(bfd != bfd);
+ }
+ if (ret != 0)
+ { /* updating factorization failed */
+ bfd->valid = 0;
+ }
+#ifdef GLP_DEBUG
+ /* save updated LP basis */
+ { SPME *e;
+ int k;
+ for (e = bfd->B->col[j]; e != NULL; e = e->c_next)
+ e->val = 0.0;
+ spm_drop_zeros(bfd->B, 0.0);
+ for (k = 1; k <= len; k++)
+ spm_new_elem(bfd->B, ind[k], j, val[k]);
+ }
+#endif
+ if (ret == 0)
+ bfd->upd_cnt++;
+ return ret;
+}
+
+int bfd_get_count(BFD *bfd)
+{ /* determine factorization update count */
+ return bfd->upd_cnt;
+}
+
+void bfd_delete_it(BFD *bfd)
+{ /* delete LP basis factorization */
+ switch (bfd->type)
+ { case 0:
+ break;
+ case 1:
+ fhvint_delete(bfd->u.fhvi);
+ break;
+ case 2:
+ scfint_delete(bfd->u.scfi);
+ break;
+ default:
+ xassert(bfd != bfd);
+ }
+#ifdef GLP_DEBUG
+ if (bfd->B != NULL)
+ spm_delete_mat(bfd->B);
+#endif
+ tfree(bfd);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/bfd.h b/test/monniaux/glpk-4.65/src/draft/bfd.h
new file mode 100644
index 00000000..0ef4c023
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/bfd.h
@@ -0,0 +1,107 @@
+/* bfd.h (LP basis factorization driver) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#ifndef BFD_H
+#define BFD_H
+
+#if 1 /* 30/III-2016 */
+#include "fvs.h"
+#endif
+
+typedef struct BFD BFD;
+
+/* return codes: */
+#define BFD_ESING 1 /* singular matrix */
+#define BFD_ECOND 2 /* ill-conditioned matrix */
+#define BFD_ECHECK 3 /* insufficient accuracy */
+#define BFD_ELIMIT 4 /* update limit reached */
+#if 0 /* 05/III-2014 */
+#define BFD_EROOM 5 /* SVA overflow */
+#endif
+
+#define bfd_create_it _glp_bfd_create_it
+BFD *bfd_create_it(void);
+/* create LP basis factorization */
+
+#if 0 /* 08/III-2014 */
+#define bfd_set_parm _glp_bfd_set_parm
+void bfd_set_parm(BFD *bfd, const void *parm);
+/* change LP basis factorization control parameters */
+#endif
+
+#define bfd_get_bfcp _glp_bfd_get_bfcp
+void bfd_get_bfcp(BFD *bfd, void /* glp_bfcp */ *parm);
+/* retrieve LP basis factorization control parameters */
+
+#define bfd_set_bfcp _glp_bfd_set_bfcp
+void bfd_set_bfcp(BFD *bfd, const void /* glp_bfcp */ *parm);
+/* change LP basis factorization control parameters */
+
+#define bfd_factorize _glp_bfd_factorize
+int bfd_factorize(BFD *bfd, int m, /*const int bh[],*/ int (*col)
+ (void *info, int j, int ind[], double val[]), void *info);
+/* compute LP basis factorization */
+
+#if 1 /* 21/IV-2014 */
+#define bfd_condest _glp_bfd_condest
+double bfd_condest(BFD *bfd);
+/* estimate condition of B */
+#endif
+
+#define bfd_ftran _glp_bfd_ftran
+void bfd_ftran(BFD *bfd, double x[]);
+/* perform forward transformation (solve system B*x = b) */
+
+#if 1 /* 30/III-2016 */
+#define bfd_ftran_s _glp_bfd_ftran_s
+void bfd_ftran_s(BFD *bfd, FVS *x);
+/* sparse version of bfd_ftran */
+#endif
+
+#define bfd_btran _glp_bfd_btran
+void bfd_btran(BFD *bfd, double x[]);
+/* perform backward transformation (solve system B'*x = b) */
+
+#if 1 /* 30/III-2016 */
+#define bfd_btran_s _glp_bfd_btran_s
+void bfd_btran_s(BFD *bfd, FVS *x);
+/* sparse version of bfd_btran */
+#endif
+
+#define bfd_update _glp_bfd_update
+int bfd_update(BFD *bfd, int j, int len, const int ind[], const double
+ val[]);
+/* update LP basis factorization */
+
+#define bfd_get_count _glp_bfd_get_count
+int bfd_get_count(BFD *bfd);
+/* determine factorization update count */
+
+#define bfd_delete_it _glp_bfd_delete_it
+void bfd_delete_it(BFD *bfd);
+/* delete LP basis factorization */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/bfx.c b/test/monniaux/glpk-4.65/src/draft/bfx.c
new file mode 100644
index 00000000..565480b6
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/bfx.c
@@ -0,0 +1,89 @@
+/* bfx.c (LP basis factorization driver, rational arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#include "bfx.h"
+#include "env.h"
+#include "lux.h"
+
+struct BFX
+{ int valid;
+ LUX *lux;
+};
+
+BFX *bfx_create_binv(void)
+{ /* create factorization of the basis matrix */
+ BFX *bfx;
+ bfx = xmalloc(sizeof(BFX));
+ bfx->valid = 0;
+ bfx->lux = NULL;
+ return bfx;
+}
+
+int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j,
+ int ind[], mpq_t val[]), void *info)
+{ /* compute factorization of the basis matrix */
+ int ret;
+ xassert(m > 0);
+ if (binv->lux != NULL && binv->lux->n != m)
+ { lux_delete(binv->lux);
+ binv->lux = NULL;
+ }
+ if (binv->lux == NULL)
+ binv->lux = lux_create(m);
+ ret = lux_decomp(binv->lux, col, info);
+ binv->valid = (ret == 0);
+ return ret;
+}
+
+void bfx_ftran(BFX *binv, mpq_t x[], int save)
+{ /* perform forward transformation (FTRAN) */
+ xassert(binv->valid);
+ lux_solve(binv->lux, 0, x);
+ xassert(save == save);
+ return;
+}
+
+void bfx_btran(BFX *binv, mpq_t x[])
+{ /* perform backward transformation (BTRAN) */
+ xassert(binv->valid);
+ lux_solve(binv->lux, 1, x);
+ return;
+}
+
+int bfx_update(BFX *binv, int j)
+{ /* update factorization of the basis matrix */
+ xassert(binv->valid);
+ xassert(1 <= j && j <= binv->lux->n);
+ return 1;
+}
+
+void bfx_delete_binv(BFX *binv)
+{ /* delete factorization of the basis matrix */
+ if (binv->lux != NULL)
+ lux_delete(binv->lux);
+ xfree(binv);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/bfx.h b/test/monniaux/glpk-4.65/src/draft/bfx.h
new file mode 100644
index 00000000..c67d5ea4
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/bfx.h
@@ -0,0 +1,67 @@
+/* bfx.h (LP basis factorization driver, rational arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#ifndef BFX_H
+#define BFX_H
+
+#include "mygmp.h"
+
+typedef struct BFX BFX;
+
+#define bfx_create_binv _glp_bfx_create_binv
+BFX *bfx_create_binv(void);
+/* create factorization of the basis matrix */
+
+#define bfx_is_valid _glp_bfx_is_valid
+int bfx_is_valid(BFX *binv);
+/* check if factorization is valid */
+
+#define bfx_invalidate _glp_bfx_invalidate
+void bfx_invalidate(BFX *binv);
+/* invalidate factorization of the basis matrix */
+
+#define bfx_factorize _glp_bfx_factorize
+int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j,
+ int ind[], mpq_t val[]), void *info);
+/* compute factorization of the basis matrix */
+
+#define bfx_ftran _glp_bfx_ftran
+void bfx_ftran(BFX *binv, mpq_t x[], int save);
+/* perform forward transformation (FTRAN) */
+
+#define bfx_btran _glp_bfx_btran
+void bfx_btran(BFX *binv, mpq_t x[]);
+/* perform backward transformation (BTRAN) */
+
+#define bfx_update _glp_bfx_update
+int bfx_update(BFX *binv, int j);
+/* update factorization of the basis matrix */
+
+#define bfx_delete_binv _glp_bfx_delete_binv
+void bfx_delete_binv(BFX *binv);
+/* delete factorization of the basis matrix */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/draft.h b/test/monniaux/glpk-4.65/src/draft/draft.h
new file mode 100644
index 00000000..cefd2124
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/draft.h
@@ -0,0 +1,22 @@
+/* draft.h */
+
+/* (reserved for copyright notice) */
+
+#ifndef DRAFT_H
+#define DRAFT_H
+
+#if 1 /* 28/III-2016 */
+#define GLP_UNDOC 1
+#endif
+#include "glpk.h"
+
+#if 1 /* 28/XI-2009 */
+int _glp_analyze_row(glp_prob *P, int len, const int ind[],
+ const double val[], int type, double rhs, double eps, int *_piv,
+ double *_x, double *_dx, double *_y, double *_dy, double *_dz);
+/* simulate one iteration of dual simplex method */
+#endif
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpapi06.c b/test/monniaux/glpk-4.65/src/draft/glpapi06.c
new file mode 100644
index 00000000..a31e3968
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpapi06.c
@@ -0,0 +1,860 @@
+/* glpapi06.c (simplex method routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+#include "npp.h"
+#if 0 /* 07/XI-2015 */
+#include "glpspx.h"
+#else
+#include "simplex.h"
+#define spx_dual spy_dual
+#endif
+
+/***********************************************************************
+* NAME
+*
+* glp_simplex - solve LP problem with the simplex method
+*
+* SYNOPSIS
+*
+* int glp_simplex(glp_prob *P, const glp_smcp *parm);
+*
+* DESCRIPTION
+*
+* The routine glp_simplex is a driver to the LP solver based on the
+* simplex method. This routine retrieves problem data from the
+* specified problem object, calls the solver to solve the problem
+* instance, and stores results of computations back into the problem
+* object.
+*
+* The simplex solver has a set of control parameters. Values of the
+* control parameters can be passed in a structure glp_smcp, which the
+* parameter parm points to.
+*
+* The parameter parm can be specified as NULL, in which case the LP
+* solver uses default settings.
+*
+* RETURNS
+*
+* 0 The LP problem instance has been successfully solved. This code
+* does not necessarily mean that the solver has found optimal
+* solution. It only means that the solution process was successful.
+*
+* GLP_EBADB
+* Unable to start the search, because the initial basis specified
+* in the problem object is invalid--the number of basic (auxiliary
+* and structural) variables is not the same as the number of rows in
+* the problem object.
+*
+* GLP_ESING
+* Unable to start the search, because the basis matrix correspodning
+* to the initial basis is singular within the working precision.
+*
+* GLP_ECOND
+* Unable to start the search, because the basis matrix correspodning
+* to the initial basis is ill-conditioned, i.e. its condition number
+* is too large.
+*
+* GLP_EBOUND
+* Unable to start the search, because some double-bounded variables
+* have incorrect bounds.
+*
+* GLP_EFAIL
+* The search was prematurely terminated due to the solver failure.
+*
+* GLP_EOBJLL
+* The search was prematurely terminated, because the objective
+* function being maximized has reached its lower limit and continues
+* decreasing (dual simplex only).
+*
+* GLP_EOBJUL
+* The search was prematurely terminated, because the objective
+* function being minimized has reached its upper limit and continues
+* increasing (dual simplex only).
+*
+* GLP_EITLIM
+* The search was prematurely terminated, because the simplex
+* iteration limit has been exceeded.
+*
+* GLP_ETMLIM
+* The search was prematurely terminated, because the time limit has
+* been exceeded.
+*
+* GLP_ENOPFS
+* The LP problem instance has no primal feasible solution (only if
+* the LP presolver is used).
+*
+* GLP_ENODFS
+* The LP problem instance has no dual feasible solution (only if the
+* LP presolver is used). */
+
+static void trivial_lp(glp_prob *P, const glp_smcp *parm)
+{ /* solve trivial LP which has empty constraint matrix */
+ GLPROW *row;
+ GLPCOL *col;
+ int i, j;
+ double p_infeas, d_infeas, zeta;
+ P->valid = 0;
+ P->pbs_stat = P->dbs_stat = GLP_FEAS;
+ P->obj_val = P->c0;
+ P->some = 0;
+ p_infeas = d_infeas = 0.0;
+ /* make all auxiliary variables basic */
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ row->stat = GLP_BS;
+ row->prim = row->dual = 0.0;
+ /* check primal feasibility */
+ if (row->type == GLP_LO || row->type == GLP_DB ||
+ row->type == GLP_FX)
+ { /* row has lower bound */
+ if (row->lb > + parm->tol_bnd)
+ { P->pbs_stat = GLP_NOFEAS;
+ if (P->some == 0 && parm->meth != GLP_PRIMAL)
+ P->some = i;
+ }
+ if (p_infeas < + row->lb)
+ p_infeas = + row->lb;
+ }
+ if (row->type == GLP_UP || row->type == GLP_DB ||
+ row->type == GLP_FX)
+ { /* row has upper bound */
+ if (row->ub < - parm->tol_bnd)
+ { P->pbs_stat = GLP_NOFEAS;
+ if (P->some == 0 && parm->meth != GLP_PRIMAL)
+ P->some = i;
+ }
+ if (p_infeas < - row->ub)
+ p_infeas = - row->ub;
+ }
+ }
+ /* determine scale factor for the objective row */
+ zeta = 1.0;
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (zeta < fabs(col->coef)) zeta = fabs(col->coef);
+ }
+ zeta = (P->dir == GLP_MIN ? +1.0 : -1.0) / zeta;
+ /* make all structural variables non-basic */
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (col->type == GLP_FR)
+ col->stat = GLP_NF, col->prim = 0.0;
+ else if (col->type == GLP_LO)
+lo: col->stat = GLP_NL, col->prim = col->lb;
+ else if (col->type == GLP_UP)
+up: col->stat = GLP_NU, col->prim = col->ub;
+ else if (col->type == GLP_DB)
+ { if (zeta * col->coef > 0.0)
+ goto lo;
+ else if (zeta * col->coef < 0.0)
+ goto up;
+ else if (fabs(col->lb) <= fabs(col->ub))
+ goto lo;
+ else
+ goto up;
+ }
+ else if (col->type == GLP_FX)
+ col->stat = GLP_NS, col->prim = col->lb;
+ col->dual = col->coef;
+ P->obj_val += col->coef * col->prim;
+ /* check dual feasibility */
+ if (col->type == GLP_FR || col->type == GLP_LO)
+ { /* column has no upper bound */
+ if (zeta * col->dual < - parm->tol_dj)
+ { P->dbs_stat = GLP_NOFEAS;
+ if (P->some == 0 && parm->meth == GLP_PRIMAL)
+ P->some = P->m + j;
+ }
+ if (d_infeas < - zeta * col->dual)
+ d_infeas = - zeta * col->dual;
+ }
+ if (col->type == GLP_FR || col->type == GLP_UP)
+ { /* column has no lower bound */
+ if (zeta * col->dual > + parm->tol_dj)
+ { P->dbs_stat = GLP_NOFEAS;
+ if (P->some == 0 && parm->meth == GLP_PRIMAL)
+ P->some = P->m + j;
+ }
+ if (d_infeas < + zeta * col->dual)
+ d_infeas = + zeta * col->dual;
+ }
+ }
+ /* simulate the simplex solver output */
+ if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
+ { xprintf("~%6d: obj = %17.9e infeas = %10.3e\n", P->it_cnt,
+ P->obj_val, parm->meth == GLP_PRIMAL ? p_infeas : d_infeas);
+ }
+ if (parm->msg_lev >= GLP_MSG_ALL && parm->out_dly == 0)
+ { if (P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS)
+ xprintf("OPTIMAL SOLUTION FOUND\n");
+ else if (P->pbs_stat == GLP_NOFEAS)
+ xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
+ else if (parm->meth == GLP_PRIMAL)
+ xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
+ else
+ xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
+ }
+ return;
+}
+
+static int solve_lp(glp_prob *P, const glp_smcp *parm)
+{ /* solve LP directly without using the preprocessor */
+ int ret;
+ if (!glp_bf_exists(P))
+ { ret = glp_factorize(P);
+ if (ret == 0)
+ ;
+ else if (ret == GLP_EBADB)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_simplex: initial basis is invalid\n");
+ }
+ else if (ret == GLP_ESING)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_simplex: initial basis is singular\n");
+ }
+ else if (ret == GLP_ECOND)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf(
+ "glp_simplex: initial basis is ill-conditioned\n");
+ }
+ else
+ xassert(ret != ret);
+ if (ret != 0) goto done;
+ }
+ if (parm->meth == GLP_PRIMAL)
+ ret = spx_primal(P, parm);
+ else if (parm->meth == GLP_DUALP)
+ { ret = spx_dual(P, parm);
+ if (ret == GLP_EFAIL && P->valid)
+ ret = spx_primal(P, parm);
+ }
+ else if (parm->meth == GLP_DUAL)
+ ret = spx_dual(P, parm);
+ else
+ xassert(parm != parm);
+done: return ret;
+}
+
+static int preprocess_and_solve_lp(glp_prob *P, const glp_smcp *parm)
+{ /* solve LP using the preprocessor */
+ NPP *npp;
+ glp_prob *lp = NULL;
+ glp_bfcp bfcp;
+ int ret;
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Preprocessing...\n");
+ /* create preprocessor workspace */
+ npp = npp_create_wksp();
+ /* load original problem into the preprocessor workspace */
+ npp_load_prob(npp, P, GLP_OFF, GLP_SOL, GLP_OFF);
+ /* process LP prior to applying primal/dual simplex method */
+ ret = npp_simplex(npp, parm);
+ if (ret == 0)
+ ;
+ else if (ret == GLP_ENOPFS)
+ { if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
+ }
+ else if (ret == GLP_ENODFS)
+ { if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
+ }
+ else
+ xassert(ret != ret);
+ if (ret != 0) goto done;
+ /* build transformed LP */
+ lp = glp_create_prob();
+ npp_build_prob(npp, lp);
+ /* if the transformed LP is empty, it has empty solution, which
+ is optimal */
+ if (lp->m == 0 && lp->n == 0)
+ { lp->pbs_stat = lp->dbs_stat = GLP_FEAS;
+ lp->obj_val = lp->c0;
+ if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
+ { xprintf("~%6d: obj = %17.9e infeas = %10.3e\n", P->it_cnt,
+ lp->obj_val, 0.0);
+ }
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("OPTIMAL SOLUTION FOUND BY LP PREPROCESSOR\n");
+ goto post;
+ }
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ { xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+ lp->m, lp->m == 1 ? "" : "s", lp->n, lp->n == 1 ? "" : "s",
+ lp->nnz, lp->nnz == 1 ? "" : "s");
+ }
+ /* inherit basis factorization control parameters */
+ glp_get_bfcp(P, &bfcp);
+ glp_set_bfcp(lp, &bfcp);
+ /* scale the transformed problem */
+ { ENV *env = get_env_ptr();
+ int term_out = env->term_out;
+ if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+ env->term_out = GLP_OFF;
+ else
+ env->term_out = GLP_ON;
+ glp_scale_prob(lp, GLP_SF_AUTO);
+ env->term_out = term_out;
+ }
+ /* build advanced initial basis */
+ { ENV *env = get_env_ptr();
+ int term_out = env->term_out;
+ if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+ env->term_out = GLP_OFF;
+ else
+ env->term_out = GLP_ON;
+ glp_adv_basis(lp, 0);
+ env->term_out = term_out;
+ }
+ /* solve the transformed LP */
+ lp->it_cnt = P->it_cnt;
+ ret = solve_lp(lp, parm);
+ P->it_cnt = lp->it_cnt;
+ /* only optimal solution can be postprocessed */
+ if (!(ret == 0 && lp->pbs_stat == GLP_FEAS && lp->dbs_stat ==
+ GLP_FEAS))
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_simplex: unable to recover undefined or non-op"
+ "timal solution\n");
+ if (ret == 0)
+ { if (lp->pbs_stat == GLP_NOFEAS)
+ ret = GLP_ENOPFS;
+ else if (lp->dbs_stat == GLP_NOFEAS)
+ ret = GLP_ENODFS;
+ else
+ xassert(lp != lp);
+ }
+ goto done;
+ }
+post: /* postprocess solution from the transformed LP */
+ npp_postprocess(npp, lp);
+ /* the transformed LP is no longer needed */
+ glp_delete_prob(lp), lp = NULL;
+ /* store solution to the original problem */
+ npp_unload_sol(npp, P);
+ /* the original LP has been successfully solved */
+ ret = 0;
+done: /* delete the transformed LP, if it exists */
+ if (lp != NULL) glp_delete_prob(lp);
+ /* delete preprocessor workspace */
+ npp_delete_wksp(npp);
+ return ret;
+}
+
+int glp_simplex(glp_prob *P, const glp_smcp *parm)
+{ /* solve LP problem with the simplex method */
+ glp_smcp _parm;
+ int i, j, ret;
+ /* check problem object */
+#if 0 /* 04/IV-2016 */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_simplex: P = %p; invalid problem object\n", P);
+#endif
+ if (P->tree != NULL && P->tree->reason != 0)
+ xerror("glp_simplex: operation not allowed\n");
+ /* check control parameters */
+ if (parm == NULL)
+ parm = &_parm, glp_init_smcp((glp_smcp *)parm);
+ if (!(parm->msg_lev == GLP_MSG_OFF ||
+ parm->msg_lev == GLP_MSG_ERR ||
+ parm->msg_lev == GLP_MSG_ON ||
+ parm->msg_lev == GLP_MSG_ALL ||
+ parm->msg_lev == GLP_MSG_DBG))
+ xerror("glp_simplex: msg_lev = %d; invalid parameter\n",
+ parm->msg_lev);
+ if (!(parm->meth == GLP_PRIMAL ||
+ parm->meth == GLP_DUALP ||
+ parm->meth == GLP_DUAL))
+ xerror("glp_simplex: meth = %d; invalid parameter\n",
+ parm->meth);
+ if (!(parm->pricing == GLP_PT_STD ||
+ parm->pricing == GLP_PT_PSE))
+ xerror("glp_simplex: pricing = %d; invalid parameter\n",
+ parm->pricing);
+ if (!(parm->r_test == GLP_RT_STD ||
+#if 1 /* 16/III-2016 */
+ parm->r_test == GLP_RT_FLIP ||
+#endif
+ parm->r_test == GLP_RT_HAR))
+ xerror("glp_simplex: r_test = %d; invalid parameter\n",
+ parm->r_test);
+ if (!(0.0 < parm->tol_bnd && parm->tol_bnd < 1.0))
+ xerror("glp_simplex: tol_bnd = %g; invalid parameter\n",
+ parm->tol_bnd);
+ if (!(0.0 < parm->tol_dj && parm->tol_dj < 1.0))
+ xerror("glp_simplex: tol_dj = %g; invalid parameter\n",
+ parm->tol_dj);
+ if (!(0.0 < parm->tol_piv && parm->tol_piv < 1.0))
+ xerror("glp_simplex: tol_piv = %g; invalid parameter\n",
+ parm->tol_piv);
+ if (parm->it_lim < 0)
+ xerror("glp_simplex: it_lim = %d; invalid parameter\n",
+ parm->it_lim);
+ if (parm->tm_lim < 0)
+ xerror("glp_simplex: tm_lim = %d; invalid parameter\n",
+ parm->tm_lim);
+#if 0 /* 15/VII-2017 */
+ if (parm->out_frq < 1)
+#else
+ if (parm->out_frq < 0)
+#endif
+ xerror("glp_simplex: out_frq = %d; invalid parameter\n",
+ parm->out_frq);
+ if (parm->out_dly < 0)
+ xerror("glp_simplex: out_dly = %d; invalid parameter\n",
+ parm->out_dly);
+ if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
+ xerror("glp_simplex: presolve = %d; invalid parameter\n",
+ parm->presolve);
+#if 1 /* 11/VII-2017 */
+ if (!(parm->excl == GLP_ON || parm->excl == GLP_OFF))
+ xerror("glp_simplex: excl = %d; invalid parameter\n",
+ parm->excl);
+ if (!(parm->shift == GLP_ON || parm->shift == GLP_OFF))
+ xerror("glp_simplex: shift = %d; invalid parameter\n",
+ parm->shift);
+ if (!(parm->aorn == GLP_USE_AT || parm->aorn == GLP_USE_NT))
+ xerror("glp_simplex: aorn = %d; invalid parameter\n",
+ parm->aorn);
+#endif
+ /* basic solution is currently undefined */
+ P->pbs_stat = P->dbs_stat = GLP_UNDEF;
+ P->obj_val = 0.0;
+ P->some = 0;
+ /* check bounds of double-bounded variables */
+ for (i = 1; i <= P->m; i++)
+ { GLPROW *row = P->row[i];
+ if (row->type == GLP_DB && row->lb >= row->ub)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_simplex: row %d: lb = %g, ub = %g; incorrec"
+ "t bounds\n", i, row->lb, row->ub);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ for (j = 1; j <= P->n; j++)
+ { GLPCOL *col = P->col[j];
+ if (col->type == GLP_DB && col->lb >= col->ub)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_simplex: column %d: lb = %g, ub = %g; incor"
+ "rect bounds\n", j, col->lb, col->ub);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ /* solve LP problem */
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ { xprintf("GLPK Simplex Optimizer, v%s\n", glp_version());
+ xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+ P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+ P->nnz, P->nnz == 1 ? "" : "s");
+ }
+ if (P->nnz == 0)
+ trivial_lp(P, parm), ret = 0;
+ else if (!parm->presolve)
+ ret = solve_lp(P, parm);
+ else
+ ret = preprocess_and_solve_lp(P, parm);
+done: /* return to the application program */
+ return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_init_smcp - initialize simplex method control parameters
+*
+* SYNOPSIS
+*
+* void glp_init_smcp(glp_smcp *parm);
+*
+* DESCRIPTION
+*
+* The routine glp_init_smcp initializes control parameters, which are
+* used by the simplex solver, with default values.
+*
+* Default values of the control parameters are stored in a glp_smcp
+* structure, which the parameter parm points to. */
+
+void glp_init_smcp(glp_smcp *parm)
+{ parm->msg_lev = GLP_MSG_ALL;
+ parm->meth = GLP_PRIMAL;
+ parm->pricing = GLP_PT_PSE;
+ parm->r_test = GLP_RT_HAR;
+ parm->tol_bnd = 1e-7;
+ parm->tol_dj = 1e-7;
+#if 0 /* 07/XI-2015 */
+ parm->tol_piv = 1e-10;
+#else
+ parm->tol_piv = 1e-9;
+#endif
+ parm->obj_ll = -DBL_MAX;
+ parm->obj_ul = +DBL_MAX;
+ parm->it_lim = INT_MAX;
+ parm->tm_lim = INT_MAX;
+#if 0 /* 15/VII-2017 */
+ parm->out_frq = 500;
+#else
+ parm->out_frq = 5000; /* 5 seconds */
+#endif
+ parm->out_dly = 0;
+ parm->presolve = GLP_OFF;
+#if 1 /* 11/VII-2017 */
+ parm->excl = GLP_ON;
+ parm->shift = GLP_ON;
+ parm->aorn = GLP_USE_NT;
+#endif
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_status - retrieve generic status of basic solution
+*
+* SYNOPSIS
+*
+* int glp_get_status(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_status reports the generic status of the basic
+* solution for the specified problem object as follows:
+*
+* GLP_OPT - solution is optimal;
+* GLP_FEAS - solution is feasible;
+* GLP_INFEAS - solution is infeasible;
+* GLP_NOFEAS - problem has no feasible solution;
+* GLP_UNBND - problem has unbounded solution;
+* GLP_UNDEF - solution is undefined. */
+
+int glp_get_status(glp_prob *lp)
+{ int status;
+ status = glp_get_prim_stat(lp);
+ switch (status)
+ { case GLP_FEAS:
+ switch (glp_get_dual_stat(lp))
+ { case GLP_FEAS:
+ status = GLP_OPT;
+ break;
+ case GLP_NOFEAS:
+ status = GLP_UNBND;
+ break;
+ case GLP_UNDEF:
+ case GLP_INFEAS:
+ status = status;
+ break;
+ default:
+ xassert(lp != lp);
+ }
+ break;
+ case GLP_UNDEF:
+ case GLP_INFEAS:
+ case GLP_NOFEAS:
+ status = status;
+ break;
+ default:
+ xassert(lp != lp);
+ }
+ return status;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_prim_stat - retrieve status of primal basic solution
+*
+* SYNOPSIS
+*
+* int glp_get_prim_stat(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_prim_stat reports the status of the primal basic
+* solution for the specified problem object as follows:
+*
+* GLP_UNDEF - primal solution is undefined;
+* GLP_FEAS - primal solution is feasible;
+* GLP_INFEAS - primal solution is infeasible;
+* GLP_NOFEAS - no primal feasible solution exists. */
+
+int glp_get_prim_stat(glp_prob *lp)
+{ int pbs_stat = lp->pbs_stat;
+ return pbs_stat;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_dual_stat - retrieve status of dual basic solution
+*
+* SYNOPSIS
+*
+* int glp_get_dual_stat(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_dual_stat reports the status of the dual basic
+* solution for the specified problem object as follows:
+*
+* GLP_UNDEF - dual solution is undefined;
+* GLP_FEAS - dual solution is feasible;
+* GLP_INFEAS - dual solution is infeasible;
+* GLP_NOFEAS - no dual feasible solution exists. */
+
+int glp_get_dual_stat(glp_prob *lp)
+{ int dbs_stat = lp->dbs_stat;
+ return dbs_stat;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_obj_val - retrieve objective value (basic solution)
+*
+* SYNOPSIS
+*
+* double glp_get_obj_val(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_obj_val returns value of the objective function
+* for basic solution. */
+
+double glp_get_obj_val(glp_prob *lp)
+{ /*struct LPXCPS *cps = lp->cps;*/
+ double z;
+ z = lp->obj_val;
+ /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
+ return z;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_row_stat - retrieve row status
+*
+* SYNOPSIS
+*
+* int glp_get_row_stat(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_get_row_stat returns current status assigned to the
+* auxiliary variable associated with i-th row as follows:
+*
+* GLP_BS - basic variable;
+* GLP_NL - non-basic variable on its lower bound;
+* GLP_NU - non-basic variable on its upper bound;
+* GLP_NF - non-basic free (unbounded) variable;
+* GLP_NS - non-basic fixed variable. */
+
+int glp_get_row_stat(glp_prob *lp, int i)
+{ if (!(1 <= i && i <= lp->m))
+ xerror("glp_get_row_stat: i = %d; row number out of range\n",
+ i);
+ return lp->row[i]->stat;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_row_prim - retrieve row primal value (basic solution)
+*
+* SYNOPSIS
+*
+* double glp_get_row_prim(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_get_row_prim returns primal value of the auxiliary
+* variable associated with i-th row. */
+
+double glp_get_row_prim(glp_prob *lp, int i)
+{ /*struct LPXCPS *cps = lp->cps;*/
+ double prim;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_get_row_prim: i = %d; row number out of range\n",
+ i);
+ prim = lp->row[i]->prim;
+ /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
+ return prim;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_row_dual - retrieve row dual value (basic solution)
+*
+* SYNOPSIS
+*
+* double glp_get_row_dual(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_get_row_dual returns dual value (i.e. reduced cost)
+* of the auxiliary variable associated with i-th row. */
+
+double glp_get_row_dual(glp_prob *lp, int i)
+{ /*struct LPXCPS *cps = lp->cps;*/
+ double dual;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_get_row_dual: i = %d; row number out of range\n",
+ i);
+ dual = lp->row[i]->dual;
+ /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
+ return dual;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_col_stat - retrieve column status
+*
+* SYNOPSIS
+*
+* int glp_get_col_stat(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_get_col_stat returns current status assigned to the
+* structural variable associated with j-th column as follows:
+*
+* GLP_BS - basic variable;
+* GLP_NL - non-basic variable on its lower bound;
+* GLP_NU - non-basic variable on its upper bound;
+* GLP_NF - non-basic free (unbounded) variable;
+* GLP_NS - non-basic fixed variable. */
+
+int glp_get_col_stat(glp_prob *lp, int j)
+{ if (!(1 <= j && j <= lp->n))
+ xerror("glp_get_col_stat: j = %d; column number out of range\n"
+ , j);
+ return lp->col[j]->stat;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_col_prim - retrieve column primal value (basic solution)
+*
+* SYNOPSIS
+*
+* double glp_get_col_prim(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_get_col_prim returns primal value of the structural
+* variable associated with j-th column. */
+
+double glp_get_col_prim(glp_prob *lp, int j)
+{ /*struct LPXCPS *cps = lp->cps;*/
+ double prim;
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_get_col_prim: j = %d; column number out of range\n"
+ , j);
+ prim = lp->col[j]->prim;
+ /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
+ return prim;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_col_dual - retrieve column dual value (basic solution)
+*
+* SYNOPSIS
+*
+* double glp_get_col_dual(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_get_col_dual returns dual value (i.e. reduced cost)
+* of the structural variable associated with j-th column. */
+
+double glp_get_col_dual(glp_prob *lp, int j)
+{ /*struct LPXCPS *cps = lp->cps;*/
+ double dual;
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_get_col_dual: j = %d; column number out of range\n"
+ , j);
+ dual = lp->col[j]->dual;
+ /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
+ return dual;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_unbnd_ray - determine variable causing unboundedness
+*
+* SYNOPSIS
+*
+* int glp_get_unbnd_ray(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_get_unbnd_ray returns the number k of a variable,
+* which causes primal or dual unboundedness. If 1 <= k <= m, it is
+* k-th auxiliary variable, and if m+1 <= k <= m+n, it is (k-m)-th
+* structural variable, where m is the number of rows, n is the number
+* of columns in the problem object. If such variable is not defined,
+* the routine returns 0.
+*
+* COMMENTS
+*
+* If it is not exactly known which version of the simplex solver
+* detected unboundedness, i.e. whether the unboundedness is primal or
+* dual, it is sufficient to check the status of the variable reported
+* with the routine glp_get_row_stat or glp_get_col_stat. If the
+* variable is non-basic, the unboundedness is primal, otherwise, if
+* the variable is basic, the unboundedness is dual (the latter case
+* means that the problem has no primal feasible dolution). */
+
+int glp_get_unbnd_ray(glp_prob *lp)
+{ int k;
+ k = lp->some;
+ xassert(k >= 0);
+ if (k > lp->m + lp->n) k = 0;
+ return k;
+}
+
+#if 1 /* 08/VIII-2013 */
+int glp_get_it_cnt(glp_prob *P)
+{ /* get simplex solver iteration count */
+ return P->it_cnt;
+}
+#endif
+
+#if 1 /* 08/VIII-2013 */
+void glp_set_it_cnt(glp_prob *P, int it_cnt)
+{ /* set simplex solver iteration count */
+ P->it_cnt = it_cnt;
+ return;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpapi07.c b/test/monniaux/glpk-4.65/src/draft/glpapi07.c
new file mode 100644
index 00000000..9ac294bd
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpapi07.c
@@ -0,0 +1,499 @@
+/* glpapi07.c (exact simplex solver) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2017 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/>.
+***********************************************************************/
+
+#include "draft.h"
+#include "glpssx.h"
+#include "misc.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_exact - solve LP problem in exact arithmetic
+*
+* SYNOPSIS
+*
+* int glp_exact(glp_prob *lp, const glp_smcp *parm);
+*
+* DESCRIPTION
+*
+* The routine glp_exact is a tentative implementation of the primal
+* two-phase simplex method based on exact (rational) arithmetic. It is
+* similar to the routine glp_simplex, however, for all internal
+* computations it uses arithmetic of rational numbers, which is exact
+* in mathematical sense, i.e. free of round-off errors unlike floating
+* point arithmetic.
+*
+* Note that the routine glp_exact uses inly two control parameters
+* passed in the structure glp_smcp, namely, it_lim and tm_lim.
+*
+* RETURNS
+*
+* 0 The LP problem instance has been successfully solved. This code
+* does not necessarily mean that the solver has found optimal
+* solution. It only means that the solution process was successful.
+*
+* GLP_EBADB
+* Unable to start the search, because the initial basis specified
+* in the problem object is invalid--the number of basic (auxiliary
+* and structural) variables is not the same as the number of rows in
+* the problem object.
+*
+* GLP_ESING
+* Unable to start the search, because the basis matrix correspodning
+* to the initial basis is exactly singular.
+*
+* GLP_EBOUND
+* Unable to start the search, because some double-bounded variables
+* have incorrect bounds.
+*
+* GLP_EFAIL
+* The problem has no rows/columns.
+*
+* GLP_EITLIM
+* The search was prematurely terminated, because the simplex
+* iteration limit has been exceeded.
+*
+* GLP_ETMLIM
+* The search was prematurely terminated, because the time limit has
+* been exceeded. */
+
+static void set_d_eps(mpq_t x, double val)
+{ /* convert double val to rational x obtaining a more adequate
+ fraction than provided by mpq_set_d due to allowing a small
+ approximation error specified by a given relative tolerance;
+ for example, mpq_set_d would give the following
+ 1/3 ~= 0.333333333333333314829616256247391... ->
+ -> 6004799503160661/18014398509481984
+ while this routine gives exactly 1/3 */
+ int s, n, j;
+ double f, p, q, eps = 1e-9;
+ mpq_t temp;
+ xassert(-DBL_MAX <= val && val <= +DBL_MAX);
+#if 1 /* 30/VII-2008 */
+ if (val == floor(val))
+ { /* if val is integral, do not approximate */
+ mpq_set_d(x, val);
+ goto done;
+ }
+#endif
+ if (val > 0.0)
+ s = +1;
+ else if (val < 0.0)
+ s = -1;
+ else
+ { mpq_set_si(x, 0, 1);
+ goto done;
+ }
+ f = frexp(fabs(val), &n);
+ /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
+ fp2rat(f, 0.1 * eps, &p, &q);
+ /* f ~= p / q, where p and q are integers */
+ mpq_init(temp);
+ mpq_set_d(x, p);
+ mpq_set_d(temp, q);
+ mpq_div(x, x, temp);
+ mpq_set_si(temp, 1, 1);
+ for (j = 1; j <= abs(n); j++)
+ mpq_add(temp, temp, temp);
+ if (n > 0)
+ mpq_mul(x, x, temp);
+ else if (n < 0)
+ mpq_div(x, x, temp);
+ mpq_clear(temp);
+ if (s < 0) mpq_neg(x, x);
+ /* check that the desired tolerance has been attained */
+ xassert(fabs(val - mpq_get_d(x)) <= eps * (1.0 + fabs(val)));
+done: return;
+}
+
+static void load_data(SSX *ssx, glp_prob *lp)
+{ /* load LP problem data into simplex solver workspace */
+ int m = ssx->m;
+ int n = ssx->n;
+ int nnz = ssx->A_ptr[n+1]-1;
+ int j, k, type, loc, len, *ind;
+ double lb, ub, coef, *val;
+ xassert(lp->m == m);
+ xassert(lp->n == n);
+ xassert(lp->nnz == nnz);
+ /* types and bounds of rows and columns */
+ for (k = 1; k <= m+n; k++)
+ { if (k <= m)
+ { type = lp->row[k]->type;
+ lb = lp->row[k]->lb;
+ ub = lp->row[k]->ub;
+ }
+ else
+ { type = lp->col[k-m]->type;
+ lb = lp->col[k-m]->lb;
+ ub = lp->col[k-m]->ub;
+ }
+ switch (type)
+ { case GLP_FR: type = SSX_FR; break;
+ case GLP_LO: type = SSX_LO; break;
+ case GLP_UP: type = SSX_UP; break;
+ case GLP_DB: type = SSX_DB; break;
+ case GLP_FX: type = SSX_FX; break;
+ default: xassert(type != type);
+ }
+ ssx->type[k] = type;
+ set_d_eps(ssx->lb[k], lb);
+ set_d_eps(ssx->ub[k], ub);
+ }
+ /* optimization direction */
+ switch (lp->dir)
+ { case GLP_MIN: ssx->dir = SSX_MIN; break;
+ case GLP_MAX: ssx->dir = SSX_MAX; break;
+ default: xassert(lp != lp);
+ }
+ /* objective coefficients */
+ for (k = 0; k <= m+n; k++)
+ { if (k == 0)
+ coef = lp->c0;
+ else if (k <= m)
+ coef = 0.0;
+ else
+ coef = lp->col[k-m]->coef;
+ set_d_eps(ssx->coef[k], coef);
+ }
+ /* constraint coefficients */
+ ind = xcalloc(1+m, sizeof(int));
+ val = xcalloc(1+m, sizeof(double));
+ loc = 0;
+ for (j = 1; j <= n; j++)
+ { ssx->A_ptr[j] = loc+1;
+ len = glp_get_mat_col(lp, j, ind, val);
+ for (k = 1; k <= len; k++)
+ { loc++;
+ ssx->A_ind[loc] = ind[k];
+ set_d_eps(ssx->A_val[loc], val[k]);
+ }
+ }
+ xassert(loc == nnz);
+ xfree(ind);
+ xfree(val);
+ return;
+}
+
+static int load_basis(SSX *ssx, glp_prob *lp)
+{ /* load current LP basis into simplex solver workspace */
+ int m = ssx->m;
+ int n = ssx->n;
+ int *type = ssx->type;
+ int *stat = ssx->stat;
+ int *Q_row = ssx->Q_row;
+ int *Q_col = ssx->Q_col;
+ int i, j, k;
+ xassert(lp->m == m);
+ xassert(lp->n == n);
+ /* statuses of rows and columns */
+ for (k = 1; k <= m+n; k++)
+ { if (k <= m)
+ stat[k] = lp->row[k]->stat;
+ else
+ stat[k] = lp->col[k-m]->stat;
+ switch (stat[k])
+ { case GLP_BS:
+ stat[k] = SSX_BS;
+ break;
+ case GLP_NL:
+ stat[k] = SSX_NL;
+ xassert(type[k] == SSX_LO || type[k] == SSX_DB);
+ break;
+ case GLP_NU:
+ stat[k] = SSX_NU;
+ xassert(type[k] == SSX_UP || type[k] == SSX_DB);
+ break;
+ case GLP_NF:
+ stat[k] = SSX_NF;
+ xassert(type[k] == SSX_FR);
+ break;
+ case GLP_NS:
+ stat[k] = SSX_NS;
+ xassert(type[k] == SSX_FX);
+ break;
+ default:
+ xassert(stat != stat);
+ }
+ }
+ /* build permutation matix Q */
+ i = j = 0;
+ for (k = 1; k <= m+n; k++)
+ { if (stat[k] == SSX_BS)
+ { i++;
+ if (i > m) return 1;
+ Q_row[k] = i, Q_col[i] = k;
+ }
+ else
+ { j++;
+ if (j > n) return 1;
+ Q_row[k] = m+j, Q_col[m+j] = k;
+ }
+ }
+ xassert(i == m && j == n);
+ return 0;
+}
+
+int glp_exact(glp_prob *lp, const glp_smcp *parm)
+{ glp_smcp _parm;
+ SSX *ssx;
+ int m = lp->m;
+ int n = lp->n;
+ int nnz = lp->nnz;
+ int i, j, k, type, pst, dst, ret, stat;
+ double lb, ub, prim, dual, sum;
+ if (parm == NULL)
+ parm = &_parm, glp_init_smcp((glp_smcp *)parm);
+ /* check control parameters */
+#if 1 /* 25/XI-2017 */
+ switch (parm->msg_lev)
+ { case GLP_MSG_OFF:
+ case GLP_MSG_ERR:
+ case GLP_MSG_ON:
+ case GLP_MSG_ALL:
+ case GLP_MSG_DBG:
+ break;
+ default:
+ xerror("glp_exact: msg_lev = %d; invalid parameter\n",
+ parm->msg_lev);
+ }
+#endif
+ if (parm->it_lim < 0)
+ xerror("glp_exact: it_lim = %d; invalid parameter\n",
+ parm->it_lim);
+ if (parm->tm_lim < 0)
+ xerror("glp_exact: tm_lim = %d; invalid parameter\n",
+ parm->tm_lim);
+ /* the problem must have at least one row and one column */
+ if (!(m > 0 && n > 0))
+#if 0 /* 25/XI-2017 */
+ { xprintf("glp_exact: problem has no rows/columns\n");
+#else
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_exact: problem has no rows/columns\n");
+#endif
+ return GLP_EFAIL;
+ }
+#if 1
+ /* basic solution is currently undefined */
+ lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+ lp->obj_val = 0.0;
+ lp->some = 0;
+#endif
+ /* check that all double-bounded variables have correct bounds */
+ for (k = 1; k <= m+n; k++)
+ { if (k <= m)
+ { type = lp->row[k]->type;
+ lb = lp->row[k]->lb;
+ ub = lp->row[k]->ub;
+ }
+ else
+ { type = lp->col[k-m]->type;
+ lb = lp->col[k-m]->lb;
+ ub = lp->col[k-m]->ub;
+ }
+ if (type == GLP_DB && lb >= ub)
+#if 0 /* 25/XI-2017 */
+ { xprintf("glp_exact: %s %d has invalid bounds\n",
+ k <= m ? "row" : "column", k <= m ? k : k-m);
+#else
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_exact: %s %d has invalid bounds\n",
+ k <= m ? "row" : "column", k <= m ? k : k-m);
+#endif
+ return GLP_EBOUND;
+ }
+ }
+ /* create the simplex solver workspace */
+#if 1 /* 25/XI-2017 */
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ {
+#endif
+ xprintf("glp_exact: %d rows, %d columns, %d non-zeros\n",
+ m, n, nnz);
+#ifdef HAVE_GMP
+ xprintf("GNU MP bignum library is being used\n");
+#else
+ xprintf("GLPK bignum module is being used\n");
+ xprintf("(Consider installing GNU MP to attain a much better perf"
+ "ormance.)\n");
+#endif
+#if 1 /* 25/XI-2017 */
+ }
+#endif
+ ssx = ssx_create(m, n, nnz);
+ /* load LP problem data into the workspace */
+ load_data(ssx, lp);
+ /* load current LP basis into the workspace */
+ if (load_basis(ssx, lp))
+#if 0 /* 25/XI-2017 */
+ { xprintf("glp_exact: initial LP basis is invalid\n");
+#else
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_exact: initial LP basis is invalid\n");
+#endif
+ ret = GLP_EBADB;
+ goto done;
+ }
+#if 0
+ /* inherit some control parameters from the LP object */
+ ssx->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
+ ssx->it_cnt = lpx_get_int_parm(lp, LPX_K_ITCNT);
+ ssx->tm_lim = lpx_get_real_parm(lp, LPX_K_TMLIM);
+#else
+#if 1 /* 25/XI-2017 */
+ ssx->msg_lev = parm->msg_lev;
+#endif
+ ssx->it_lim = parm->it_lim;
+ ssx->it_cnt = lp->it_cnt;
+ ssx->tm_lim = (double)parm->tm_lim / 1000.0;
+#endif
+ ssx->out_frq = 5.0;
+ ssx->tm_beg = xtime();
+#if 0 /* 10/VI-2013 */
+ ssx->tm_lag = xlset(0);
+#else
+ ssx->tm_lag = 0.0;
+#endif
+ /* solve LP */
+ ret = ssx_driver(ssx);
+#if 0
+ /* copy back some statistics to the LP object */
+ lpx_set_int_parm(lp, LPX_K_ITLIM, ssx->it_lim);
+ lpx_set_int_parm(lp, LPX_K_ITCNT, ssx->it_cnt);
+ lpx_set_real_parm(lp, LPX_K_TMLIM, ssx->tm_lim);
+#else
+ lp->it_cnt = ssx->it_cnt;
+#endif
+ /* analyze the return code */
+ switch (ret)
+ { case 0:
+ /* optimal solution found */
+ ret = 0;
+ pst = dst = GLP_FEAS;
+ break;
+ case 1:
+ /* problem has no feasible solution */
+ ret = 0;
+ pst = GLP_NOFEAS, dst = GLP_INFEAS;
+ break;
+ case 2:
+ /* problem has unbounded solution */
+ ret = 0;
+ pst = GLP_FEAS, dst = GLP_NOFEAS;
+#if 1
+ xassert(1 <= ssx->q && ssx->q <= n);
+ lp->some = ssx->Q_col[m + ssx->q];
+ xassert(1 <= lp->some && lp->some <= m+n);
+#endif
+ break;
+ case 3:
+ /* iteration limit exceeded (phase I) */
+ ret = GLP_EITLIM;
+ pst = dst = GLP_INFEAS;
+ break;
+ case 4:
+ /* iteration limit exceeded (phase II) */
+ ret = GLP_EITLIM;
+ pst = GLP_FEAS, dst = GLP_INFEAS;
+ break;
+ case 5:
+ /* time limit exceeded (phase I) */
+ ret = GLP_ETMLIM;
+ pst = dst = GLP_INFEAS;
+ break;
+ case 6:
+ /* time limit exceeded (phase II) */
+ ret = GLP_ETMLIM;
+ pst = GLP_FEAS, dst = GLP_INFEAS;
+ break;
+ case 7:
+ /* initial basis matrix is singular */
+ ret = GLP_ESING;
+ goto done;
+ default:
+ xassert(ret != ret);
+ }
+ /* store final basic solution components into LP object */
+ lp->pbs_stat = pst;
+ lp->dbs_stat = dst;
+ sum = lp->c0;
+ for (k = 1; k <= m+n; k++)
+ { if (ssx->stat[k] == SSX_BS)
+ { i = ssx->Q_row[k]; /* x[k] = xB[i] */
+ xassert(1 <= i && i <= m);
+ stat = GLP_BS;
+ prim = mpq_get_d(ssx->bbar[i]);
+ dual = 0.0;
+ }
+ else
+ { j = ssx->Q_row[k] - m; /* x[k] = xN[j] */
+ xassert(1 <= j && j <= n);
+ switch (ssx->stat[k])
+ { case SSX_NF:
+ stat = GLP_NF;
+ prim = 0.0;
+ break;
+ case SSX_NL:
+ stat = GLP_NL;
+ prim = mpq_get_d(ssx->lb[k]);
+ break;
+ case SSX_NU:
+ stat = GLP_NU;
+ prim = mpq_get_d(ssx->ub[k]);
+ break;
+ case SSX_NS:
+ stat = GLP_NS;
+ prim = mpq_get_d(ssx->lb[k]);
+ break;
+ default:
+ xassert(ssx != ssx);
+ }
+ dual = mpq_get_d(ssx->cbar[j]);
+ }
+ if (k <= m)
+ { glp_set_row_stat(lp, k, stat);
+ lp->row[k]->prim = prim;
+ lp->row[k]->dual = dual;
+ }
+ else
+ { glp_set_col_stat(lp, k-m, stat);
+ lp->col[k-m]->prim = prim;
+ lp->col[k-m]->dual = dual;
+ sum += lp->col[k-m]->coef * prim;
+ }
+ }
+ lp->obj_val = sum;
+done: /* delete the simplex solver workspace */
+ ssx_delete(ssx);
+#if 1 /* 23/XI-2015 */
+ xassert(gmp_pool_count() == 0);
+ gmp_free_mem();
+#endif
+ /* return to the application program */
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpapi08.c b/test/monniaux/glpk-4.65/src/draft/glpapi08.c
new file mode 100644
index 00000000..652292cb
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpapi08.c
@@ -0,0 +1,388 @@
+/* glpapi08.c (interior-point method routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpipm.h"
+#include "npp.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_interior - solve LP problem with the interior-point method
+*
+* SYNOPSIS
+*
+* int glp_interior(glp_prob *P, const glp_iptcp *parm);
+*
+* The routine glp_interior is a driver to the LP solver based on the
+* interior-point method.
+*
+* The interior-point solver has a set of control parameters. Values of
+* the control parameters can be passed in a structure glp_iptcp, which
+* the parameter parm points to.
+*
+* Currently this routine implements an easy variant of the primal-dual
+* interior-point method based on Mehrotra's technique.
+*
+* This routine transforms the original LP problem to an equivalent LP
+* problem in the standard formulation (all constraints are equalities,
+* all variables are non-negative), calls the routine ipm_main to solve
+* the transformed problem, and then transforms an obtained solution to
+* the solution of the original problem.
+*
+* RETURNS
+*
+* 0 The LP problem instance has been successfully solved. This code
+* does not necessarily mean that the solver has found optimal
+* solution. It only means that the solution process was successful.
+*
+* GLP_EFAIL
+* The problem has no rows/columns.
+*
+* GLP_ENOCVG
+* Very slow convergence or divergence.
+*
+* GLP_EITLIM
+* Iteration limit exceeded.
+*
+* GLP_EINSTAB
+* Numerical instability on solving Newtonian system. */
+
+static void transform(NPP *npp)
+{ /* transform LP to the standard formulation */
+ NPPROW *row, *prev_row;
+ NPPCOL *col, *prev_col;
+ for (row = npp->r_tail; row != NULL; row = prev_row)
+ { prev_row = row->prev;
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ npp_free_row(npp, row);
+ else if (row->lb == -DBL_MAX)
+ npp_leq_row(npp, row);
+ else if (row->ub == +DBL_MAX)
+ npp_geq_row(npp, row);
+ else if (row->lb != row->ub)
+ { if (fabs(row->lb) < fabs(row->ub))
+ npp_geq_row(npp, row);
+ else
+ npp_leq_row(npp, row);
+ }
+ }
+ for (col = npp->c_tail; col != NULL; col = prev_col)
+ { prev_col = col->prev;
+ if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
+ npp_free_col(npp, col);
+ else if (col->lb == -DBL_MAX)
+ npp_ubnd_col(npp, col);
+ else if (col->ub == +DBL_MAX)
+ { if (col->lb != 0.0)
+ npp_lbnd_col(npp, col);
+ }
+ else if (col->lb != col->ub)
+ { if (fabs(col->lb) < fabs(col->ub))
+ { if (col->lb != 0.0)
+ npp_lbnd_col(npp, col);
+ }
+ else
+ npp_ubnd_col(npp, col);
+ npp_dbnd_col(npp, col);
+ }
+ else
+ npp_fixed_col(npp, col);
+ }
+ for (row = npp->r_head; row != NULL; row = row->next)
+ xassert(row->lb == row->ub);
+ for (col = npp->c_head; col != NULL; col = col->next)
+ xassert(col->lb == 0.0 && col->ub == +DBL_MAX);
+ return;
+}
+
+int glp_interior(glp_prob *P, const glp_iptcp *parm)
+{ glp_iptcp _parm;
+ GLPROW *row;
+ GLPCOL *col;
+ NPP *npp = NULL;
+ glp_prob *prob = NULL;
+ int i, j, ret;
+ /* check control parameters */
+ if (parm == NULL)
+ glp_init_iptcp(&_parm), parm = &_parm;
+ if (!(parm->msg_lev == GLP_MSG_OFF ||
+ parm->msg_lev == GLP_MSG_ERR ||
+ parm->msg_lev == GLP_MSG_ON ||
+ parm->msg_lev == GLP_MSG_ALL))
+ xerror("glp_interior: msg_lev = %d; invalid parameter\n",
+ parm->msg_lev);
+ if (!(parm->ord_alg == GLP_ORD_NONE ||
+ parm->ord_alg == GLP_ORD_QMD ||
+ parm->ord_alg == GLP_ORD_AMD ||
+ parm->ord_alg == GLP_ORD_SYMAMD))
+ xerror("glp_interior: ord_alg = %d; invalid parameter\n",
+ parm->ord_alg);
+ /* interior-point solution is currently undefined */
+ P->ipt_stat = GLP_UNDEF;
+ P->ipt_obj = 0.0;
+ /* check bounds of double-bounded variables */
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ if (row->type == GLP_DB && row->lb >= row->ub)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_interior: row %d: lb = %g, ub = %g; incorre"
+ "ct bounds\n", i, row->lb, row->ub);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (col->type == GLP_DB && col->lb >= col->ub)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_interior: column %d: lb = %g, ub = %g; inco"
+ "rrect bounds\n", j, col->lb, col->ub);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ /* transform LP to the standard formulation */
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Original LP has %d row(s), %d column(s), and %d non-z"
+ "ero(s)\n", P->m, P->n, P->nnz);
+ npp = npp_create_wksp();
+ npp_load_prob(npp, P, GLP_OFF, GLP_IPT, GLP_ON);
+ transform(npp);
+ prob = glp_create_prob();
+ npp_build_prob(npp, prob);
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Working LP has %d row(s), %d column(s), and %d non-ze"
+ "ro(s)\n", prob->m, prob->n, prob->nnz);
+#if 1
+ /* currently empty problem cannot be solved */
+ if (!(prob->m > 0 && prob->n > 0))
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_interior: unable to solve empty problem\n");
+ ret = GLP_EFAIL;
+ goto done;
+ }
+#endif
+ /* scale the resultant LP */
+ { ENV *env = get_env_ptr();
+ int term_out = env->term_out;
+ env->term_out = GLP_OFF;
+ glp_scale_prob(prob, GLP_SF_EQ);
+ env->term_out = term_out;
+ }
+ /* warn about dense columns */
+ if (parm->msg_lev >= GLP_MSG_ON && prob->m >= 200)
+ { int len, cnt = 0;
+ for (j = 1; j <= prob->n; j++)
+ { len = glp_get_mat_col(prob, j, NULL, NULL);
+ if ((double)len >= 0.20 * (double)prob->m) cnt++;
+ }
+ if (cnt == 1)
+ xprintf("WARNING: PROBLEM HAS ONE DENSE COLUMN\n");
+ else if (cnt > 0)
+ xprintf("WARNING: PROBLEM HAS %d DENSE COLUMNS\n", cnt);
+ }
+ /* solve the transformed LP */
+ ret = ipm_solve(prob, parm);
+ /* postprocess solution from the transformed LP */
+ npp_postprocess(npp, prob);
+ /* and store solution to the original LP */
+ npp_unload_sol(npp, P);
+done: /* free working program objects */
+ if (npp != NULL) npp_delete_wksp(npp);
+ if (prob != NULL) glp_delete_prob(prob);
+ /* return to the application program */
+ return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_init_iptcp - initialize interior-point solver control parameters
+*
+* SYNOPSIS
+*
+* void glp_init_iptcp(glp_iptcp *parm);
+*
+* DESCRIPTION
+*
+* The routine glp_init_iptcp initializes control parameters, which are
+* used by the interior-point solver, with default values.
+*
+* Default values of the control parameters are stored in the glp_iptcp
+* structure, which the parameter parm points to. */
+
+void glp_init_iptcp(glp_iptcp *parm)
+{ parm->msg_lev = GLP_MSG_ALL;
+ parm->ord_alg = GLP_ORD_AMD;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ipt_status - retrieve status of interior-point solution
+*
+* SYNOPSIS
+*
+* int glp_ipt_status(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_ipt_status reports the status of solution found by
+* the interior-point solver as follows:
+*
+* GLP_UNDEF - interior-point solution is undefined;
+* GLP_OPT - interior-point solution is optimal;
+* GLP_INFEAS - interior-point solution is infeasible;
+* GLP_NOFEAS - no feasible solution exists. */
+
+int glp_ipt_status(glp_prob *lp)
+{ int ipt_stat = lp->ipt_stat;
+ return ipt_stat;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ipt_obj_val - retrieve objective value (interior point)
+*
+* SYNOPSIS
+*
+* double glp_ipt_obj_val(glp_prob *lp);
+*
+* RETURNS
+*
+* The routine glp_ipt_obj_val returns value of the objective function
+* for interior-point solution. */
+
+double glp_ipt_obj_val(glp_prob *lp)
+{ /*struct LPXCPS *cps = lp->cps;*/
+ double z;
+ z = lp->ipt_obj;
+ /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
+ return z;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ipt_row_prim - retrieve row primal value (interior point)
+*
+* SYNOPSIS
+*
+* double glp_ipt_row_prim(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_ipt_row_prim returns primal value of the auxiliary
+* variable associated with i-th row. */
+
+double glp_ipt_row_prim(glp_prob *lp, int i)
+{ /*struct LPXCPS *cps = lp->cps;*/
+ double pval;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_ipt_row_prim: i = %d; row number out of range\n",
+ i);
+ pval = lp->row[i]->pval;
+ /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
+ return pval;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ipt_row_dual - retrieve row dual value (interior point)
+*
+* SYNOPSIS
+*
+* double glp_ipt_row_dual(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_ipt_row_dual returns dual value (i.e. reduced cost)
+* of the auxiliary variable associated with i-th row. */
+
+double glp_ipt_row_dual(glp_prob *lp, int i)
+{ /*struct LPXCPS *cps = lp->cps;*/
+ double dval;
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_ipt_row_dual: i = %d; row number out of range\n",
+ i);
+ dval = lp->row[i]->dval;
+ /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
+ return dval;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ipt_col_prim - retrieve column primal value (interior point)
+*
+* SYNOPSIS
+*
+* double glp_ipt_col_prim(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_ipt_col_prim returns primal value of the structural
+* variable associated with j-th column. */
+
+double glp_ipt_col_prim(glp_prob *lp, int j)
+{ /*struct LPXCPS *cps = lp->cps;*/
+ double pval;
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_ipt_col_prim: j = %d; column number out of range\n"
+ , j);
+ pval = lp->col[j]->pval;
+ /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
+ return pval;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ipt_col_dual - retrieve column dual value (interior point)
+*
+* SYNOPSIS
+*
+* double glp_ipt_col_dual(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_ipt_col_dual returns dual value (i.e. reduced cost)
+* of the structural variable associated with j-th column. */
+
+double glp_ipt_col_dual(glp_prob *lp, int j)
+{ /*struct LPXCPS *cps = lp->cps;*/
+ double dval;
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_ipt_col_dual: j = %d; column number out of range\n"
+ , j);
+ dval = lp->col[j]->dval;
+ /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
+ return dval;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpapi09.c b/test/monniaux/glpk-4.65/src/draft/glpapi09.c
new file mode 100644
index 00000000..0d3ab57b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpapi09.c
@@ -0,0 +1,798 @@
+/* glpapi09.c (mixed integer programming routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2018 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/>.
+***********************************************************************/
+
+#include "draft.h"
+#include "env.h"
+#include "ios.h"
+#include "npp.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_set_col_kind - set (change) column kind
+*
+* SYNOPSIS
+*
+* void glp_set_col_kind(glp_prob *mip, int j, int kind);
+*
+* DESCRIPTION
+*
+* The routine glp_set_col_kind sets (changes) the kind of j-th column
+* (structural variable) as specified by the parameter kind:
+*
+* GLP_CV - continuous variable;
+* GLP_IV - integer variable;
+* GLP_BV - binary variable. */
+
+void glp_set_col_kind(glp_prob *mip, int j, int kind)
+{ GLPCOL *col;
+ if (!(1 <= j && j <= mip->n))
+ xerror("glp_set_col_kind: j = %d; column number out of range\n"
+ , j);
+ col = mip->col[j];
+ switch (kind)
+ { case GLP_CV:
+ col->kind = GLP_CV;
+ break;
+ case GLP_IV:
+ col->kind = GLP_IV;
+ break;
+ case GLP_BV:
+ col->kind = GLP_IV;
+ if (!(col->type == GLP_DB && col->lb == 0.0 && col->ub ==
+ 1.0)) glp_set_col_bnds(mip, j, GLP_DB, 0.0, 1.0);
+ break;
+ default:
+ xerror("glp_set_col_kind: j = %d; kind = %d; invalid column"
+ " kind\n", j, kind);
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_col_kind - retrieve column kind
+*
+* SYNOPSIS
+*
+* int glp_get_col_kind(glp_prob *mip, int j);
+*
+* RETURNS
+*
+* The routine glp_get_col_kind returns the kind of j-th column, i.e.
+* the kind of corresponding structural variable, as follows:
+*
+* GLP_CV - continuous variable;
+* GLP_IV - integer variable;
+* GLP_BV - binary variable */
+
+int glp_get_col_kind(glp_prob *mip, int j)
+{ GLPCOL *col;
+ int kind;
+ if (!(1 <= j && j <= mip->n))
+ xerror("glp_get_col_kind: j = %d; column number out of range\n"
+ , j);
+ col = mip->col[j];
+ kind = col->kind;
+ switch (kind)
+ { case GLP_CV:
+ break;
+ case GLP_IV:
+ if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
+ kind = GLP_BV;
+ break;
+ default:
+ xassert(kind != kind);
+ }
+ return kind;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_num_int - retrieve number of integer columns
+*
+* SYNOPSIS
+*
+* int glp_get_num_int(glp_prob *mip);
+*
+* RETURNS
+*
+* The routine glp_get_num_int returns the current number of columns,
+* which are marked as integer. */
+
+int glp_get_num_int(glp_prob *mip)
+{ GLPCOL *col;
+ int j, count = 0;
+ for (j = 1; j <= mip->n; j++)
+ { col = mip->col[j];
+ if (col->kind == GLP_IV) count++;
+ }
+ return count;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_num_bin - retrieve number of binary columns
+*
+* SYNOPSIS
+*
+* int glp_get_num_bin(glp_prob *mip);
+*
+* RETURNS
+*
+* The routine glp_get_num_bin returns the current number of columns,
+* which are marked as binary. */
+
+int glp_get_num_bin(glp_prob *mip)
+{ GLPCOL *col;
+ int j, count = 0;
+ for (j = 1; j <= mip->n; j++)
+ { col = mip->col[j];
+ if (col->kind == GLP_IV && col->type == GLP_DB && col->lb ==
+ 0.0 && col->ub == 1.0) count++;
+ }
+ return count;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_intopt - solve MIP problem with the branch-and-bound method
+*
+* SYNOPSIS
+*
+* int glp_intopt(glp_prob *P, const glp_iocp *parm);
+*
+* DESCRIPTION
+*
+* The routine glp_intopt is a driver to the MIP solver based on the
+* branch-and-bound method.
+*
+* On entry the problem object should contain optimal solution to LP
+* relaxation (which can be obtained with the routine glp_simplex).
+*
+* The MIP solver has a set of control parameters. Values of the control
+* parameters can be passed in a structure glp_iocp, which the parameter
+* parm points to.
+*
+* The parameter parm can be specified as NULL, in which case the MIP
+* solver uses default settings.
+*
+* RETURNS
+*
+* 0 The MIP problem instance has been successfully solved. This code
+* does not necessarily mean that the solver has found optimal
+* solution. It only means that the solution process was successful.
+*
+* GLP_EBOUND
+* Unable to start the search, because some double-bounded variables
+* have incorrect bounds or some integer variables have non-integer
+* (fractional) bounds.
+*
+* GLP_EROOT
+* Unable to start the search, because optimal basis for initial LP
+* relaxation is not provided.
+*
+* GLP_EFAIL
+* The search was prematurely terminated due to the solver failure.
+*
+* GLP_EMIPGAP
+* The search was prematurely terminated, because the relative mip
+* gap tolerance has been reached.
+*
+* GLP_ETMLIM
+* The search was prematurely terminated, because the time limit has
+* been exceeded.
+*
+* GLP_ENOPFS
+* The MIP problem instance has no primal feasible solution (only if
+* the MIP presolver is used).
+*
+* GLP_ENODFS
+* LP relaxation of the MIP problem instance has no dual feasible
+* solution (only if the MIP presolver is used).
+*
+* GLP_ESTOP
+* The search was prematurely terminated by application. */
+
+#if 0 /* 11/VII-2013 */
+static int solve_mip(glp_prob *P, const glp_iocp *parm)
+#else
+static int solve_mip(glp_prob *P, const glp_iocp *parm,
+ glp_prob *P0 /* problem passed to glp_intopt */,
+ NPP *npp /* preprocessor workspace or NULL */)
+#endif
+{ /* solve MIP directly without using the preprocessor */
+ glp_tree *T;
+ int ret;
+ /* optimal basis to LP relaxation must be provided */
+ if (glp_get_status(P) != GLP_OPT)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_intopt: optimal basis to initial LP relaxation"
+ " not provided\n");
+ ret = GLP_EROOT;
+ goto done;
+ }
+ /* it seems all is ok */
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Integer optimization begins...\n");
+ /* create the branch-and-bound tree */
+ T = ios_create_tree(P, parm);
+#if 1 /* 11/VII-2013 */
+ T->P = P0;
+ T->npp = npp;
+#endif
+ /* solve the problem instance */
+ ret = ios_driver(T);
+ /* delete the branch-and-bound tree */
+ ios_delete_tree(T);
+ /* analyze exit code reported by the mip driver */
+ if (ret == 0)
+ { if (P->mip_stat == GLP_FEAS)
+ { if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("INTEGER OPTIMAL SOLUTION FOUND\n");
+ P->mip_stat = GLP_OPT;
+ }
+ else
+ { if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n");
+ P->mip_stat = GLP_NOFEAS;
+ }
+ }
+ else if (ret == GLP_EMIPGAP)
+ { if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("RELATIVE MIP GAP TOLERANCE REACHED; SEARCH TERMINA"
+ "TED\n");
+ }
+ else if (ret == GLP_ETMLIM)
+ { if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+ }
+ else if (ret == GLP_EFAIL)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_intopt: cannot solve current LP relaxation\n");
+ }
+ else if (ret == GLP_ESTOP)
+ { if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("SEARCH TERMINATED BY APPLICATION\n");
+ }
+ else
+ xassert(ret != ret);
+done: return ret;
+}
+
+static int preprocess_and_solve_mip(glp_prob *P, const glp_iocp *parm)
+{ /* solve MIP using the preprocessor */
+ ENV *env = get_env_ptr();
+ int term_out = env->term_out;
+ NPP *npp;
+ glp_prob *mip = NULL;
+ glp_bfcp bfcp;
+ glp_smcp smcp;
+ int ret;
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Preprocessing...\n");
+ /* create preprocessor workspace */
+ npp = npp_create_wksp();
+ /* load original problem into the preprocessor workspace */
+ npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF);
+ /* process MIP prior to applying the branch-and-bound method */
+ if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+ env->term_out = GLP_OFF;
+ else
+ env->term_out = GLP_ON;
+ ret = npp_integer(npp, parm);
+ env->term_out = term_out;
+ if (ret == 0)
+ ;
+ else if (ret == GLP_ENOPFS)
+ { if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
+ }
+ else if (ret == GLP_ENODFS)
+ { if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("LP RELAXATION HAS NO DUAL FEASIBLE SOLUTION\n");
+ }
+ else
+ xassert(ret != ret);
+ if (ret != 0) goto done;
+ /* build transformed MIP */
+ mip = glp_create_prob();
+ npp_build_prob(npp, mip);
+ /* if the transformed MIP is empty, it has empty solution, which
+ is optimal */
+ if (mip->m == 0 && mip->n == 0)
+ { mip->mip_stat = GLP_OPT;
+ mip->mip_obj = mip->c0;
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ { xprintf("Objective value = %17.9e\n", mip->mip_obj);
+ xprintf("INTEGER OPTIMAL SOLUTION FOUND BY MIP PREPROCESSOR"
+ "\n");
+ }
+ goto post;
+ }
+ /* display some statistics */
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ { int ni = glp_get_num_int(mip);
+ int nb = glp_get_num_bin(mip);
+ char s[50];
+ xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+ mip->m, mip->m == 1 ? "" : "s", mip->n, mip->n == 1 ? "" :
+ "s", mip->nnz, mip->nnz == 1 ? "" : "s");
+ if (nb == 0)
+ strcpy(s, "none of");
+ else if (ni == 1 && nb == 1)
+ strcpy(s, "");
+ else if (nb == 1)
+ strcpy(s, "one of");
+ else if (nb == ni)
+ strcpy(s, "all of");
+ else
+ sprintf(s, "%d of", nb);
+ xprintf("%d integer variable%s, %s which %s binary\n",
+ ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
+ }
+ /* inherit basis factorization control parameters */
+ glp_get_bfcp(P, &bfcp);
+ glp_set_bfcp(mip, &bfcp);
+ /* scale the transformed problem */
+ if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+ env->term_out = GLP_OFF;
+ else
+ env->term_out = GLP_ON;
+ glp_scale_prob(mip,
+ GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP);
+ env->term_out = term_out;
+ /* build advanced initial basis */
+ if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+ env->term_out = GLP_OFF;
+ else
+ env->term_out = GLP_ON;
+ glp_adv_basis(mip, 0);
+ env->term_out = term_out;
+ /* solve initial LP relaxation */
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Solving LP relaxation...\n");
+ glp_init_smcp(&smcp);
+ smcp.msg_lev = parm->msg_lev;
+ /* respect time limit */
+ smcp.tm_lim = parm->tm_lim;
+ mip->it_cnt = P->it_cnt;
+ ret = glp_simplex(mip, &smcp);
+ P->it_cnt = mip->it_cnt;
+ if (ret == GLP_ETMLIM)
+ goto done;
+ else if (ret != 0)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_intopt: cannot solve LP relaxation\n");
+ ret = GLP_EFAIL;
+ goto done;
+ }
+ /* check status of the basic solution */
+ ret = glp_get_status(mip);
+ if (ret == GLP_OPT)
+ ret = 0;
+ else if (ret == GLP_NOFEAS)
+ ret = GLP_ENOPFS;
+ else if (ret == GLP_UNBND)
+ ret = GLP_ENODFS;
+ else
+ xassert(ret != ret);
+ if (ret != 0) goto done;
+ /* solve the transformed MIP */
+ mip->it_cnt = P->it_cnt;
+#if 0 /* 11/VII-2013 */
+ ret = solve_mip(mip, parm);
+#else
+ if (parm->use_sol)
+ { mip->mip_stat = P->mip_stat;
+ mip->mip_obj = P->mip_obj;
+ }
+ ret = solve_mip(mip, parm, P, npp);
+#endif
+ P->it_cnt = mip->it_cnt;
+ /* only integer feasible solution can be postprocessed */
+ if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS))
+ { P->mip_stat = mip->mip_stat;
+ goto done;
+ }
+ /* postprocess solution from the transformed MIP */
+post: npp_postprocess(npp, mip);
+ /* the transformed MIP is no longer needed */
+ glp_delete_prob(mip), mip = NULL;
+ /* store solution to the original problem */
+ npp_unload_sol(npp, P);
+done: /* delete the transformed MIP, if it exists */
+ if (mip != NULL) glp_delete_prob(mip);
+ /* delete preprocessor workspace */
+ npp_delete_wksp(npp);
+ return ret;
+}
+
+#ifndef HAVE_ALIEN_SOLVER /* 28/V-2010 */
+int _glp_intopt1(glp_prob *P, const glp_iocp *parm)
+{ xassert(P == P);
+ xassert(parm == parm);
+ xprintf("glp_intopt: no alien solver is available\n");
+ return GLP_EFAIL;
+}
+#endif
+
+int glp_intopt(glp_prob *P, const glp_iocp *parm)
+{ /* solve MIP problem with the branch-and-bound method */
+ glp_iocp _parm;
+ int i, j, ret;
+#if 0 /* 04/IV-2016 */
+ /* check problem object */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_intopt: P = %p; invalid problem object\n", P);
+#endif
+ if (P->tree != NULL)
+ xerror("glp_intopt: operation not allowed\n");
+ /* check control parameters */
+ if (parm == NULL)
+ parm = &_parm, glp_init_iocp((glp_iocp *)parm);
+ if (!(parm->msg_lev == GLP_MSG_OFF ||
+ parm->msg_lev == GLP_MSG_ERR ||
+ parm->msg_lev == GLP_MSG_ON ||
+ parm->msg_lev == GLP_MSG_ALL ||
+ parm->msg_lev == GLP_MSG_DBG))
+ xerror("glp_intopt: msg_lev = %d; invalid parameter\n",
+ parm->msg_lev);
+ if (!(parm->br_tech == GLP_BR_FFV ||
+ parm->br_tech == GLP_BR_LFV ||
+ parm->br_tech == GLP_BR_MFV ||
+ parm->br_tech == GLP_BR_DTH ||
+ parm->br_tech == GLP_BR_PCH))
+ xerror("glp_intopt: br_tech = %d; invalid parameter\n",
+ parm->br_tech);
+ if (!(parm->bt_tech == GLP_BT_DFS ||
+ parm->bt_tech == GLP_BT_BFS ||
+ parm->bt_tech == GLP_BT_BLB ||
+ parm->bt_tech == GLP_BT_BPH))
+ xerror("glp_intopt: bt_tech = %d; invalid parameter\n",
+ parm->bt_tech);
+ if (!(0.0 < parm->tol_int && parm->tol_int < 1.0))
+ xerror("glp_intopt: tol_int = %g; invalid parameter\n",
+ parm->tol_int);
+ if (!(0.0 < parm->tol_obj && parm->tol_obj < 1.0))
+ xerror("glp_intopt: tol_obj = %g; invalid parameter\n",
+ parm->tol_obj);
+ if (parm->tm_lim < 0)
+ xerror("glp_intopt: tm_lim = %d; invalid parameter\n",
+ parm->tm_lim);
+ if (parm->out_frq < 0)
+ xerror("glp_intopt: out_frq = %d; invalid parameter\n",
+ parm->out_frq);
+ if (parm->out_dly < 0)
+ xerror("glp_intopt: out_dly = %d; invalid parameter\n",
+ parm->out_dly);
+ if (!(0 <= parm->cb_size && parm->cb_size <= 256))
+ xerror("glp_intopt: cb_size = %d; invalid parameter\n",
+ parm->cb_size);
+ if (!(parm->pp_tech == GLP_PP_NONE ||
+ parm->pp_tech == GLP_PP_ROOT ||
+ parm->pp_tech == GLP_PP_ALL))
+ xerror("glp_intopt: pp_tech = %d; invalid parameter\n",
+ parm->pp_tech);
+ if (parm->mip_gap < 0.0)
+ xerror("glp_intopt: mip_gap = %g; invalid parameter\n",
+ parm->mip_gap);
+ if (!(parm->mir_cuts == GLP_ON || parm->mir_cuts == GLP_OFF))
+ xerror("glp_intopt: mir_cuts = %d; invalid parameter\n",
+ parm->mir_cuts);
+ if (!(parm->gmi_cuts == GLP_ON || parm->gmi_cuts == GLP_OFF))
+ xerror("glp_intopt: gmi_cuts = %d; invalid parameter\n",
+ parm->gmi_cuts);
+ if (!(parm->cov_cuts == GLP_ON || parm->cov_cuts == GLP_OFF))
+ xerror("glp_intopt: cov_cuts = %d; invalid parameter\n",
+ parm->cov_cuts);
+ if (!(parm->clq_cuts == GLP_ON || parm->clq_cuts == GLP_OFF))
+ xerror("glp_intopt: clq_cuts = %d; invalid parameter\n",
+ parm->clq_cuts);
+ if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
+ xerror("glp_intopt: presolve = %d; invalid parameter\n",
+ parm->presolve);
+ if (!(parm->binarize == GLP_ON || parm->binarize == GLP_OFF))
+ xerror("glp_intopt: binarize = %d; invalid parameter\n",
+ parm->binarize);
+ if (!(parm->fp_heur == GLP_ON || parm->fp_heur == GLP_OFF))
+ xerror("glp_intopt: fp_heur = %d; invalid parameter\n",
+ parm->fp_heur);
+#if 1 /* 28/V-2010 */
+ if (!(parm->alien == GLP_ON || parm->alien == GLP_OFF))
+ xerror("glp_intopt: alien = %d; invalid parameter\n",
+ parm->alien);
+#endif
+#if 0 /* 11/VII-2013 */
+ /* integer solution is currently undefined */
+ P->mip_stat = GLP_UNDEF;
+ P->mip_obj = 0.0;
+#else
+ if (!parm->use_sol)
+ P->mip_stat = GLP_UNDEF;
+ if (P->mip_stat == GLP_NOFEAS)
+ P->mip_stat = GLP_UNDEF;
+ if (P->mip_stat == GLP_UNDEF)
+ P->mip_obj = 0.0;
+ else if (P->mip_stat == GLP_OPT)
+ P->mip_stat = GLP_FEAS;
+#endif
+ /* check bounds of double-bounded variables */
+ for (i = 1; i <= P->m; i++)
+ { GLPROW *row = P->row[i];
+ if (row->type == GLP_DB && row->lb >= row->ub)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_intopt: row %d: lb = %g, ub = %g; incorrect"
+ " bounds\n", i, row->lb, row->ub);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ for (j = 1; j <= P->n; j++)
+ { GLPCOL *col = P->col[j];
+ if (col->type == GLP_DB && col->lb >= col->ub)
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_intopt: column %d: lb = %g, ub = %g; incorr"
+ "ect bounds\n", j, col->lb, col->ub);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ /* bounds of all integer variables must be integral */
+ for (j = 1; j <= P->n; j++)
+ { GLPCOL *col = P->col[j];
+ if (col->kind != GLP_IV) continue;
+ if (col->type == GLP_LO || col->type == GLP_DB)
+ { if (col->lb != floor(col->lb))
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_intopt: integer column %d has non-intege"
+ "r lower bound %g\n", j, col->lb);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ if (col->type == GLP_UP || col->type == GLP_DB)
+ { if (col->ub != floor(col->ub))
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_intopt: integer column %d has non-intege"
+ "r upper bound %g\n", j, col->ub);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ if (col->type == GLP_FX)
+ { if (col->lb != floor(col->lb))
+ { if (parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("glp_intopt: integer column %d has non-intege"
+ "r fixed value %g\n", j, col->lb);
+ ret = GLP_EBOUND;
+ goto done;
+ }
+ }
+ }
+ /* solve MIP problem */
+ if (parm->msg_lev >= GLP_MSG_ALL)
+ { int ni = glp_get_num_int(P);
+ int nb = glp_get_num_bin(P);
+ char s[50];
+ xprintf("GLPK Integer Optimizer, v%s\n", glp_version());
+ xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+ P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+ P->nnz, P->nnz == 1 ? "" : "s");
+ if (nb == 0)
+ strcpy(s, "none of");
+ else if (ni == 1 && nb == 1)
+ strcpy(s, "");
+ else if (nb == 1)
+ strcpy(s, "one of");
+ else if (nb == ni)
+ strcpy(s, "all of");
+ else
+ sprintf(s, "%d of", nb);
+ xprintf("%d integer variable%s, %s which %s binary\n",
+ ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
+ }
+#if 1 /* 28/V-2010 */
+ if (parm->alien)
+ { /* use alien integer optimizer */
+ ret = _glp_intopt1(P, parm);
+ goto done;
+ }
+#endif
+ if (!parm->presolve)
+#if 0 /* 11/VII-2013 */
+ ret = solve_mip(P, parm);
+#else
+ ret = solve_mip(P, parm, P, NULL);
+#endif
+ else
+ ret = preprocess_and_solve_mip(P, parm);
+#if 1 /* 12/III-2013 */
+ if (ret == GLP_ENOPFS)
+ P->mip_stat = GLP_NOFEAS;
+#endif
+done: /* return to the application program */
+ return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_init_iocp - initialize integer optimizer control parameters
+*
+* SYNOPSIS
+*
+* void glp_init_iocp(glp_iocp *parm);
+*
+* DESCRIPTION
+*
+* The routine glp_init_iocp initializes control parameters, which are
+* used by the integer optimizer, with default values.
+*
+* Default values of the control parameters are stored in a glp_iocp
+* structure, which the parameter parm points to. */
+
+void glp_init_iocp(glp_iocp *parm)
+{ parm->msg_lev = GLP_MSG_ALL;
+ parm->br_tech = GLP_BR_DTH;
+ parm->bt_tech = GLP_BT_BLB;
+ parm->tol_int = 1e-5;
+ parm->tol_obj = 1e-7;
+ parm->tm_lim = INT_MAX;
+ parm->out_frq = 5000;
+ parm->out_dly = 10000;
+ parm->cb_func = NULL;
+ parm->cb_info = NULL;
+ parm->cb_size = 0;
+ parm->pp_tech = GLP_PP_ALL;
+ parm->mip_gap = 0.0;
+ parm->mir_cuts = GLP_OFF;
+ parm->gmi_cuts = GLP_OFF;
+ parm->cov_cuts = GLP_OFF;
+ parm->clq_cuts = GLP_OFF;
+ parm->presolve = GLP_OFF;
+ parm->binarize = GLP_OFF;
+ parm->fp_heur = GLP_OFF;
+ parm->ps_heur = GLP_OFF;
+ parm->ps_tm_lim = 60000; /* 1 minute */
+ parm->sr_heur = GLP_ON;
+#if 1 /* 24/X-2015; not documented--should not be used */
+ parm->use_sol = GLP_OFF;
+ parm->save_sol = NULL;
+ parm->alien = GLP_OFF;
+#endif
+#if 0 /* 20/I-2018 */
+#if 1 /* 16/III-2016; not documented--should not be used */
+ parm->flip = GLP_OFF;
+#endif
+#else
+ parm->flip = GLP_ON;
+#endif
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_mip_status - retrieve status of MIP solution
+*
+* SYNOPSIS
+*
+* int glp_mip_status(glp_prob *mip);
+*
+* RETURNS
+*
+* The routine lpx_mip_status reports the status of MIP solution found
+* by the branch-and-bound solver as follows:
+*
+* GLP_UNDEF - MIP solution is undefined;
+* GLP_OPT - MIP solution is integer optimal;
+* GLP_FEAS - MIP solution is integer feasible but its optimality
+* (or non-optimality) has not been proven, perhaps due to
+* premature termination of the search;
+* GLP_NOFEAS - problem has no integer feasible solution (proven by the
+* solver). */
+
+int glp_mip_status(glp_prob *mip)
+{ int mip_stat = mip->mip_stat;
+ return mip_stat;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_mip_obj_val - retrieve objective value (MIP solution)
+*
+* SYNOPSIS
+*
+* double glp_mip_obj_val(glp_prob *mip);
+*
+* RETURNS
+*
+* The routine glp_mip_obj_val returns value of the objective function
+* for MIP solution. */
+
+double glp_mip_obj_val(glp_prob *mip)
+{ /*struct LPXCPS *cps = mip->cps;*/
+ double z;
+ z = mip->mip_obj;
+ /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
+ return z;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_mip_row_val - retrieve row value (MIP solution)
+*
+* SYNOPSIS
+*
+* double glp_mip_row_val(glp_prob *mip, int i);
+*
+* RETURNS
+*
+* The routine glp_mip_row_val returns value of the auxiliary variable
+* associated with i-th row. */
+
+double glp_mip_row_val(glp_prob *mip, int i)
+{ /*struct LPXCPS *cps = mip->cps;*/
+ double mipx;
+ if (!(1 <= i && i <= mip->m))
+ xerror("glp_mip_row_val: i = %d; row number out of range\n", i)
+ ;
+ mipx = mip->row[i]->mipx;
+ /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
+ return mipx;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_mip_col_val - retrieve column value (MIP solution)
+*
+* SYNOPSIS
+*
+* double glp_mip_col_val(glp_prob *mip, int j);
+*
+* RETURNS
+*
+* The routine glp_mip_col_val returns value of the structural variable
+* associated with j-th column. */
+
+double glp_mip_col_val(glp_prob *mip, int j)
+{ /*struct LPXCPS *cps = mip->cps;*/
+ double mipx;
+ if (!(1 <= j && j <= mip->n))
+ xerror("glp_mip_col_val: j = %d; column number out of range\n",
+ j);
+ mipx = mip->col[j]->mipx;
+ /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
+ return mipx;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpapi10.c b/test/monniaux/glpk-4.65/src/draft/glpapi10.c
new file mode 100644
index 00000000..5550aa39
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpapi10.c
@@ -0,0 +1,305 @@
+/* glpapi10.c (solution checking routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+void glp_check_kkt(glp_prob *P, int sol, int cond, double *_ae_max,
+ int *_ae_ind, double *_re_max, int *_re_ind)
+{ /* check feasibility and optimality conditions */
+ int m = P->m;
+ int n = P->n;
+ GLPROW *row;
+ GLPCOL *col;
+ GLPAIJ *aij;
+ int i, j, ae_ind, re_ind;
+ double e, sp, sn, t, ae_max, re_max;
+ if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
+ xerror("glp_check_kkt: sol = %d; invalid solution indicator\n",
+ sol);
+ if (!(cond == GLP_KKT_PE || cond == GLP_KKT_PB ||
+ cond == GLP_KKT_DE || cond == GLP_KKT_DB ||
+ cond == GLP_KKT_CS))
+ xerror("glp_check_kkt: cond = %d; invalid condition indicator "
+ "\n", cond);
+ ae_max = re_max = 0.0;
+ ae_ind = re_ind = 0;
+ if (cond == GLP_KKT_PE)
+ { /* xR - A * xS = 0 */
+ for (i = 1; i <= m; i++)
+ { row = P->row[i];
+ sp = sn = 0.0;
+ /* t := xR[i] */
+ if (sol == GLP_SOL)
+ t = row->prim;
+ else if (sol == GLP_IPT)
+ t = row->pval;
+ else if (sol == GLP_MIP)
+ t = row->mipx;
+ else
+ xassert(sol != sol);
+ if (t >= 0.0) sp += t; else sn -= t;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ /* t := - a[i,j] * xS[j] */
+ if (sol == GLP_SOL)
+ t = - aij->val * col->prim;
+ else if (sol == GLP_IPT)
+ t = - aij->val * col->pval;
+ else if (sol == GLP_MIP)
+ t = - aij->val * col->mipx;
+ else
+ xassert(sol != sol);
+ if (t >= 0.0) sp += t; else sn -= t;
+ }
+ /* absolute error */
+ e = fabs(sp - sn);
+ if (ae_max < e)
+ ae_max = e, ae_ind = i;
+ /* relative error */
+ e /= (1.0 + sp + sn);
+ if (re_max < e)
+ re_max = e, re_ind = i;
+ }
+ }
+ else if (cond == GLP_KKT_PB)
+ { /* lR <= xR <= uR */
+ for (i = 1; i <= m; i++)
+ { row = P->row[i];
+ /* t := xR[i] */
+ if (sol == GLP_SOL)
+ t = row->prim;
+ else if (sol == GLP_IPT)
+ t = row->pval;
+ else if (sol == GLP_MIP)
+ t = row->mipx;
+ else
+ xassert(sol != sol);
+ /* check lower bound */
+ if (row->type == GLP_LO || row->type == GLP_DB ||
+ row->type == GLP_FX)
+ { if (t < row->lb)
+ { /* absolute error */
+ e = row->lb - t;
+ if (ae_max < e)
+ ae_max = e, ae_ind = i;
+ /* relative error */
+ e /= (1.0 + fabs(row->lb));
+ if (re_max < e)
+ re_max = e, re_ind = i;
+ }
+ }
+ /* check upper bound */
+ if (row->type == GLP_UP || row->type == GLP_DB ||
+ row->type == GLP_FX)
+ { if (t > row->ub)
+ { /* absolute error */
+ e = t - row->ub;
+ if (ae_max < e)
+ ae_max = e, ae_ind = i;
+ /* relative error */
+ e /= (1.0 + fabs(row->ub));
+ if (re_max < e)
+ re_max = e, re_ind = i;
+ }
+ }
+ }
+ /* lS <= xS <= uS */
+ for (j = 1; j <= n; j++)
+ { col = P->col[j];
+ /* t := xS[j] */
+ if (sol == GLP_SOL)
+ t = col->prim;
+ else if (sol == GLP_IPT)
+ t = col->pval;
+ else if (sol == GLP_MIP)
+ t = col->mipx;
+ else
+ xassert(sol != sol);
+ /* check lower bound */
+ if (col->type == GLP_LO || col->type == GLP_DB ||
+ col->type == GLP_FX)
+ { if (t < col->lb)
+ { /* absolute error */
+ e = col->lb - t;
+ if (ae_max < e)
+ ae_max = e, ae_ind = m+j;
+ /* relative error */
+ e /= (1.0 + fabs(col->lb));
+ if (re_max < e)
+ re_max = e, re_ind = m+j;
+ }
+ }
+ /* check upper bound */
+ if (col->type == GLP_UP || col->type == GLP_DB ||
+ col->type == GLP_FX)
+ { if (t > col->ub)
+ { /* absolute error */
+ e = t - col->ub;
+ if (ae_max < e)
+ ae_max = e, ae_ind = m+j;
+ /* relative error */
+ e /= (1.0 + fabs(col->ub));
+ if (re_max < e)
+ re_max = e, re_ind = m+j;
+ }
+ }
+ }
+ }
+ else if (cond == GLP_KKT_DE)
+ { /* A' * (lambdaR - cR) + (lambdaS - cS) = 0 */
+ for (j = 1; j <= n; j++)
+ { col = P->col[j];
+ sp = sn = 0.0;
+ /* t := lambdaS[j] - cS[j] */
+ if (sol == GLP_SOL)
+ t = col->dual - col->coef;
+ else if (sol == GLP_IPT)
+ t = col->dval - col->coef;
+ else
+ xassert(sol != sol);
+ if (t >= 0.0) sp += t; else sn -= t;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ { row = aij->row;
+ /* t := a[i,j] * (lambdaR[i] - cR[i]) */
+ if (sol == GLP_SOL)
+ t = aij->val * row->dual;
+ else if (sol == GLP_IPT)
+ t = aij->val * row->dval;
+ else
+ xassert(sol != sol);
+ if (t >= 0.0) sp += t; else sn -= t;
+ }
+ /* absolute error */
+ e = fabs(sp - sn);
+ if (ae_max < e)
+ ae_max = e, ae_ind = m+j;
+ /* relative error */
+ e /= (1.0 + sp + sn);
+ if (re_max < e)
+ re_max = e, re_ind = m+j;
+ }
+ }
+ else if (cond == GLP_KKT_DB)
+ { /* check lambdaR */
+ for (i = 1; i <= m; i++)
+ { row = P->row[i];
+ /* t := lambdaR[i] */
+ if (sol == GLP_SOL)
+ t = row->dual;
+ else if (sol == GLP_IPT)
+ t = row->dval;
+ else
+ xassert(sol != sol);
+ /* correct sign */
+ if (P->dir == GLP_MIN)
+ t = + t;
+ else if (P->dir == GLP_MAX)
+ t = - t;
+ else
+ xassert(P != P);
+ /* check for positivity */
+#if 1 /* 08/III-2013 */
+ /* the former check was correct */
+ /* the bug reported by David Price is related to violation
+ of complementarity slackness, not to this condition */
+ if (row->type == GLP_FR || row->type == GLP_LO)
+#else
+ if (row->stat == GLP_NF || row->stat == GLP_NL)
+#endif
+ { if (t < 0.0)
+ { e = - t;
+ if (ae_max < e)
+ ae_max = re_max = e, ae_ind = re_ind = i;
+ }
+ }
+ /* check for negativity */
+#if 1 /* 08/III-2013 */
+ /* see comment above */
+ if (row->type == GLP_FR || row->type == GLP_UP)
+#else
+ if (row->stat == GLP_NF || row->stat == GLP_NU)
+#endif
+ { if (t > 0.0)
+ { e = + t;
+ if (ae_max < e)
+ ae_max = re_max = e, ae_ind = re_ind = i;
+ }
+ }
+ }
+ /* check lambdaS */
+ for (j = 1; j <= n; j++)
+ { col = P->col[j];
+ /* t := lambdaS[j] */
+ if (sol == GLP_SOL)
+ t = col->dual;
+ else if (sol == GLP_IPT)
+ t = col->dval;
+ else
+ xassert(sol != sol);
+ /* correct sign */
+ if (P->dir == GLP_MIN)
+ t = + t;
+ else if (P->dir == GLP_MAX)
+ t = - t;
+ else
+ xassert(P != P);
+ /* check for positivity */
+#if 1 /* 08/III-2013 */
+ /* see comment above */
+ if (col->type == GLP_FR || col->type == GLP_LO)
+#else
+ if (col->stat == GLP_NF || col->stat == GLP_NL)
+#endif
+ { if (t < 0.0)
+ { e = - t;
+ if (ae_max < e)
+ ae_max = re_max = e, ae_ind = re_ind = m+j;
+ }
+ }
+ /* check for negativity */
+#if 1 /* 08/III-2013 */
+ /* see comment above */
+ if (col->type == GLP_FR || col->type == GLP_UP)
+#else
+ if (col->stat == GLP_NF || col->stat == GLP_NU)
+#endif
+ { if (t > 0.0)
+ { e = + t;
+ if (ae_max < e)
+ ae_max = re_max = e, ae_ind = re_ind = m+j;
+ }
+ }
+ }
+ }
+ else
+ xassert(cond != cond);
+ if (_ae_max != NULL) *_ae_max = ae_max;
+ if (_ae_ind != NULL) *_ae_ind = ae_ind;
+ if (_re_max != NULL) *_re_max = re_max;
+ if (_re_ind != NULL) *_re_ind = re_ind;
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpapi12.c b/test/monniaux/glpk-4.65/src/draft/glpapi12.c
new file mode 100644
index 00000000..020c8981
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpapi12.c
@@ -0,0 +1,2185 @@
+/* glpapi12.c (basis factorization and simplex tableau routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#include "draft.h"
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_bf_exists - check if the basis factorization exists
+*
+* SYNOPSIS
+*
+* int glp_bf_exists(glp_prob *lp);
+*
+* RETURNS
+*
+* If the basis factorization for the current basis associated with
+* the specified problem object exists and therefore is available for
+* computations, the routine glp_bf_exists returns non-zero. Otherwise
+* the routine returns zero. */
+
+int glp_bf_exists(glp_prob *lp)
+{ int ret;
+ ret = (lp->m == 0 || lp->valid);
+ return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_factorize - compute the basis factorization
+*
+* SYNOPSIS
+*
+* int glp_factorize(glp_prob *lp);
+*
+* DESCRIPTION
+*
+* The routine glp_factorize computes the basis factorization for the
+* current basis associated with the specified problem object.
+*
+* RETURNS
+*
+* 0 The basis factorization has been successfully computed.
+*
+* GLP_EBADB
+* The basis matrix is invalid, i.e. the number of basic (auxiliary
+* and structural) variables differs from the number of rows in the
+* problem object.
+*
+* GLP_ESING
+* The basis matrix is singular within the working precision.
+*
+* GLP_ECOND
+* The basis matrix is ill-conditioned. */
+
+static int b_col(void *info, int j, int ind[], double val[])
+{ glp_prob *lp = info;
+ int m = lp->m;
+ GLPAIJ *aij;
+ int k, len;
+ xassert(1 <= j && j <= m);
+ /* determine the ordinal number of basic auxiliary or structural
+ variable x[k] corresponding to basic variable xB[j] */
+ k = lp->head[j];
+ /* build j-th column of the basic matrix, which is k-th column of
+ the scaled augmented matrix (I | -R*A*S) */
+ if (k <= m)
+ { /* x[k] is auxiliary variable */
+ len = 1;
+ ind[1] = k;
+ val[1] = 1.0;
+ }
+ else
+ { /* x[k] is structural variable */
+ len = 0;
+ for (aij = lp->col[k-m]->ptr; aij != NULL; aij = aij->c_next)
+ { len++;
+ ind[len] = aij->row->i;
+ val[len] = - aij->row->rii * aij->val * aij->col->sjj;
+ }
+ }
+ return len;
+}
+
+int glp_factorize(glp_prob *lp)
+{ int m = lp->m;
+ int n = lp->n;
+ GLPROW **row = lp->row;
+ GLPCOL **col = lp->col;
+ int *head = lp->head;
+ int j, k, stat, ret;
+ /* invalidate the basis factorization */
+ lp->valid = 0;
+ /* build the basis header */
+ j = 0;
+ for (k = 1; k <= m+n; k++)
+ { if (k <= m)
+ { stat = row[k]->stat;
+ row[k]->bind = 0;
+ }
+ else
+ { stat = col[k-m]->stat;
+ col[k-m]->bind = 0;
+ }
+ if (stat == GLP_BS)
+ { j++;
+ if (j > m)
+ { /* too many basic variables */
+ ret = GLP_EBADB;
+ goto fini;
+ }
+ head[j] = k;
+ if (k <= m)
+ row[k]->bind = j;
+ else
+ col[k-m]->bind = j;
+ }
+ }
+ if (j < m)
+ { /* too few basic variables */
+ ret = GLP_EBADB;
+ goto fini;
+ }
+ /* try to factorize the basis matrix */
+ if (m > 0)
+ { if (lp->bfd == NULL)
+ { lp->bfd = bfd_create_it();
+#if 0 /* 08/III-2014 */
+ copy_bfcp(lp);
+#endif
+ }
+ switch (bfd_factorize(lp->bfd, m, /*lp->head,*/ b_col, lp))
+ { case 0:
+ /* ok */
+ break;
+ case BFD_ESING:
+ /* singular matrix */
+ ret = GLP_ESING;
+ goto fini;
+ case BFD_ECOND:
+ /* ill-conditioned matrix */
+ ret = GLP_ECOND;
+ goto fini;
+ default:
+ xassert(lp != lp);
+ }
+ lp->valid = 1;
+ }
+ /* factorization successful */
+ ret = 0;
+fini: /* bring the return code to the calling program */
+ return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_bf_updated - check if the basis factorization has been updated
+*
+* SYNOPSIS
+*
+* int glp_bf_updated(glp_prob *lp);
+*
+* RETURNS
+*
+* If the basis factorization has been just computed from scratch, the
+* routine glp_bf_updated returns zero. Otherwise, if the factorization
+* has been updated one or more times, the routine returns non-zero. */
+
+int glp_bf_updated(glp_prob *lp)
+{ int cnt;
+ if (!(lp->m == 0 || lp->valid))
+ xerror("glp_bf_update: basis factorization does not exist\n");
+#if 0 /* 15/XI-2009 */
+ cnt = (lp->m == 0 ? 0 : lp->bfd->upd_cnt);
+#else
+ cnt = (lp->m == 0 ? 0 : bfd_get_count(lp->bfd));
+#endif
+ return cnt;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_bfcp - retrieve basis factorization control parameters
+*
+* SYNOPSIS
+*
+* void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm);
+*
+* DESCRIPTION
+*
+* The routine glp_get_bfcp retrieves control parameters, which are
+* used on computing and updating the basis factorization associated
+* with the specified problem object.
+*
+* Current values of control parameters are stored by the routine in
+* a glp_bfcp structure, which the parameter parm points to. */
+
+#if 1 /* 08/III-2014 */
+void glp_get_bfcp(glp_prob *P, glp_bfcp *parm)
+{ if (P->bfd == NULL)
+ P->bfd = bfd_create_it();
+ bfd_get_bfcp(P->bfd, parm);
+ return;
+}
+#endif
+
+/***********************************************************************
+* NAME
+*
+* glp_set_bfcp - change basis factorization control parameters
+*
+* SYNOPSIS
+*
+* void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm);
+*
+* DESCRIPTION
+*
+* The routine glp_set_bfcp changes control parameters, which are used
+* by internal GLPK routines in computing and updating the basis
+* factorization associated with the specified problem object.
+*
+* New values of the control parameters should be passed in a structure
+* glp_bfcp, which the parameter parm points to.
+*
+* The parameter parm can be specified as NULL, in which case all
+* control parameters are reset to their default values. */
+
+#if 1 /* 08/III-2014 */
+void glp_set_bfcp(glp_prob *P, const glp_bfcp *parm)
+{ if (P->bfd == NULL)
+ P->bfd = bfd_create_it();
+ if (parm != NULL)
+ { if (!(parm->type == GLP_BF_LUF + GLP_BF_FT ||
+ parm->type == GLP_BF_LUF + GLP_BF_BG ||
+ parm->type == GLP_BF_LUF + GLP_BF_GR ||
+ parm->type == GLP_BF_BTF + GLP_BF_BG ||
+ parm->type == GLP_BF_BTF + GLP_BF_GR))
+ xerror("glp_set_bfcp: type = 0x%02X; invalid parameter\n",
+ parm->type);
+ if (!(0.0 < parm->piv_tol && parm->piv_tol < 1.0))
+ xerror("glp_set_bfcp: piv_tol = %g; invalid parameter\n",
+ parm->piv_tol);
+ if (parm->piv_lim < 1)
+ xerror("glp_set_bfcp: piv_lim = %d; invalid parameter\n",
+ parm->piv_lim);
+ if (!(parm->suhl == GLP_ON || parm->suhl == GLP_OFF))
+ xerror("glp_set_bfcp: suhl = %d; invalid parameter\n",
+ parm->suhl);
+ if (!(0.0 <= parm->eps_tol && parm->eps_tol <= 1e-6))
+ xerror("glp_set_bfcp: eps_tol = %g; invalid parameter\n",
+ parm->eps_tol);
+ if (!(1 <= parm->nfs_max && parm->nfs_max <= 32767))
+ xerror("glp_set_bfcp: nfs_max = %d; invalid parameter\n",
+ parm->nfs_max);
+ if (!(1 <= parm->nrs_max && parm->nrs_max <= 32767))
+ xerror("glp_set_bfcp: nrs_max = %d; invalid parameter\n",
+ parm->nrs_max);
+ }
+ bfd_set_bfcp(P->bfd, parm);
+ return;
+}
+#endif
+
+/***********************************************************************
+* NAME
+*
+* glp_get_bhead - retrieve the basis header information
+*
+* SYNOPSIS
+*
+* int glp_get_bhead(glp_prob *lp, int k);
+*
+* DESCRIPTION
+*
+* The routine glp_get_bhead returns the basis header information for
+* the current basis associated with the specified problem object.
+*
+* RETURNS
+*
+* If xB[k], 1 <= k <= m, is i-th auxiliary variable (1 <= i <= m), the
+* routine returns i. Otherwise, if xB[k] is j-th structural variable
+* (1 <= j <= n), the routine returns m+j. Here m is the number of rows
+* and n is the number of columns in the problem object. */
+
+int glp_get_bhead(glp_prob *lp, int k)
+{ if (!(lp->m == 0 || lp->valid))
+ xerror("glp_get_bhead: basis factorization does not exist\n");
+ if (!(1 <= k && k <= lp->m))
+ xerror("glp_get_bhead: k = %d; index out of range\n", k);
+ return lp->head[k];
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_row_bind - retrieve row index in the basis header
+*
+* SYNOPSIS
+*
+* int glp_get_row_bind(glp_prob *lp, int i);
+*
+* RETURNS
+*
+* The routine glp_get_row_bind returns the index k of basic variable
+* xB[k], 1 <= k <= m, which is i-th auxiliary variable, 1 <= i <= m,
+* in the current basis associated with the specified problem object,
+* where m is the number of rows. However, if i-th auxiliary variable
+* is non-basic, the routine returns zero. */
+
+int glp_get_row_bind(glp_prob *lp, int i)
+{ if (!(lp->m == 0 || lp->valid))
+ xerror("glp_get_row_bind: basis factorization does not exist\n"
+ );
+ if (!(1 <= i && i <= lp->m))
+ xerror("glp_get_row_bind: i = %d; row number out of range\n",
+ i);
+ return lp->row[i]->bind;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_get_col_bind - retrieve column index in the basis header
+*
+* SYNOPSIS
+*
+* int glp_get_col_bind(glp_prob *lp, int j);
+*
+* RETURNS
+*
+* The routine glp_get_col_bind returns the index k of basic variable
+* xB[k], 1 <= k <= m, which is j-th structural variable, 1 <= j <= n,
+* in the current basis associated with the specified problem object,
+* where m is the number of rows, n is the number of columns. However,
+* if j-th structural variable is non-basic, the routine returns zero.*/
+
+int glp_get_col_bind(glp_prob *lp, int j)
+{ if (!(lp->m == 0 || lp->valid))
+ xerror("glp_get_col_bind: basis factorization does not exist\n"
+ );
+ if (!(1 <= j && j <= lp->n))
+ xerror("glp_get_col_bind: j = %d; column number out of range\n"
+ , j);
+ return lp->col[j]->bind;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ftran - perform forward transformation (solve system B*x = b)
+*
+* SYNOPSIS
+*
+* void glp_ftran(glp_prob *lp, double x[]);
+*
+* DESCRIPTION
+*
+* The routine glp_ftran performs forward transformation, i.e. solves
+* the system B*x = b, where B is the basis matrix corresponding to the
+* current basis for the specified problem object, x is the vector of
+* unknowns to be computed, b is the vector of right-hand sides.
+*
+* On entry elements of the vector b should be stored in dense format
+* in locations x[1], ..., x[m], where m is the number of rows. On exit
+* the routine stores elements of the vector x in the same locations.
+*
+* SCALING/UNSCALING
+*
+* Let A~ = (I | -A) is the augmented constraint matrix of the original
+* (unscaled) problem. In the scaled LP problem instead the matrix A the
+* scaled matrix A" = R*A*S is actually used, so
+*
+* A~" = (I | A") = (I | R*A*S) = (R*I*inv(R) | R*A*S) =
+* (1)
+* = R*(I | A)*S~ = R*A~*S~,
+*
+* is the scaled augmented constraint matrix, where R and S are diagonal
+* scaling matrices used to scale rows and columns of the matrix A, and
+*
+* S~ = diag(inv(R) | S) (2)
+*
+* is an augmented diagonal scaling matrix.
+*
+* By definition:
+*
+* A~ = (B | N), (3)
+*
+* where B is the basic matrix, which consists of basic columns of the
+* augmented constraint matrix A~, and N is a matrix, which consists of
+* non-basic columns of A~. From (1) it follows that:
+*
+* A~" = (B" | N") = (R*B*SB | R*N*SN), (4)
+*
+* where SB and SN are parts of the augmented scaling matrix S~, which
+* correspond to basic and non-basic variables, respectively. Therefore
+*
+* B" = R*B*SB, (5)
+*
+* which is the scaled basis matrix. */
+
+void glp_ftran(glp_prob *lp, double x[])
+{ int m = lp->m;
+ GLPROW **row = lp->row;
+ GLPCOL **col = lp->col;
+ int i, k;
+ /* B*x = b ===> (R*B*SB)*(inv(SB)*x) = R*b ===>
+ B"*x" = b", where b" = R*b, x = SB*x" */
+ if (!(m == 0 || lp->valid))
+ xerror("glp_ftran: basis factorization does not exist\n");
+ /* b" := R*b */
+ for (i = 1; i <= m; i++)
+ x[i] *= row[i]->rii;
+ /* x" := inv(B")*b" */
+ if (m > 0) bfd_ftran(lp->bfd, x);
+ /* x := SB*x" */
+ for (i = 1; i <= m; i++)
+ { k = lp->head[i];
+ if (k <= m)
+ x[i] /= row[k]->rii;
+ else
+ x[i] *= col[k-m]->sjj;
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_btran - perform backward transformation (solve system B'*x = b)
+*
+* SYNOPSIS
+*
+* void glp_btran(glp_prob *lp, double x[]);
+*
+* DESCRIPTION
+*
+* The routine glp_btran performs backward transformation, i.e. solves
+* the system B'*x = b, where B' is a matrix transposed to the basis
+* matrix corresponding to the current basis for the specified problem
+* problem object, x is the vector of unknowns to be computed, b is the
+* vector of right-hand sides.
+*
+* On entry elements of the vector b should be stored in dense format
+* in locations x[1], ..., x[m], where m is the number of rows. On exit
+* the routine stores elements of the vector x in the same locations.
+*
+* SCALING/UNSCALING
+*
+* See comments to the routine glp_ftran. */
+
+void glp_btran(glp_prob *lp, double x[])
+{ int m = lp->m;
+ GLPROW **row = lp->row;
+ GLPCOL **col = lp->col;
+ int i, k;
+ /* B'*x = b ===> (SB*B'*R)*(inv(R)*x) = SB*b ===>
+ (B")'*x" = b", where b" = SB*b, x = R*x" */
+ if (!(m == 0 || lp->valid))
+ xerror("glp_btran: basis factorization does not exist\n");
+ /* b" := SB*b */
+ for (i = 1; i <= m; i++)
+ { k = lp->head[i];
+ if (k <= m)
+ x[i] /= row[k]->rii;
+ else
+ x[i] *= col[k-m]->sjj;
+ }
+ /* x" := inv[(B")']*b" */
+ if (m > 0) bfd_btran(lp->bfd, x);
+ /* x := R*x" */
+ for (i = 1; i <= m; i++)
+ x[i] *= row[i]->rii;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_warm_up - "warm up" LP basis
+*
+* SYNOPSIS
+*
+* int glp_warm_up(glp_prob *P);
+*
+* DESCRIPTION
+*
+* The routine glp_warm_up "warms up" the LP basis for the specified
+* problem object using current statuses assigned to rows and columns
+* (that is, to auxiliary and structural variables).
+*
+* This operation includes computing factorization of the basis matrix
+* (if it does not exist), computing primal and dual components of basic
+* solution, and determining the solution status.
+*
+* RETURNS
+*
+* 0 The operation has been successfully performed.
+*
+* GLP_EBADB
+* The basis matrix is invalid, i.e. the number of basic (auxiliary
+* and structural) variables differs from the number of rows in the
+* problem object.
+*
+* GLP_ESING
+* The basis matrix is singular within the working precision.
+*
+* GLP_ECOND
+* The basis matrix is ill-conditioned. */
+
+int glp_warm_up(glp_prob *P)
+{ GLPROW *row;
+ GLPCOL *col;
+ GLPAIJ *aij;
+ int i, j, type, stat, ret;
+ double eps, temp, *work;
+ /* invalidate basic solution */
+ P->pbs_stat = P->dbs_stat = GLP_UNDEF;
+ P->obj_val = 0.0;
+ P->some = 0;
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ row->prim = row->dual = 0.0;
+ }
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ col->prim = col->dual = 0.0;
+ }
+ /* compute the basis factorization, if necessary */
+ if (!glp_bf_exists(P))
+ { ret = glp_factorize(P);
+ if (ret != 0) goto done;
+ }
+ /* allocate working array */
+ work = xcalloc(1+P->m, sizeof(double));
+ /* determine and store values of non-basic variables, compute
+ vector (- N * xN) */
+ for (i = 1; i <= P->m; i++)
+ work[i] = 0.0;
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ if (row->stat == GLP_BS)
+ continue;
+ else if (row->stat == GLP_NL)
+ row->prim = row->lb;
+ else if (row->stat == GLP_NU)
+ row->prim = row->ub;
+ else if (row->stat == GLP_NF)
+ row->prim = 0.0;
+ else if (row->stat == GLP_NS)
+ row->prim = row->lb;
+ else
+ xassert(row != row);
+ /* N[j] is i-th column of matrix (I|-A) */
+ work[i] -= row->prim;
+ }
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (col->stat == GLP_BS)
+ continue;
+ else if (col->stat == GLP_NL)
+ col->prim = col->lb;
+ else if (col->stat == GLP_NU)
+ col->prim = col->ub;
+ else if (col->stat == GLP_NF)
+ col->prim = 0.0;
+ else if (col->stat == GLP_NS)
+ col->prim = col->lb;
+ else
+ xassert(col != col);
+ /* N[j] is (m+j)-th column of matrix (I|-A) */
+ if (col->prim != 0.0)
+ { for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ work[aij->row->i] += aij->val * col->prim;
+ }
+ }
+ /* compute vector of basic variables xB = - inv(B) * N * xN */
+ glp_ftran(P, work);
+ /* store values of basic variables, check primal feasibility */
+ P->pbs_stat = GLP_FEAS;
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ if (row->stat != GLP_BS)
+ continue;
+ row->prim = work[row->bind];
+ type = row->type;
+ if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+ { eps = 1e-6 + 1e-9 * fabs(row->lb);
+ if (row->prim < row->lb - eps)
+ P->pbs_stat = GLP_INFEAS;
+ }
+ if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+ { eps = 1e-6 + 1e-9 * fabs(row->ub);
+ if (row->prim > row->ub + eps)
+ P->pbs_stat = GLP_INFEAS;
+ }
+ }
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (col->stat != GLP_BS)
+ continue;
+ col->prim = work[col->bind];
+ type = col->type;
+ if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+ { eps = 1e-6 + 1e-9 * fabs(col->lb);
+ if (col->prim < col->lb - eps)
+ P->pbs_stat = GLP_INFEAS;
+ }
+ if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+ { eps = 1e-6 + 1e-9 * fabs(col->ub);
+ if (col->prim > col->ub + eps)
+ P->pbs_stat = GLP_INFEAS;
+ }
+ }
+ /* compute value of the objective function */
+ P->obj_val = P->c0;
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ P->obj_val += col->coef * col->prim;
+ }
+ /* build vector cB of objective coefficients at basic variables */
+ for (i = 1; i <= P->m; i++)
+ work[i] = 0.0;
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (col->stat == GLP_BS)
+ work[col->bind] = col->coef;
+ }
+ /* compute vector of simplex multipliers pi = inv(B') * cB */
+ glp_btran(P, work);
+ /* compute and store reduced costs of non-basic variables d[j] =
+ c[j] - N'[j] * pi, check dual feasibility */
+ P->dbs_stat = GLP_FEAS;
+ for (i = 1; i <= P->m; i++)
+ { row = P->row[i];
+ if (row->stat == GLP_BS)
+ { row->dual = 0.0;
+ continue;
+ }
+ /* N[j] is i-th column of matrix (I|-A) */
+ row->dual = - work[i];
+#if 0 /* 07/III-2013 */
+ type = row->type;
+ temp = (P->dir == GLP_MIN ? + row->dual : - row->dual);
+ if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 ||
+ (type == GLP_FR || type == GLP_UP) && temp > +1e-5)
+ P->dbs_stat = GLP_INFEAS;
+#else
+ stat = row->stat;
+ temp = (P->dir == GLP_MIN ? + row->dual : - row->dual);
+ if ((stat == GLP_NF || stat == GLP_NL) && temp < -1e-5 ||
+ (stat == GLP_NF || stat == GLP_NU) && temp > +1e-5)
+ P->dbs_stat = GLP_INFEAS;
+#endif
+ }
+ for (j = 1; j <= P->n; j++)
+ { col = P->col[j];
+ if (col->stat == GLP_BS)
+ { col->dual = 0.0;
+ continue;
+ }
+ /* N[j] is (m+j)-th column of matrix (I|-A) */
+ col->dual = col->coef;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ col->dual += aij->val * work[aij->row->i];
+#if 0 /* 07/III-2013 */
+ type = col->type;
+ temp = (P->dir == GLP_MIN ? + col->dual : - col->dual);
+ if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 ||
+ (type == GLP_FR || type == GLP_UP) && temp > +1e-5)
+ P->dbs_stat = GLP_INFEAS;
+#else
+ stat = col->stat;
+ temp = (P->dir == GLP_MIN ? + col->dual : - col->dual);
+ if ((stat == GLP_NF || stat == GLP_NL) && temp < -1e-5 ||
+ (stat == GLP_NF || stat == GLP_NU) && temp > +1e-5)
+ P->dbs_stat = GLP_INFEAS;
+#endif
+ }
+ /* free working array */
+ xfree(work);
+ ret = 0;
+done: return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_eval_tab_row - compute row of the simplex tableau
+*
+* SYNOPSIS
+*
+* int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[]);
+*
+* DESCRIPTION
+*
+* The routine glp_eval_tab_row computes a row of the current simplex
+* tableau for the basic variable, which is specified by the number k:
+* if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n,
+* x[k] is (k-m)-th structural variable, where m is number of rows, and
+* n is number of columns. The current basis must be available.
+*
+* The routine stores column indices and numerical values of non-zero
+* elements of the computed row using sparse format to the locations
+* ind[1], ..., ind[len] and val[1], ..., val[len], respectively, where
+* 0 <= len <= n is number of non-zeros returned on exit.
+*
+* Element indices stored in the array ind have the same sense as the
+* index k, i.e. indices 1 to m denote auxiliary variables and indices
+* m+1 to m+n denote structural ones (all these variables are obviously
+* non-basic by definition).
+*
+* The computed row shows how the specified basic variable x[k] = xB[i]
+* depends on non-basic variables:
+*
+* xB[i] = alfa[i,1]*xN[1] + alfa[i,2]*xN[2] + ... + alfa[i,n]*xN[n],
+*
+* where alfa[i,j] are elements of the simplex table row, xN[j] are
+* non-basic (auxiliary and structural) variables.
+*
+* RETURNS
+*
+* The routine returns number of non-zero elements in the simplex table
+* row stored in the arrays ind and val.
+*
+* BACKGROUND
+*
+* The system of equality constraints of the LP problem is:
+*
+* xR = A * xS, (1)
+*
+* where xR is the vector of auxliary variables, xS is the vector of
+* structural variables, A is the matrix of constraint coefficients.
+*
+* The system (1) can be written in homogenous form as follows:
+*
+* A~ * x = 0, (2)
+*
+* where A~ = (I | -A) is the augmented constraint matrix (has m rows
+* and m+n columns), x = (xR | xS) is the vector of all (auxiliary and
+* structural) variables.
+*
+* By definition for the current basis we have:
+*
+* A~ = (B | N), (3)
+*
+* where B is the basis matrix. Thus, the system (2) can be written as:
+*
+* B * xB + N * xN = 0. (4)
+*
+* From (4) it follows that:
+*
+* xB = A^ * xN, (5)
+*
+* where the matrix
+*
+* A^ = - inv(B) * N (6)
+*
+* is called the simplex table.
+*
+* It is understood that i-th row of the simplex table is:
+*
+* e * A^ = - e * inv(B) * N, (7)
+*
+* where e is a unity vector with e[i] = 1.
+*
+* To compute i-th row of the simplex table the routine first computes
+* i-th row of the inverse:
+*
+* rho = inv(B') * e, (8)
+*
+* where B' is a matrix transposed to B, and then computes elements of
+* i-th row of the simplex table as scalar products:
+*
+* alfa[i,j] = - rho * N[j] for all j, (9)
+*
+* where N[j] is a column of the augmented constraint matrix A~, which
+* corresponds to some non-basic auxiliary or structural variable. */
+
+int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[])
+{ int m = lp->m;
+ int n = lp->n;
+ int i, t, len, lll, *iii;
+ double alfa, *rho, *vvv;
+ if (!(m == 0 || lp->valid))
+ xerror("glp_eval_tab_row: basis factorization does not exist\n"
+ );
+ if (!(1 <= k && k <= m+n))
+ xerror("glp_eval_tab_row: k = %d; variable number out of range"
+ , k);
+ /* determine xB[i] which corresponds to x[k] */
+ if (k <= m)
+ i = glp_get_row_bind(lp, k);
+ else
+ i = glp_get_col_bind(lp, k-m);
+ if (i == 0)
+ xerror("glp_eval_tab_row: k = %d; variable must be basic", k);
+ xassert(1 <= i && i <= m);
+ /* allocate working arrays */
+ rho = xcalloc(1+m, sizeof(double));
+ iii = xcalloc(1+m, sizeof(int));
+ vvv = xcalloc(1+m, sizeof(double));
+ /* compute i-th row of the inverse; see (8) */
+ for (t = 1; t <= m; t++) rho[t] = 0.0;
+ rho[i] = 1.0;
+ glp_btran(lp, rho);
+ /* compute i-th row of the simplex table */
+ len = 0;
+ for (k = 1; k <= m+n; k++)
+ { if (k <= m)
+ { /* x[k] is auxiliary variable, so N[k] is a unity column */
+ if (glp_get_row_stat(lp, k) == GLP_BS) continue;
+ /* compute alfa[i,j]; see (9) */
+ alfa = - rho[k];
+ }
+ else
+ { /* x[k] is structural variable, so N[k] is a column of the
+ original constraint matrix A with negative sign */
+ if (glp_get_col_stat(lp, k-m) == GLP_BS) continue;
+ /* compute alfa[i,j]; see (9) */
+ lll = glp_get_mat_col(lp, k-m, iii, vvv);
+ alfa = 0.0;
+ for (t = 1; t <= lll; t++) alfa += rho[iii[t]] * vvv[t];
+ }
+ /* store alfa[i,j] */
+ if (alfa != 0.0) len++, ind[len] = k, val[len] = alfa;
+ }
+ xassert(len <= n);
+ /* free working arrays */
+ xfree(rho);
+ xfree(iii);
+ xfree(vvv);
+ /* return to the calling program */
+ return len;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_eval_tab_col - compute column of the simplex tableau
+*
+* SYNOPSIS
+*
+* int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[]);
+*
+* DESCRIPTION
+*
+* The routine glp_eval_tab_col computes a column of the current simplex
+* table for the non-basic variable, which is specified by the number k:
+* if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n,
+* x[k] is (k-m)-th structural variable, where m is number of rows, and
+* n is number of columns. The current basis must be available.
+*
+* The routine stores row indices and numerical values of non-zero
+* elements of the computed column using sparse format to the locations
+* ind[1], ..., ind[len] and val[1], ..., val[len] respectively, where
+* 0 <= len <= m is number of non-zeros returned on exit.
+*
+* Element indices stored in the array ind have the same sense as the
+* index k, i.e. indices 1 to m denote auxiliary variables and indices
+* m+1 to m+n denote structural ones (all these variables are obviously
+* basic by the definition).
+*
+* The computed column shows how basic variables depend on the specified
+* non-basic variable x[k] = xN[j]:
+*
+* xB[1] = ... + alfa[1,j]*xN[j] + ...
+* xB[2] = ... + alfa[2,j]*xN[j] + ...
+* . . . . . .
+* xB[m] = ... + alfa[m,j]*xN[j] + ...
+*
+* where alfa[i,j] are elements of the simplex table column, xB[i] are
+* basic (auxiliary and structural) variables.
+*
+* RETURNS
+*
+* The routine returns number of non-zero elements in the simplex table
+* column stored in the arrays ind and val.
+*
+* BACKGROUND
+*
+* As it was explained in comments to the routine glp_eval_tab_row (see
+* above) the simplex table is the following matrix:
+*
+* A^ = - inv(B) * N. (1)
+*
+* Therefore j-th column of the simplex table is:
+*
+* A^ * e = - inv(B) * N * e = - inv(B) * N[j], (2)
+*
+* where e is a unity vector with e[j] = 1, B is the basis matrix, N[j]
+* is a column of the augmented constraint matrix A~, which corresponds
+* to the given non-basic auxiliary or structural variable. */
+
+int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[])
+{ int m = lp->m;
+ int n = lp->n;
+ int t, len, stat;
+ double *col;
+ if (!(m == 0 || lp->valid))
+ xerror("glp_eval_tab_col: basis factorization does not exist\n"
+ );
+ if (!(1 <= k && k <= m+n))
+ xerror("glp_eval_tab_col: k = %d; variable number out of range"
+ , k);
+ if (k <= m)
+ stat = glp_get_row_stat(lp, k);
+ else
+ stat = glp_get_col_stat(lp, k-m);
+ if (stat == GLP_BS)
+ xerror("glp_eval_tab_col: k = %d; variable must be non-basic",
+ k);
+ /* obtain column N[k] with negative sign */
+ col = xcalloc(1+m, sizeof(double));
+ for (t = 1; t <= m; t++) col[t] = 0.0;
+ if (k <= m)
+ { /* x[k] is auxiliary variable, so N[k] is a unity column */
+ col[k] = -1.0;
+ }
+ else
+ { /* x[k] is structural variable, so N[k] is a column of the
+ original constraint matrix A with negative sign */
+ len = glp_get_mat_col(lp, k-m, ind, val);
+ for (t = 1; t <= len; t++) col[ind[t]] = val[t];
+ }
+ /* compute column of the simplex table, which corresponds to the
+ specified non-basic variable x[k] */
+ glp_ftran(lp, col);
+ len = 0;
+ for (t = 1; t <= m; t++)
+ { if (col[t] != 0.0)
+ { len++;
+ ind[len] = glp_get_bhead(lp, t);
+ val[len] = col[t];
+ }
+ }
+ xfree(col);
+ /* return to the calling program */
+ return len;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_transform_row - transform explicitly specified row
+*
+* SYNOPSIS
+*
+* int glp_transform_row(glp_prob *P, int len, int ind[], double val[]);
+*
+* DESCRIPTION
+*
+* The routine glp_transform_row performs the same operation as the
+* routine glp_eval_tab_row with exception that the row to be
+* transformed is specified explicitly as a sparse vector.
+*
+* The explicitly specified row may be thought as a linear form:
+*
+* x = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n], (1)
+*
+* where x is an auxiliary variable for this row, a[j] are coefficients
+* of the linear form, x[m+j] are structural variables.
+*
+* On entry column indices and numerical values of non-zero elements of
+* the row should be stored in locations ind[1], ..., ind[len] and
+* val[1], ..., val[len], where len is the number of non-zero elements.
+*
+* This routine uses the system of equality constraints and the current
+* basis in order to express the auxiliary variable x in (1) through the
+* current non-basic variables (as if the transformed row were added to
+* the problem object and its auxiliary variable were basic), i.e. the
+* resultant row has the form:
+*
+* x = alfa[1]*xN[1] + alfa[2]*xN[2] + ... + alfa[n]*xN[n], (2)
+*
+* where xN[j] are non-basic (auxiliary or structural) variables, n is
+* the number of columns in the LP problem object.
+*
+* On exit the routine stores indices and numerical values of non-zero
+* elements of the resultant row (2) in locations ind[1], ..., ind[len']
+* and val[1], ..., val[len'], where 0 <= len' <= n is the number of
+* non-zero elements in the resultant row returned by the routine. Note
+* that indices (numbers) of non-basic variables stored in the array ind
+* correspond to original ordinal numbers of variables: indices 1 to m
+* mean auxiliary variables and indices m+1 to m+n mean structural ones.
+*
+* RETURNS
+*
+* The routine returns len', which is the number of non-zero elements in
+* the resultant row stored in the arrays ind and val.
+*
+* BACKGROUND
+*
+* The explicitly specified row (1) is transformed in the same way as it
+* were the objective function row.
+*
+* From (1) it follows that:
+*
+* x = aB * xB + aN * xN, (3)
+*
+* where xB is the vector of basic variables, xN is the vector of
+* non-basic variables.
+*
+* The simplex table, which corresponds to the current basis, is:
+*
+* xB = [-inv(B) * N] * xN. (4)
+*
+* Therefore substituting xB from (4) to (3) we have:
+*
+* x = aB * [-inv(B) * N] * xN + aN * xN =
+* (5)
+* = rho * (-N) * xN + aN * xN = alfa * xN,
+*
+* where:
+*
+* rho = inv(B') * aB, (6)
+*
+* and
+*
+* alfa = aN + rho * (-N) (7)
+*
+* is the resultant row computed by the routine. */
+
+int glp_transform_row(glp_prob *P, int len, int ind[], double val[])
+{ int i, j, k, m, n, t, lll, *iii;
+ double alfa, *a, *aB, *rho, *vvv;
+ if (!glp_bf_exists(P))
+ xerror("glp_transform_row: basis factorization does not exist "
+ "\n");
+ m = glp_get_num_rows(P);
+ n = glp_get_num_cols(P);
+ /* unpack the row to be transformed to the array a */
+ a = xcalloc(1+n, sizeof(double));
+ for (j = 1; j <= n; j++) a[j] = 0.0;
+ if (!(0 <= len && len <= n))
+ xerror("glp_transform_row: len = %d; invalid row length\n",
+ len);
+ for (t = 1; t <= len; t++)
+ { j = ind[t];
+ if (!(1 <= j && j <= n))
+ xerror("glp_transform_row: ind[%d] = %d; column index out o"
+ "f range\n", t, j);
+ if (val[t] == 0.0)
+ xerror("glp_transform_row: val[%d] = 0; zero coefficient no"
+ "t allowed\n", t);
+ if (a[j] != 0.0)
+ xerror("glp_transform_row: ind[%d] = %d; duplicate column i"
+ "ndices not allowed\n", t, j);
+ a[j] = val[t];
+ }
+ /* construct the vector aB */
+ aB = xcalloc(1+m, sizeof(double));
+ for (i = 1; i <= m; i++)
+ { k = glp_get_bhead(P, i);
+ /* xB[i] is k-th original variable */
+ xassert(1 <= k && k <= m+n);
+ aB[i] = (k <= m ? 0.0 : a[k-m]);
+ }
+ /* solve the system B'*rho = aB to compute the vector rho */
+ rho = aB, glp_btran(P, rho);
+ /* compute coefficients at non-basic auxiliary variables */
+ len = 0;
+ for (i = 1; i <= m; i++)
+ { if (glp_get_row_stat(P, i) != GLP_BS)
+ { alfa = - rho[i];
+ if (alfa != 0.0)
+ { len++;
+ ind[len] = i;
+ val[len] = alfa;
+ }
+ }
+ }
+ /* compute coefficients at non-basic structural variables */
+ iii = xcalloc(1+m, sizeof(int));
+ vvv = xcalloc(1+m, sizeof(double));
+ for (j = 1; j <= n; j++)
+ { if (glp_get_col_stat(P, j) != GLP_BS)
+ { alfa = a[j];
+ lll = glp_get_mat_col(P, j, iii, vvv);
+ for (t = 1; t <= lll; t++) alfa += vvv[t] * rho[iii[t]];
+ if (alfa != 0.0)
+ { len++;
+ ind[len] = m+j;
+ val[len] = alfa;
+ }
+ }
+ }
+ xassert(len <= n);
+ xfree(iii);
+ xfree(vvv);
+ xfree(aB);
+ xfree(a);
+ return len;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_transform_col - transform explicitly specified column
+*
+* SYNOPSIS
+*
+* int glp_transform_col(glp_prob *P, int len, int ind[], double val[]);
+*
+* DESCRIPTION
+*
+* The routine glp_transform_col performs the same operation as the
+* routine glp_eval_tab_col with exception that the column to be
+* transformed is specified explicitly as a sparse vector.
+*
+* The explicitly specified column may be thought as if it were added
+* to the original system of equality constraints:
+*
+* x[1] = a[1,1]*x[m+1] + ... + a[1,n]*x[m+n] + a[1]*x
+* x[2] = a[2,1]*x[m+1] + ... + a[2,n]*x[m+n] + a[2]*x (1)
+* . . . . . . . . . . . . . . .
+* x[m] = a[m,1]*x[m+1] + ... + a[m,n]*x[m+n] + a[m]*x
+*
+* where x[i] are auxiliary variables, x[m+j] are structural variables,
+* x is a structural variable for the explicitly specified column, a[i]
+* are constraint coefficients for x.
+*
+* On entry row indices and numerical values of non-zero elements of
+* the column should be stored in locations ind[1], ..., ind[len] and
+* val[1], ..., val[len], where len is the number of non-zero elements.
+*
+* This routine uses the system of equality constraints and the current
+* basis in order to express the current basic variables through the
+* structural variable x in (1) (as if the transformed column were added
+* to the problem object and the variable x were non-basic), i.e. the
+* resultant column has the form:
+*
+* xB[1] = ... + alfa[1]*x
+* xB[2] = ... + alfa[2]*x (2)
+* . . . . . .
+* xB[m] = ... + alfa[m]*x
+*
+* where xB are basic (auxiliary and structural) variables, m is the
+* number of rows in the problem object.
+*
+* On exit the routine stores indices and numerical values of non-zero
+* elements of the resultant column (2) in locations ind[1], ...,
+* ind[len'] and val[1], ..., val[len'], where 0 <= len' <= m is the
+* number of non-zero element in the resultant column returned by the
+* routine. Note that indices (numbers) of basic variables stored in
+* the array ind correspond to original ordinal numbers of variables:
+* indices 1 to m mean auxiliary variables and indices m+1 to m+n mean
+* structural ones.
+*
+* RETURNS
+*
+* The routine returns len', which is the number of non-zero elements
+* in the resultant column stored in the arrays ind and val.
+*
+* BACKGROUND
+*
+* The explicitly specified column (1) is transformed in the same way
+* as any other column of the constraint matrix using the formula:
+*
+* alfa = inv(B) * a, (3)
+*
+* where alfa is the resultant column computed by the routine. */
+
+int glp_transform_col(glp_prob *P, int len, int ind[], double val[])
+{ int i, m, t;
+ double *a, *alfa;
+ if (!glp_bf_exists(P))
+ xerror("glp_transform_col: basis factorization does not exist "
+ "\n");
+ m = glp_get_num_rows(P);
+ /* unpack the column to be transformed to the array a */
+ a = xcalloc(1+m, sizeof(double));
+ for (i = 1; i <= m; i++) a[i] = 0.0;
+ if (!(0 <= len && len <= m))
+ xerror("glp_transform_col: len = %d; invalid column length\n",
+ len);
+ for (t = 1; t <= len; t++)
+ { i = ind[t];
+ if (!(1 <= i && i <= m))
+ xerror("glp_transform_col: ind[%d] = %d; row index out of r"
+ "ange\n", t, i);
+ if (val[t] == 0.0)
+ xerror("glp_transform_col: val[%d] = 0; zero coefficient no"
+ "t allowed\n", t);
+ if (a[i] != 0.0)
+ xerror("glp_transform_col: ind[%d] = %d; duplicate row indi"
+ "ces not allowed\n", t, i);
+ a[i] = val[t];
+ }
+ /* solve the system B*a = alfa to compute the vector alfa */
+ alfa = a, glp_ftran(P, alfa);
+ /* store resultant coefficients */
+ len = 0;
+ for (i = 1; i <= m; i++)
+ { if (alfa[i] != 0.0)
+ { len++;
+ ind[len] = glp_get_bhead(P, i);
+ val[len] = alfa[i];
+ }
+ }
+ xfree(a);
+ return len;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_prim_rtest - perform primal ratio test
+*
+* SYNOPSIS
+*
+* int glp_prim_rtest(glp_prob *P, int len, const int ind[],
+* const double val[], int dir, double eps);
+*
+* DESCRIPTION
+*
+* The routine glp_prim_rtest performs the primal ratio test using an
+* explicitly specified column of the simplex table.
+*
+* The current basic solution associated with the LP problem object
+* must be primal feasible.
+*
+* The explicitly specified column of the simplex table shows how the
+* basic variables xB depend on some non-basic variable x (which is not
+* necessarily presented in the problem object):
+*
+* xB[1] = ... + alfa[1] * x + ...
+* xB[2] = ... + alfa[2] * x + ... (*)
+* . . . . . . . .
+* xB[m] = ... + alfa[m] * x + ...
+*
+* The column (*) is specifed on entry to the routine using the sparse
+* format. Ordinal numbers of basic variables xB[i] should be placed in
+* locations ind[1], ..., ind[len], where ordinal number 1 to m denote
+* auxiliary variables, and ordinal numbers m+1 to m+n denote structural
+* variables. The corresponding non-zero coefficients alfa[i] should be
+* placed in locations val[1], ..., val[len]. The arrays ind and val are
+* not changed on exit.
+*
+* The parameter dir specifies direction in which the variable x changes
+* on entering the basis: +1 means increasing, -1 means decreasing.
+*
+* The parameter eps is an absolute tolerance (small positive number)
+* used by the routine to skip small alfa[j] of the row (*).
+*
+* The routine determines which basic variable (among specified in
+* ind[1], ..., ind[len]) should leave the basis in order to keep primal
+* feasibility.
+*
+* RETURNS
+*
+* The routine glp_prim_rtest returns the index piv in the arrays ind
+* and val corresponding to the pivot element chosen, 1 <= piv <= len.
+* If the adjacent basic solution is primal unbounded and therefore the
+* choice cannot be made, the routine returns zero.
+*
+* COMMENTS
+*
+* If the non-basic variable x is presented in the LP problem object,
+* the column (*) can be computed with the routine glp_eval_tab_col;
+* otherwise it can be computed with the routine glp_transform_col. */
+
+int glp_prim_rtest(glp_prob *P, int len, const int ind[],
+ const double val[], int dir, double eps)
+{ int k, m, n, piv, t, type, stat;
+ double alfa, big, beta, lb, ub, temp, teta;
+ if (glp_get_prim_stat(P) != GLP_FEAS)
+ xerror("glp_prim_rtest: basic solution is not primal feasible "
+ "\n");
+ if (!(dir == +1 || dir == -1))
+ xerror("glp_prim_rtest: dir = %d; invalid parameter\n", dir);
+ if (!(0.0 < eps && eps < 1.0))
+ xerror("glp_prim_rtest: eps = %g; invalid parameter\n", eps);
+ m = glp_get_num_rows(P);
+ n = glp_get_num_cols(P);
+ /* initial settings */
+ piv = 0, teta = DBL_MAX, big = 0.0;
+ /* walk through the entries of the specified column */
+ for (t = 1; t <= len; t++)
+ { /* get the ordinal number of basic variable */
+ k = ind[t];
+ if (!(1 <= k && k <= m+n))
+ xerror("glp_prim_rtest: ind[%d] = %d; variable number out o"
+ "f range\n", t, k);
+ /* determine type, bounds, status and primal value of basic
+ variable xB[i] = x[k] in the current basic solution */
+ if (k <= m)
+ { type = glp_get_row_type(P, k);
+ lb = glp_get_row_lb(P, k);
+ ub = glp_get_row_ub(P, k);
+ stat = glp_get_row_stat(P, k);
+ beta = glp_get_row_prim(P, k);
+ }
+ else
+ { type = glp_get_col_type(P, k-m);
+ lb = glp_get_col_lb(P, k-m);
+ ub = glp_get_col_ub(P, k-m);
+ stat = glp_get_col_stat(P, k-m);
+ beta = glp_get_col_prim(P, k-m);
+ }
+ if (stat != GLP_BS)
+ xerror("glp_prim_rtest: ind[%d] = %d; non-basic variable no"
+ "t allowed\n", t, k);
+ /* determine influence coefficient at basic variable xB[i]
+ in the explicitly specified column and turn to the case of
+ increasing the variable x in order to simplify the program
+ logic */
+ alfa = (dir > 0 ? + val[t] : - val[t]);
+ /* analyze main cases */
+ if (type == GLP_FR)
+ { /* xB[i] is free variable */
+ continue;
+ }
+ else if (type == GLP_LO)
+lo: { /* xB[i] has an lower bound */
+ if (alfa > - eps) continue;
+ temp = (lb - beta) / alfa;
+ }
+ else if (type == GLP_UP)
+up: { /* xB[i] has an upper bound */
+ if (alfa < + eps) continue;
+ temp = (ub - beta) / alfa;
+ }
+ else if (type == GLP_DB)
+ { /* xB[i] has both lower and upper bounds */
+ if (alfa < 0.0) goto lo; else goto up;
+ }
+ else if (type == GLP_FX)
+ { /* xB[i] is fixed variable */
+ if (- eps < alfa && alfa < + eps) continue;
+ temp = 0.0;
+ }
+ else
+ xassert(type != type);
+ /* if the value of the variable xB[i] violates its lower or
+ upper bound (slightly, because the current basis is assumed
+ to be primal feasible), temp is negative; we can think this
+ happens due to round-off errors and the value is exactly on
+ the bound; this allows replacing temp by zero */
+ if (temp < 0.0) temp = 0.0;
+ /* apply the minimal ratio test */
+ if (teta > temp || teta == temp && big < fabs(alfa))
+ piv = t, teta = temp, big = fabs(alfa);
+ }
+ /* return index of the pivot element chosen */
+ return piv;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_dual_rtest - perform dual ratio test
+*
+* SYNOPSIS
+*
+* int glp_dual_rtest(glp_prob *P, int len, const int ind[],
+* const double val[], int dir, double eps);
+*
+* DESCRIPTION
+*
+* The routine glp_dual_rtest performs the dual ratio test using an
+* explicitly specified row of the simplex table.
+*
+* The current basic solution associated with the LP problem object
+* must be dual feasible.
+*
+* The explicitly specified row of the simplex table is a linear form
+* that shows how some basic variable x (which is not necessarily
+* presented in the problem object) depends on non-basic variables xN:
+*
+* x = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n]. (*)
+*
+* The row (*) is specified on entry to the routine using the sparse
+* format. Ordinal numbers of non-basic variables xN[j] should be placed
+* in locations ind[1], ..., ind[len], where ordinal numbers 1 to m
+* denote auxiliary variables, and ordinal numbers m+1 to m+n denote
+* structural variables. The corresponding non-zero coefficients alfa[j]
+* should be placed in locations val[1], ..., val[len]. The arrays ind
+* and val are not changed on exit.
+*
+* The parameter dir specifies direction in which the variable x changes
+* on leaving the basis: +1 means that x goes to its lower bound, and -1
+* means that x goes to its upper bound.
+*
+* The parameter eps is an absolute tolerance (small positive number)
+* used by the routine to skip small alfa[j] of the row (*).
+*
+* The routine determines which non-basic variable (among specified in
+* ind[1], ..., ind[len]) should enter the basis in order to keep dual
+* feasibility.
+*
+* RETURNS
+*
+* The routine glp_dual_rtest returns the index piv in the arrays ind
+* and val corresponding to the pivot element chosen, 1 <= piv <= len.
+* If the adjacent basic solution is dual unbounded and therefore the
+* choice cannot be made, the routine returns zero.
+*
+* COMMENTS
+*
+* If the basic variable x is presented in the LP problem object, the
+* row (*) can be computed with the routine glp_eval_tab_row; otherwise
+* it can be computed with the routine glp_transform_row. */
+
+int glp_dual_rtest(glp_prob *P, int len, const int ind[],
+ const double val[], int dir, double eps)
+{ int k, m, n, piv, t, stat;
+ double alfa, big, cost, obj, temp, teta;
+ if (glp_get_dual_stat(P) != GLP_FEAS)
+ xerror("glp_dual_rtest: basic solution is not dual feasible\n")
+ ;
+ if (!(dir == +1 || dir == -1))
+ xerror("glp_dual_rtest: dir = %d; invalid parameter\n", dir);
+ if (!(0.0 < eps && eps < 1.0))
+ xerror("glp_dual_rtest: eps = %g; invalid parameter\n", eps);
+ m = glp_get_num_rows(P);
+ n = glp_get_num_cols(P);
+ /* take into account optimization direction */
+ obj = (glp_get_obj_dir(P) == GLP_MIN ? +1.0 : -1.0);
+ /* initial settings */
+ piv = 0, teta = DBL_MAX, big = 0.0;
+ /* walk through the entries of the specified row */
+ for (t = 1; t <= len; t++)
+ { /* get ordinal number of non-basic variable */
+ k = ind[t];
+ if (!(1 <= k && k <= m+n))
+ xerror("glp_dual_rtest: ind[%d] = %d; variable number out o"
+ "f range\n", t, k);
+ /* determine status and reduced cost of non-basic variable
+ x[k] = xN[j] in the current basic solution */
+ if (k <= m)
+ { stat = glp_get_row_stat(P, k);
+ cost = glp_get_row_dual(P, k);
+ }
+ else
+ { stat = glp_get_col_stat(P, k-m);
+ cost = glp_get_col_dual(P, k-m);
+ }
+ if (stat == GLP_BS)
+ xerror("glp_dual_rtest: ind[%d] = %d; basic variable not al"
+ "lowed\n", t, k);
+ /* determine influence coefficient at non-basic variable xN[j]
+ in the explicitly specified row and turn to the case of
+ increasing the variable x in order to simplify the program
+ logic */
+ alfa = (dir > 0 ? + val[t] : - val[t]);
+ /* analyze main cases */
+ if (stat == GLP_NL)
+ { /* xN[j] is on its lower bound */
+ if (alfa < + eps) continue;
+ temp = (obj * cost) / alfa;
+ }
+ else if (stat == GLP_NU)
+ { /* xN[j] is on its upper bound */
+ if (alfa > - eps) continue;
+ temp = (obj * cost) / alfa;
+ }
+ else if (stat == GLP_NF)
+ { /* xN[j] is non-basic free variable */
+ if (- eps < alfa && alfa < + eps) continue;
+ temp = 0.0;
+ }
+ else if (stat == GLP_NS)
+ { /* xN[j] is non-basic fixed variable */
+ continue;
+ }
+ else
+ xassert(stat != stat);
+ /* if the reduced cost of the variable xN[j] violates its zero
+ bound (slightly, because the current basis is assumed to be
+ dual feasible), temp is negative; we can think this happens
+ due to round-off errors and the reduced cost is exact zero;
+ this allows replacing temp by zero */
+ if (temp < 0.0) temp = 0.0;
+ /* apply the minimal ratio test */
+ if (teta > temp || teta == temp && big < fabs(alfa))
+ piv = t, teta = temp, big = fabs(alfa);
+ }
+ /* return index of the pivot element chosen */
+ return piv;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_analyze_row - simulate one iteration of dual simplex method
+*
+* SYNOPSIS
+*
+* int glp_analyze_row(glp_prob *P, int len, const int ind[],
+* const double val[], int type, double rhs, double eps, int *piv,
+* double *x, double *dx, double *y, double *dy, double *dz);
+*
+* DESCRIPTION
+*
+* Let the current basis be optimal or dual feasible, and there be
+* specified a row (constraint), which is violated by the current basic
+* solution. The routine glp_analyze_row simulates one iteration of the
+* dual simplex method to determine some information on the adjacent
+* basis (see below), where the specified row becomes active constraint
+* (i.e. its auxiliary variable becomes non-basic).
+*
+* The current basic solution associated with the problem object passed
+* to the routine must be dual feasible, and its primal components must
+* be defined.
+*
+* The row to be analyzed must be previously transformed either with
+* the routine glp_eval_tab_row (if the row is in the problem object)
+* or with the routine glp_transform_row (if the row is external, i.e.
+* not in the problem object). This is needed to express the row only
+* through (auxiliary and structural) variables, which are non-basic in
+* the current basis:
+*
+* y = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n],
+*
+* where y is an auxiliary variable of the row, alfa[j] is an influence
+* coefficient, xN[j] is a non-basic variable.
+*
+* The row is passed to the routine in sparse format. Ordinal numbers
+* of non-basic variables are stored in locations ind[1], ..., ind[len],
+* where numbers 1 to m denote auxiliary variables while numbers m+1 to
+* m+n denote structural variables. Corresponding non-zero coefficients
+* alfa[j] are stored in locations val[1], ..., val[len]. The arrays
+* ind and val are ot changed on exit.
+*
+* The parameters type and rhs specify the row type and its right-hand
+* side as follows:
+*
+* type = GLP_LO: y = sum alfa[j] * xN[j] >= rhs
+*
+* type = GLP_UP: y = sum alfa[j] * xN[j] <= rhs
+*
+* The parameter eps is an absolute tolerance (small positive number)
+* used by the routine to skip small coefficients alfa[j] on performing
+* the dual ratio test.
+*
+* If the operation was successful, the routine stores the following
+* information to corresponding location (if some parameter is NULL,
+* its value is not stored):
+*
+* piv index in the array ind and val, 1 <= piv <= len, determining
+* the non-basic variable, which would enter the adjacent basis;
+*
+* x value of the non-basic variable in the current basis;
+*
+* dx difference between values of the non-basic variable in the
+* adjacent and current bases, dx = x.new - x.old;
+*
+* y value of the row (i.e. of its auxiliary variable) in the
+* current basis;
+*
+* dy difference between values of the row in the adjacent and
+* current bases, dy = y.new - y.old;
+*
+* dz difference between values of the objective function in the
+* adjacent and current bases, dz = z.new - z.old. Note that in
+* case of minimization dz >= 0, and in case of maximization
+* dz <= 0, i.e. in the adjacent basis the objective function
+* always gets worse (degrades). */
+
+int _glp_analyze_row(glp_prob *P, int len, const int ind[],
+ const double val[], int type, double rhs, double eps, int *_piv,
+ double *_x, double *_dx, double *_y, double *_dy, double *_dz)
+{ int t, k, dir, piv, ret = 0;
+ double x, dx, y, dy, dz;
+ if (P->pbs_stat == GLP_UNDEF)
+ xerror("glp_analyze_row: primal basic solution components are "
+ "undefined\n");
+ if (P->dbs_stat != GLP_FEAS)
+ xerror("glp_analyze_row: basic solution is not dual feasible\n"
+ );
+ /* compute the row value y = sum alfa[j] * xN[j] in the current
+ basis */
+ if (!(0 <= len && len <= P->n))
+ xerror("glp_analyze_row: len = %d; invalid row length\n", len);
+ y = 0.0;
+ for (t = 1; t <= len; t++)
+ { /* determine value of x[k] = xN[j] in the current basis */
+ k = ind[t];
+ if (!(1 <= k && k <= P->m+P->n))
+ xerror("glp_analyze_row: ind[%d] = %d; row/column index out"
+ " of range\n", t, k);
+ if (k <= P->m)
+ { /* x[k] is auxiliary variable */
+ if (P->row[k]->stat == GLP_BS)
+ xerror("glp_analyze_row: ind[%d] = %d; basic auxiliary v"
+ "ariable is not allowed\n", t, k);
+ x = P->row[k]->prim;
+ }
+ else
+ { /* x[k] is structural variable */
+ if (P->col[k-P->m]->stat == GLP_BS)
+ xerror("glp_analyze_row: ind[%d] = %d; basic structural "
+ "variable is not allowed\n", t, k);
+ x = P->col[k-P->m]->prim;
+ }
+ y += val[t] * x;
+ }
+ /* check if the row is primal infeasible in the current basis,
+ i.e. the constraint is violated at the current point */
+ if (type == GLP_LO)
+ { if (y >= rhs)
+ { /* the constraint is not violated */
+ ret = 1;
+ goto done;
+ }
+ /* in the adjacent basis y goes to its lower bound */
+ dir = +1;
+ }
+ else if (type == GLP_UP)
+ { if (y <= rhs)
+ { /* the constraint is not violated */
+ ret = 1;
+ goto done;
+ }
+ /* in the adjacent basis y goes to its upper bound */
+ dir = -1;
+ }
+ else
+ xerror("glp_analyze_row: type = %d; invalid parameter\n",
+ type);
+ /* compute dy = y.new - y.old */
+ dy = rhs - y;
+ /* perform dual ratio test to determine which non-basic variable
+ should enter the adjacent basis to keep it dual feasible */
+ piv = glp_dual_rtest(P, len, ind, val, dir, eps);
+ if (piv == 0)
+ { /* no dual feasible adjacent basis exists */
+ ret = 2;
+ goto done;
+ }
+ /* non-basic variable x[k] = xN[j] should enter the basis */
+ k = ind[piv];
+ xassert(1 <= k && k <= P->m+P->n);
+ /* determine its value in the current basis */
+ if (k <= P->m)
+ x = P->row[k]->prim;
+ else
+ x = P->col[k-P->m]->prim;
+ /* compute dx = x.new - x.old = dy / alfa[j] */
+ xassert(val[piv] != 0.0);
+ dx = dy / val[piv];
+ /* compute dz = z.new - z.old = d[j] * dx, where d[j] is reduced
+ cost of xN[j] in the current basis */
+ if (k <= P->m)
+ dz = P->row[k]->dual * dx;
+ else
+ dz = P->col[k-P->m]->dual * dx;
+ /* store the analysis results */
+ if (_piv != NULL) *_piv = piv;
+ if (_x != NULL) *_x = x;
+ if (_dx != NULL) *_dx = dx;
+ if (_y != NULL) *_y = y;
+ if (_dy != NULL) *_dy = dy;
+ if (_dz != NULL) *_dz = dz;
+done: return ret;
+}
+
+#if 0
+int main(void)
+{ /* example program for the routine glp_analyze_row */
+ glp_prob *P;
+ glp_smcp parm;
+ int i, k, len, piv, ret, ind[1+100];
+ double rhs, x, dx, y, dy, dz, val[1+100];
+ P = glp_create_prob();
+ /* read plan.mps (see glpk/examples) */
+ ret = glp_read_mps(P, GLP_MPS_DECK, NULL, "plan.mps");
+ glp_assert(ret == 0);
+ /* and solve it to optimality */
+ ret = glp_simplex(P, NULL);
+ glp_assert(ret == 0);
+ glp_assert(glp_get_status(P) == GLP_OPT);
+ /* the optimal objective value is 296.217 */
+ /* we would like to know what happens if we would add a new row
+ (constraint) to plan.mps:
+ .01 * bin1 + .01 * bin2 + .02 * bin4 + .02 * bin5 <= 12 */
+ /* first, we specify this new row */
+ glp_create_index(P);
+ len = 0;
+ ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01;
+ ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01;
+ ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02;
+ ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02;
+ rhs = 12;
+ /* then we can compute value of the row (i.e. of its auxiliary
+ variable) in the current basis to see if the constraint is
+ violated */
+ y = 0.0;
+ for (k = 1; k <= len; k++)
+ y += val[k] * glp_get_col_prim(P, ind[k]);
+ glp_printf("y = %g\n", y);
+ /* this prints y = 15.1372, so the constraint is violated, since
+ we require that y <= rhs = 12 */
+ /* now we transform the row to express it only through non-basic
+ (auxiliary and artificial) variables */
+ len = glp_transform_row(P, len, ind, val);
+ /* finally, we simulate one step of the dual simplex method to
+ obtain necessary information for the adjacent basis */
+ ret = _glp_analyze_row(P, len, ind, val, GLP_UP, rhs, 1e-9, &piv,
+ &x, &dx, &y, &dy, &dz);
+ glp_assert(ret == 0);
+ glp_printf("k = %d, x = %g; dx = %g; y = %g; dy = %g; dz = %g\n",
+ ind[piv], x, dx, y, dy, dz);
+ /* this prints dz = 5.64418 and means that in the adjacent basis
+ the objective function would be 296.217 + 5.64418 = 301.861 */
+ /* now we actually include the row into the problem object; note
+ that the arrays ind and val are clobbered, so we need to build
+ them once again */
+ len = 0;
+ ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01;
+ ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01;
+ ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02;
+ ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02;
+ rhs = 12;
+ i = glp_add_rows(P, 1);
+ glp_set_row_bnds(P, i, GLP_UP, 0, rhs);
+ glp_set_mat_row(P, i, len, ind, val);
+ /* and perform one dual simplex iteration */
+ glp_init_smcp(&parm);
+ parm.meth = GLP_DUAL;
+ parm.it_lim = 1;
+ glp_simplex(P, &parm);
+ /* the current objective value is 301.861 */
+ return 0;
+}
+#endif
+
+/***********************************************************************
+* NAME
+*
+* glp_analyze_bound - analyze active bound of non-basic variable
+*
+* SYNOPSIS
+*
+* void glp_analyze_bound(glp_prob *P, int k, double *limit1, int *var1,
+* double *limit2, int *var2);
+*
+* DESCRIPTION
+*
+* The routine glp_analyze_bound analyzes the effect of varying the
+* active bound of specified non-basic variable.
+*
+* The non-basic variable is specified by the parameter k, where
+* 1 <= k <= m means auxiliary variable of corresponding row while
+* m+1 <= k <= m+n means structural variable (column).
+*
+* Note that the current basic solution must be optimal, and the basis
+* factorization must exist.
+*
+* Results of the analysis have the following meaning.
+*
+* value1 is the minimal value of the active bound, at which the basis
+* still remains primal feasible and thus optimal. -DBL_MAX means that
+* the active bound has no lower limit.
+*
+* var1 is the ordinal number of an auxiliary (1 to m) or structural
+* (m+1 to n) basic variable, which reaches its bound first and thereby
+* limits further decreasing the active bound being analyzed.
+* if value1 = -DBL_MAX, var1 is set to 0.
+*
+* value2 is the maximal value of the active bound, at which the basis
+* still remains primal feasible and thus optimal. +DBL_MAX means that
+* the active bound has no upper limit.
+*
+* var2 is the ordinal number of an auxiliary (1 to m) or structural
+* (m+1 to n) basic variable, which reaches its bound first and thereby
+* limits further increasing the active bound being analyzed.
+* if value2 = +DBL_MAX, var2 is set to 0. */
+
+void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1,
+ double *value2, int *var2)
+{ GLPROW *row;
+ GLPCOL *col;
+ int m, n, stat, kase, p, len, piv, *ind;
+ double x, new_x, ll, uu, xx, delta, *val;
+#if 0 /* 04/IV-2016 */
+ /* sanity checks */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_analyze_bound: P = %p; invalid problem object\n",
+ P);
+#endif
+ m = P->m, n = P->n;
+ if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
+ xerror("glp_analyze_bound: optimal basic solution required\n");
+ if (!(m == 0 || P->valid))
+ xerror("glp_analyze_bound: basis factorization required\n");
+ if (!(1 <= k && k <= m+n))
+ xerror("glp_analyze_bound: k = %d; variable number out of rang"
+ "e\n", k);
+ /* retrieve information about the specified non-basic variable
+ x[k] whose active bound is to be analyzed */
+ if (k <= m)
+ { row = P->row[k];
+ stat = row->stat;
+ x = row->prim;
+ }
+ else
+ { col = P->col[k-m];
+ stat = col->stat;
+ x = col->prim;
+ }
+ if (stat == GLP_BS)
+ xerror("glp_analyze_bound: k = %d; basic variable not allowed "
+ "\n", k);
+ /* allocate working arrays */
+ ind = xcalloc(1+m, sizeof(int));
+ val = xcalloc(1+m, sizeof(double));
+ /* compute column of the simplex table corresponding to the
+ non-basic variable x[k] */
+ len = glp_eval_tab_col(P, k, ind, val);
+ xassert(0 <= len && len <= m);
+ /* perform analysis */
+ for (kase = -1; kase <= +1; kase += 2)
+ { /* kase < 0 means active bound of x[k] is decreasing;
+ kase > 0 means active bound of x[k] is increasing */
+ /* use the primal ratio test to determine some basic variable
+ x[p] which reaches its bound first */
+ piv = glp_prim_rtest(P, len, ind, val, kase, 1e-9);
+ if (piv == 0)
+ { /* nothing limits changing the active bound of x[k] */
+ p = 0;
+ new_x = (kase < 0 ? -DBL_MAX : +DBL_MAX);
+ goto store;
+ }
+ /* basic variable x[p] limits changing the active bound of
+ x[k]; determine its value in the current basis */
+ xassert(1 <= piv && piv <= len);
+ p = ind[piv];
+ if (p <= m)
+ { row = P->row[p];
+ ll = glp_get_row_lb(P, row->i);
+ uu = glp_get_row_ub(P, row->i);
+ stat = row->stat;
+ xx = row->prim;
+ }
+ else
+ { col = P->col[p-m];
+ ll = glp_get_col_lb(P, col->j);
+ uu = glp_get_col_ub(P, col->j);
+ stat = col->stat;
+ xx = col->prim;
+ }
+ xassert(stat == GLP_BS);
+ /* determine delta x[p] = bound of x[p] - value of x[p] */
+ if (kase < 0 && val[piv] > 0.0 ||
+ kase > 0 && val[piv] < 0.0)
+ { /* delta x[p] < 0, so x[p] goes toward its lower bound */
+ xassert(ll != -DBL_MAX);
+ delta = ll - xx;
+ }
+ else
+ { /* delta x[p] > 0, so x[p] goes toward its upper bound */
+ xassert(uu != +DBL_MAX);
+ delta = uu - xx;
+ }
+ /* delta x[p] = alfa[p,k] * delta x[k], so new x[k] = x[k] +
+ delta x[k] = x[k] + delta x[p] / alfa[p,k] is the value of
+ x[k] in the adjacent basis */
+ xassert(val[piv] != 0.0);
+ new_x = x + delta / val[piv];
+store: /* store analysis results */
+ if (kase < 0)
+ { if (value1 != NULL) *value1 = new_x;
+ if (var1 != NULL) *var1 = p;
+ }
+ else
+ { if (value2 != NULL) *value2 = new_x;
+ if (var2 != NULL) *var2 = p;
+ }
+ }
+ /* free working arrays */
+ xfree(ind);
+ xfree(val);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_analyze_coef - analyze objective coefficient at basic variable
+*
+* SYNOPSIS
+*
+* void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
+* double *value1, double *coef2, int *var2, double *value2);
+*
+* DESCRIPTION
+*
+* The routine glp_analyze_coef analyzes the effect of varying the
+* objective coefficient at specified basic variable.
+*
+* The basic variable is specified by the parameter k, where
+* 1 <= k <= m means auxiliary variable of corresponding row while
+* m+1 <= k <= m+n means structural variable (column).
+*
+* Note that the current basic solution must be optimal, and the basis
+* factorization must exist.
+*
+* Results of the analysis have the following meaning.
+*
+* coef1 is the minimal value of the objective coefficient, at which
+* the basis still remains dual feasible and thus optimal. -DBL_MAX
+* means that the objective coefficient has no lower limit.
+*
+* var1 is the ordinal number of an auxiliary (1 to m) or structural
+* (m+1 to n) non-basic variable, whose reduced cost reaches its zero
+* bound first and thereby limits further decreasing the objective
+* coefficient being analyzed. If coef1 = -DBL_MAX, var1 is set to 0.
+*
+* value1 is value of the basic variable being analyzed in an adjacent
+* basis, which is defined as follows. Let the objective coefficient
+* reaches its minimal value (coef1) and continues decreasing. Then the
+* reduced cost of the limiting non-basic variable (var1) becomes dual
+* infeasible and the current basis becomes non-optimal that forces the
+* limiting non-basic variable to enter the basis replacing there some
+* basic variable that leaves the basis to keep primal feasibility.
+* Should note that on determining the adjacent basis current bounds
+* of the basic variable being analyzed are ignored as if it were free
+* (unbounded) variable, so it cannot leave the basis. It may happen
+* that no dual feasible adjacent basis exists, in which case value1 is
+* set to -DBL_MAX or +DBL_MAX.
+*
+* coef2 is the maximal value of the objective coefficient, at which
+* the basis still remains dual feasible and thus optimal. +DBL_MAX
+* means that the objective coefficient has no upper limit.
+*
+* var2 is the ordinal number of an auxiliary (1 to m) or structural
+* (m+1 to n) non-basic variable, whose reduced cost reaches its zero
+* bound first and thereby limits further increasing the objective
+* coefficient being analyzed. If coef2 = +DBL_MAX, var2 is set to 0.
+*
+* value2 is value of the basic variable being analyzed in an adjacent
+* basis, which is defined exactly in the same way as value1 above with
+* exception that now the objective coefficient is increasing. */
+
+void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
+ double *value1, double *coef2, int *var2, double *value2)
+{ GLPROW *row; GLPCOL *col;
+ int m, n, type, stat, kase, p, q, dir, clen, cpiv, rlen, rpiv,
+ *cind, *rind;
+ double lb, ub, coef, x, lim_coef, new_x, d, delta, ll, uu, xx,
+ *rval, *cval;
+#if 0 /* 04/IV-2016 */
+ /* sanity checks */
+ if (P == NULL || P->magic != GLP_PROB_MAGIC)
+ xerror("glp_analyze_coef: P = %p; invalid problem object\n",
+ P);
+#endif
+ m = P->m, n = P->n;
+ if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
+ xerror("glp_analyze_coef: optimal basic solution required\n");
+ if (!(m == 0 || P->valid))
+ xerror("glp_analyze_coef: basis factorization required\n");
+ if (!(1 <= k && k <= m+n))
+ xerror("glp_analyze_coef: k = %d; variable number out of range"
+ "\n", k);
+ /* retrieve information about the specified basic variable x[k]
+ whose objective coefficient c[k] is to be analyzed */
+ if (k <= m)
+ { row = P->row[k];
+ type = row->type;
+ lb = row->lb;
+ ub = row->ub;
+ coef = 0.0;
+ stat = row->stat;
+ x = row->prim;
+ }
+ else
+ { col = P->col[k-m];
+ type = col->type;
+ lb = col->lb;
+ ub = col->ub;
+ coef = col->coef;
+ stat = col->stat;
+ x = col->prim;
+ }
+ if (stat != GLP_BS)
+ xerror("glp_analyze_coef: k = %d; non-basic variable not allow"
+ "ed\n", k);
+ /* allocate working arrays */
+ cind = xcalloc(1+m, sizeof(int));
+ cval = xcalloc(1+m, sizeof(double));
+ rind = xcalloc(1+n, sizeof(int));
+ rval = xcalloc(1+n, sizeof(double));
+ /* compute row of the simplex table corresponding to the basic
+ variable x[k] */
+ rlen = glp_eval_tab_row(P, k, rind, rval);
+ xassert(0 <= rlen && rlen <= n);
+ /* perform analysis */
+ for (kase = -1; kase <= +1; kase += 2)
+ { /* kase < 0 means objective coefficient c[k] is decreasing;
+ kase > 0 means objective coefficient c[k] is increasing */
+ /* note that decreasing c[k] is equivalent to increasing dual
+ variable lambda[k] and vice versa; we need to correctly set
+ the dir flag as required by the routine glp_dual_rtest */
+ if (P->dir == GLP_MIN)
+ dir = - kase;
+ else if (P->dir == GLP_MAX)
+ dir = + kase;
+ else
+ xassert(P != P);
+ /* use the dual ratio test to determine non-basic variable
+ x[q] whose reduced cost d[q] reaches zero bound first */
+ rpiv = glp_dual_rtest(P, rlen, rind, rval, dir, 1e-9);
+ if (rpiv == 0)
+ { /* nothing limits changing c[k] */
+ lim_coef = (kase < 0 ? -DBL_MAX : +DBL_MAX);
+ q = 0;
+ /* x[k] keeps its current value */
+ new_x = x;
+ goto store;
+ }
+ /* non-basic variable x[q] limits changing coefficient c[k];
+ determine its status and reduced cost d[k] in the current
+ basis */
+ xassert(1 <= rpiv && rpiv <= rlen);
+ q = rind[rpiv];
+ xassert(1 <= q && q <= m+n);
+ if (q <= m)
+ { row = P->row[q];
+ stat = row->stat;
+ d = row->dual;
+ }
+ else
+ { col = P->col[q-m];
+ stat = col->stat;
+ d = col->dual;
+ }
+ /* note that delta d[q] = new d[q] - d[q] = - d[q], because
+ new d[q] = 0; delta d[q] = alfa[k,q] * delta c[k], so
+ delta c[k] = delta d[q] / alfa[k,q] = - d[q] / alfa[k,q] */
+ xassert(rval[rpiv] != 0.0);
+ delta = - d / rval[rpiv];
+ /* compute new c[k] = c[k] + delta c[k], which is the limiting
+ value of the objective coefficient c[k] */
+ lim_coef = coef + delta;
+ /* let c[k] continue decreasing/increasing that makes d[q]
+ dual infeasible and forces x[q] to enter the basis;
+ to perform the primal ratio test we need to know in which
+ direction x[q] changes on entering the basis; we determine
+ that analyzing the sign of delta d[q] (see above), since
+ d[q] may be close to zero having wrong sign */
+ /* let, for simplicity, the problem is minimization */
+ if (kase < 0 && rval[rpiv] > 0.0 ||
+ kase > 0 && rval[rpiv] < 0.0)
+ { /* delta d[q] < 0, so d[q] being non-negative will become
+ negative, so x[q] will increase */
+ dir = +1;
+ }
+ else
+ { /* delta d[q] > 0, so d[q] being non-positive will become
+ positive, so x[q] will decrease */
+ dir = -1;
+ }
+ /* if the problem is maximization, correct the direction */
+ if (P->dir == GLP_MAX) dir = - dir;
+ /* check that we didn't make a silly mistake */
+ if (dir > 0)
+ xassert(stat == GLP_NL || stat == GLP_NF);
+ else
+ xassert(stat == GLP_NU || stat == GLP_NF);
+ /* compute column of the simplex table corresponding to the
+ non-basic variable x[q] */
+ clen = glp_eval_tab_col(P, q, cind, cval);
+ /* make x[k] temporarily free (unbounded) */
+ if (k <= m)
+ { row = P->row[k];
+ row->type = GLP_FR;
+ row->lb = row->ub = 0.0;
+ }
+ else
+ { col = P->col[k-m];
+ col->type = GLP_FR;
+ col->lb = col->ub = 0.0;
+ }
+ /* use the primal ratio test to determine some basic variable
+ which leaves the basis */
+ cpiv = glp_prim_rtest(P, clen, cind, cval, dir, 1e-9);
+ /* restore original bounds of the basic variable x[k] */
+ if (k <= m)
+ { row = P->row[k];
+ row->type = type;
+ row->lb = lb, row->ub = ub;
+ }
+ else
+ { col = P->col[k-m];
+ col->type = type;
+ col->lb = lb, col->ub = ub;
+ }
+ if (cpiv == 0)
+ { /* non-basic variable x[q] can change unlimitedly */
+ if (dir < 0 && rval[rpiv] > 0.0 ||
+ dir > 0 && rval[rpiv] < 0.0)
+ { /* delta x[k] = alfa[k,q] * delta x[q] < 0 */
+ new_x = -DBL_MAX;
+ }
+ else
+ { /* delta x[k] = alfa[k,q] * delta x[q] > 0 */
+ new_x = +DBL_MAX;
+ }
+ goto store;
+ }
+ /* some basic variable x[p] limits changing non-basic variable
+ x[q] in the adjacent basis */
+ xassert(1 <= cpiv && cpiv <= clen);
+ p = cind[cpiv];
+ xassert(1 <= p && p <= m+n);
+ xassert(p != k);
+ if (p <= m)
+ { row = P->row[p];
+ xassert(row->stat == GLP_BS);
+ ll = glp_get_row_lb(P, row->i);
+ uu = glp_get_row_ub(P, row->i);
+ xx = row->prim;
+ }
+ else
+ { col = P->col[p-m];
+ xassert(col->stat == GLP_BS);
+ ll = glp_get_col_lb(P, col->j);
+ uu = glp_get_col_ub(P, col->j);
+ xx = col->prim;
+ }
+ /* determine delta x[p] = new x[p] - x[p] */
+ if (dir < 0 && cval[cpiv] > 0.0 ||
+ dir > 0 && cval[cpiv] < 0.0)
+ { /* delta x[p] < 0, so x[p] goes toward its lower bound */
+ xassert(ll != -DBL_MAX);
+ delta = ll - xx;
+ }
+ else
+ { /* delta x[p] > 0, so x[p] goes toward its upper bound */
+ xassert(uu != +DBL_MAX);
+ delta = uu - xx;
+ }
+ /* compute new x[k] = x[k] + alfa[k,q] * delta x[q], where
+ delta x[q] = delta x[p] / alfa[p,q] */
+ xassert(cval[cpiv] != 0.0);
+ new_x = x + (rval[rpiv] / cval[cpiv]) * delta;
+store: /* store analysis results */
+ if (kase < 0)
+ { if (coef1 != NULL) *coef1 = lim_coef;
+ if (var1 != NULL) *var1 = q;
+ if (value1 != NULL) *value1 = new_x;
+ }
+ else
+ { if (coef2 != NULL) *coef2 = lim_coef;
+ if (var2 != NULL) *var2 = q;
+ if (value2 != NULL) *value2 = new_x;
+ }
+ }
+ /* free working arrays */
+ xfree(cind);
+ xfree(cval);
+ xfree(rind);
+ xfree(rval);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpapi13.c b/test/monniaux/glpk-4.65/src/draft/glpapi13.c
new file mode 100644
index 00000000..1181b397
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpapi13.c
@@ -0,0 +1,710 @@
+/* glpapi13.c (branch-and-bound interface routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_reason - determine reason for calling the callback routine
+*
+* SYNOPSIS
+*
+* glp_ios_reason(glp_tree *tree);
+*
+* RETURNS
+*
+* The routine glp_ios_reason returns a code, which indicates why the
+* user-defined callback routine is being called. */
+
+int glp_ios_reason(glp_tree *tree)
+{ return
+ tree->reason;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_get_prob - access the problem object
+*
+* SYNOPSIS
+*
+* glp_prob *glp_ios_get_prob(glp_tree *tree);
+*
+* DESCRIPTION
+*
+* The routine glp_ios_get_prob can be called from the user-defined
+* callback routine to access the problem object, which is used by the
+* MIP solver. It is the original problem object passed to the routine
+* glp_intopt if the MIP presolver is not used; otherwise it is an
+* internal problem object built by the presolver. If the current
+* subproblem exists, LP segment of the problem object corresponds to
+* its LP relaxation.
+*
+* RETURNS
+*
+* The routine glp_ios_get_prob returns a pointer to the problem object
+* used by the MIP solver. */
+
+glp_prob *glp_ios_get_prob(glp_tree *tree)
+{ return
+ tree->mip;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_tree_size - determine size of the branch-and-bound tree
+*
+* SYNOPSIS
+*
+* void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
+* int *t_cnt);
+*
+* DESCRIPTION
+*
+* The routine glp_ios_tree_size stores the following three counts which
+* characterize the current size of the branch-and-bound tree:
+*
+* a_cnt is the current number of active nodes, i.e. the current size of
+* the active list;
+*
+* n_cnt is the current number of all (active and inactive) nodes;
+*
+* t_cnt is the total number of nodes including those which have been
+* already removed from the tree. This count is increased whenever
+* a new node appears in the tree and never decreased.
+*
+* If some of the parameters a_cnt, n_cnt, t_cnt is a null pointer, the
+* corresponding count is not stored. */
+
+void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
+ int *t_cnt)
+{ if (a_cnt != NULL) *a_cnt = tree->a_cnt;
+ if (n_cnt != NULL) *n_cnt = tree->n_cnt;
+ if (t_cnt != NULL) *t_cnt = tree->t_cnt;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_curr_node - determine current active subproblem
+*
+* SYNOPSIS
+*
+* int glp_ios_curr_node(glp_tree *tree);
+*
+* RETURNS
+*
+* The routine glp_ios_curr_node returns the reference number of the
+* current active subproblem. However, if the current subproblem does
+* not exist, the routine returns zero. */
+
+int glp_ios_curr_node(glp_tree *tree)
+{ IOSNPD *node;
+ /* obtain pointer to the current subproblem */
+ node = tree->curr;
+ /* return its reference number */
+ return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_next_node - determine next active subproblem
+*
+* SYNOPSIS
+*
+* int glp_ios_next_node(glp_tree *tree, int p);
+*
+* RETURNS
+*
+* If the parameter p is zero, the routine glp_ios_next_node returns
+* the reference number of the first active subproblem. However, if the
+* tree is empty, zero is returned.
+*
+* If the parameter p is not zero, it must specify the reference number
+* of some active subproblem, in which case the routine returns the
+* reference number of the next active subproblem. However, if there is
+* no next active subproblem in the list, zero is returned.
+*
+* All subproblems in the active list are ordered chronologically, i.e.
+* subproblem A precedes subproblem B if A was created before B. */
+
+int glp_ios_next_node(glp_tree *tree, int p)
+{ IOSNPD *node;
+ if (p == 0)
+ { /* obtain pointer to the first active subproblem */
+ node = tree->head;
+ }
+ else
+ { /* obtain pointer to the specified subproblem */
+ if (!(1 <= p && p <= tree->nslots))
+err: xerror("glp_ios_next_node: p = %d; invalid subproblem refer"
+ "ence number\n", p);
+ node = tree->slot[p].node;
+ if (node == NULL) goto err;
+ /* the specified subproblem must be active */
+ if (node->count != 0)
+ xerror("glp_ios_next_node: p = %d; subproblem not in the ac"
+ "tive list\n", p);
+ /* obtain pointer to the next active subproblem */
+ node = node->next;
+ }
+ /* return the reference number */
+ return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_prev_node - determine previous active subproblem
+*
+* SYNOPSIS
+*
+* int glp_ios_prev_node(glp_tree *tree, int p);
+*
+* RETURNS
+*
+* If the parameter p is zero, the routine glp_ios_prev_node returns
+* the reference number of the last active subproblem. However, if the
+* tree is empty, zero is returned.
+*
+* If the parameter p is not zero, it must specify the reference number
+* of some active subproblem, in which case the routine returns the
+* reference number of the previous active subproblem. However, if there
+* is no previous active subproblem in the list, zero is returned.
+*
+* All subproblems in the active list are ordered chronologically, i.e.
+* subproblem A precedes subproblem B if A was created before B. */
+
+int glp_ios_prev_node(glp_tree *tree, int p)
+{ IOSNPD *node;
+ if (p == 0)
+ { /* obtain pointer to the last active subproblem */
+ node = tree->tail;
+ }
+ else
+ { /* obtain pointer to the specified subproblem */
+ if (!(1 <= p && p <= tree->nslots))
+err: xerror("glp_ios_prev_node: p = %d; invalid subproblem refer"
+ "ence number\n", p);
+ node = tree->slot[p].node;
+ if (node == NULL) goto err;
+ /* the specified subproblem must be active */
+ if (node->count != 0)
+ xerror("glp_ios_prev_node: p = %d; subproblem not in the ac"
+ "tive list\n", p);
+ /* obtain pointer to the previous active subproblem */
+ node = node->prev;
+ }
+ /* return the reference number */
+ return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_up_node - determine parent subproblem
+*
+* SYNOPSIS
+*
+* int glp_ios_up_node(glp_tree *tree, int p);
+*
+* RETURNS
+*
+* The parameter p must specify the reference number of some (active or
+* inactive) subproblem, in which case the routine iet_get_up_node
+* returns the reference number of its parent subproblem. However, if
+* the specified subproblem is the root of the tree and, therefore, has
+* no parent, the routine returns zero. */
+
+int glp_ios_up_node(glp_tree *tree, int p)
+{ IOSNPD *node;
+ /* obtain pointer to the specified subproblem */
+ if (!(1 <= p && p <= tree->nslots))
+err: xerror("glp_ios_up_node: p = %d; invalid subproblem reference "
+ "number\n", p);
+ node = tree->slot[p].node;
+ if (node == NULL) goto err;
+ /* obtain pointer to the parent subproblem */
+ node = node->up;
+ /* return the reference number */
+ return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_node_level - determine subproblem level
+*
+* SYNOPSIS
+*
+* int glp_ios_node_level(glp_tree *tree, int p);
+*
+* RETURNS
+*
+* The routine glp_ios_node_level returns the level of the subproblem,
+* whose reference number is p, in the branch-and-bound tree. (The root
+* subproblem has level 0, and the level of any other subproblem is the
+* level of its parent plus one.) */
+
+int glp_ios_node_level(glp_tree *tree, int p)
+{ IOSNPD *node;
+ /* obtain pointer to the specified subproblem */
+ if (!(1 <= p && p <= tree->nslots))
+err: xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
+ "ce number\n", p);
+ node = tree->slot[p].node;
+ if (node == NULL) goto err;
+ /* return the node level */
+ return node->level;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_node_bound - determine subproblem local bound
+*
+* SYNOPSIS
+*
+* double glp_ios_node_bound(glp_tree *tree, int p);
+*
+* RETURNS
+*
+* The routine glp_ios_node_bound returns the local bound for (active or
+* inactive) subproblem, whose reference number is p.
+*
+* COMMENTS
+*
+* The local bound for subproblem p is an lower (minimization) or upper
+* (maximization) bound for integer optimal solution to this subproblem
+* (not to the original problem). This bound is local in the sense that
+* only subproblems in the subtree rooted at node p cannot have better
+* integer feasible solutions.
+*
+* On creating a subproblem (due to the branching step) its local bound
+* is inherited from its parent and then may get only stronger (never
+* weaker). For the root subproblem its local bound is initially set to
+* -DBL_MAX (minimization) or +DBL_MAX (maximization) and then improved
+* as the root LP relaxation has been solved.
+*
+* Note that the local bound is not necessarily the optimal objective
+* value to corresponding LP relaxation; it may be stronger. */
+
+double glp_ios_node_bound(glp_tree *tree, int p)
+{ IOSNPD *node;
+ /* obtain pointer to the specified subproblem */
+ if (!(1 <= p && p <= tree->nslots))
+err: xerror("glp_ios_node_bound: p = %d; invalid subproblem referen"
+ "ce number\n", p);
+ node = tree->slot[p].node;
+ if (node == NULL) goto err;
+ /* return the node local bound */
+ return node->bound;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_best_node - find active subproblem with best local bound
+*
+* SYNOPSIS
+*
+* int glp_ios_best_node(glp_tree *tree);
+*
+* RETURNS
+*
+* The routine glp_ios_best_node returns the reference number of the
+* active subproblem, whose local bound is best (i.e. smallest in case
+* of minimization or largest in case of maximization). However, if the
+* tree is empty, the routine returns zero.
+*
+* COMMENTS
+*
+* The best local bound is an lower (minimization) or upper
+* (maximization) bound for integer optimal solution to the original
+* MIP problem. */
+
+int glp_ios_best_node(glp_tree *tree)
+{ return
+ ios_best_node(tree);
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_mip_gap - compute relative MIP gap
+*
+* SYNOPSIS
+*
+* double glp_ios_mip_gap(glp_tree *tree);
+*
+* DESCRIPTION
+*
+* The routine glp_ios_mip_gap computes the relative MIP gap with the
+* following formula:
+*
+* gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
+*
+* where best_mip is the best integer feasible solution found so far,
+* best_bnd is the best (global) bound. If no integer feasible solution
+* has been found yet, gap is set to DBL_MAX.
+*
+* RETURNS
+*
+* The routine glp_ios_mip_gap returns the relative MIP gap. */
+
+double glp_ios_mip_gap(glp_tree *tree)
+{ return
+ ios_relative_gap(tree);
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_node_data - access subproblem application-specific data
+*
+* SYNOPSIS
+*
+* void *glp_ios_node_data(glp_tree *tree, int p);
+*
+* DESCRIPTION
+*
+* The routine glp_ios_node_data allows the application accessing a
+* memory block allocated for the subproblem (which may be active or
+* inactive), whose reference number is p.
+*
+* The size of the block is defined by the control parameter cb_size
+* passed to the routine glp_intopt. The block is initialized by binary
+* zeros on creating corresponding subproblem, and its contents is kept
+* until the subproblem will be removed from the tree.
+*
+* The application may use these memory blocks to store specific data
+* for each subproblem.
+*
+* RETURNS
+*
+* The routine glp_ios_node_data returns a pointer to the memory block
+* for the specified subproblem. Note that if cb_size = 0, the routine
+* returns a null pointer. */
+
+void *glp_ios_node_data(glp_tree *tree, int p)
+{ IOSNPD *node;
+ /* obtain pointer to the specified subproblem */
+ if (!(1 <= p && p <= tree->nslots))
+err: xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
+ "ce number\n", p);
+ node = tree->slot[p].node;
+ if (node == NULL) goto err;
+ /* return pointer to the application-specific data */
+ return node->data;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_row_attr - retrieve additional row attributes
+*
+* SYNOPSIS
+*
+* void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr);
+*
+* DESCRIPTION
+*
+* The routine glp_ios_row_attr retrieves additional attributes of row
+* i and stores them in the structure glp_attr. */
+
+void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr)
+{ GLPROW *row;
+ if (!(1 <= i && i <= tree->mip->m))
+ xerror("glp_ios_row_attr: i = %d; row number out of range\n",
+ i);
+ row = tree->mip->row[i];
+ attr->level = row->level;
+ attr->origin = row->origin;
+ attr->klass = row->klass;
+ return;
+}
+
+/**********************************************************************/
+
+int glp_ios_pool_size(glp_tree *tree)
+{ /* determine current size of the cut pool */
+ if (tree->reason != GLP_ICUTGEN)
+ xerror("glp_ios_pool_size: operation not allowed\n");
+ xassert(tree->local != NULL);
+#ifdef NEW_LOCAL /* 02/II-2018 */
+ return tree->local->m;
+#else
+ return tree->local->size;
+#endif
+}
+
+/**********************************************************************/
+
+int glp_ios_add_row(glp_tree *tree,
+ const char *name, int klass, int flags, int len, const int ind[],
+ const double val[], int type, double rhs)
+{ /* add row (constraint) to the cut pool */
+ int num;
+ if (tree->reason != GLP_ICUTGEN)
+ xerror("glp_ios_add_row: operation not allowed\n");
+ xassert(tree->local != NULL);
+ num = ios_add_row(tree, tree->local, name, klass, flags, len,
+ ind, val, type, rhs);
+ return num;
+}
+
+/**********************************************************************/
+
+void glp_ios_del_row(glp_tree *tree, int i)
+{ /* remove row (constraint) from the cut pool */
+ if (tree->reason != GLP_ICUTGEN)
+ xerror("glp_ios_del_row: operation not allowed\n");
+ ios_del_row(tree, tree->local, i);
+ return;
+}
+
+/**********************************************************************/
+
+void glp_ios_clear_pool(glp_tree *tree)
+{ /* remove all rows (constraints) from the cut pool */
+ if (tree->reason != GLP_ICUTGEN)
+ xerror("glp_ios_clear_pool: operation not allowed\n");
+ ios_clear_pool(tree, tree->local);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_can_branch - check if can branch upon specified variable
+*
+* SYNOPSIS
+*
+* int glp_ios_can_branch(glp_tree *tree, int j);
+*
+* RETURNS
+*
+* If j-th variable (column) can be used to branch upon, the routine
+* glp_ios_can_branch returns non-zero, otherwise zero. */
+
+int glp_ios_can_branch(glp_tree *tree, int j)
+{ if (!(1 <= j && j <= tree->mip->n))
+ xerror("glp_ios_can_branch: j = %d; column number out of range"
+ "\n", j);
+ return tree->non_int[j];
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_branch_upon - choose variable to branch upon
+*
+* SYNOPSIS
+*
+* void glp_ios_branch_upon(glp_tree *tree, int j, int sel);
+*
+* DESCRIPTION
+*
+* The routine glp_ios_branch_upon can be called from the user-defined
+* callback routine in response to the reason GLP_IBRANCH to choose a
+* branching variable, whose ordinal number is j. Should note that only
+* variables, for which the routine glp_ios_can_branch returns non-zero,
+* can be used to branch upon.
+*
+* The parameter sel is a flag that indicates which branch (subproblem)
+* should be selected next to continue the search:
+*
+* GLP_DN_BRNCH - select down-branch;
+* GLP_UP_BRNCH - select up-branch;
+* GLP_NO_BRNCH - use general selection technique. */
+
+void glp_ios_branch_upon(glp_tree *tree, int j, int sel)
+{ if (!(1 <= j && j <= tree->mip->n))
+ xerror("glp_ios_branch_upon: j = %d; column number out of rang"
+ "e\n", j);
+ if (!(sel == GLP_DN_BRNCH || sel == GLP_UP_BRNCH ||
+ sel == GLP_NO_BRNCH))
+ xerror("glp_ios_branch_upon: sel = %d: invalid branch selectio"
+ "n flag\n", sel);
+ if (!(tree->non_int[j]))
+ xerror("glp_ios_branch_upon: j = %d; variable cannot be used t"
+ "o branch upon\n", j);
+ if (tree->br_var != 0)
+ xerror("glp_ios_branch_upon: branching variable already chosen"
+ "\n");
+ tree->br_var = j;
+ tree->br_sel = sel;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_select_node - select subproblem to continue the search
+*
+* SYNOPSIS
+*
+* void glp_ios_select_node(glp_tree *tree, int p);
+*
+* DESCRIPTION
+*
+* The routine glp_ios_select_node can be called from the user-defined
+* callback routine in response to the reason GLP_ISELECT to select an
+* active subproblem, whose reference number is p. The search will be
+* continued from the subproblem selected. */
+
+void glp_ios_select_node(glp_tree *tree, int p)
+{ IOSNPD *node;
+ /* obtain pointer to the specified subproblem */
+ if (!(1 <= p && p <= tree->nslots))
+err: xerror("glp_ios_select_node: p = %d; invalid subproblem refere"
+ "nce number\n", p);
+ node = tree->slot[p].node;
+ if (node == NULL) goto err;
+ /* the specified subproblem must be active */
+ if (node->count != 0)
+ xerror("glp_ios_select_node: p = %d; subproblem not in the act"
+ "ive list\n", p);
+ /* no subproblem must be selected yet */
+ if (tree->next_p != 0)
+ xerror("glp_ios_select_node: subproblem already selected\n");
+ /* select the specified subproblem to continue the search */
+ tree->next_p = p;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_heur_sol - provide solution found by heuristic
+*
+* SYNOPSIS
+*
+* int glp_ios_heur_sol(glp_tree *tree, const double x[]);
+*
+* DESCRIPTION
+*
+* The routine glp_ios_heur_sol can be called from the user-defined
+* callback routine in response to the reason GLP_IHEUR to provide an
+* integer feasible solution found by a primal heuristic.
+*
+* Primal values of *all* variables (columns) found by the heuristic
+* should be placed in locations x[1], ..., x[n], where n is the number
+* of columns in the original problem object. Note that the routine
+* glp_ios_heur_sol *does not* check primal feasibility of the solution
+* provided.
+*
+* Using the solution passed in the array x the routine computes value
+* of the objective function. If the objective value is better than the
+* best known integer feasible solution, the routine computes values of
+* auxiliary variables (rows) and stores all solution components in the
+* problem object.
+*
+* RETURNS
+*
+* If the provided solution is accepted, the routine glp_ios_heur_sol
+* returns zero. Otherwise, if the provided solution is rejected, the
+* routine returns non-zero. */
+
+int glp_ios_heur_sol(glp_tree *tree, const double x[])
+{ glp_prob *mip = tree->mip;
+ int m = tree->orig_m;
+ int n = tree->n;
+ int i, j;
+ double obj;
+ xassert(mip->m >= m);
+ xassert(mip->n == n);
+ /* check values of integer variables and compute value of the
+ objective function */
+ obj = mip->c0;
+ for (j = 1; j <= n; j++)
+ { GLPCOL *col = mip->col[j];
+ if (col->kind == GLP_IV)
+ { /* provided value must be integral */
+ if (x[j] != floor(x[j])) return 1;
+ }
+ obj += col->coef * x[j];
+ }
+ /* check if the provided solution is better than the best known
+ integer feasible solution */
+ if (mip->mip_stat == GLP_FEAS)
+ { switch (mip->dir)
+ { case GLP_MIN:
+ if (obj >= tree->mip->mip_obj) return 1;
+ break;
+ case GLP_MAX:
+ if (obj <= tree->mip->mip_obj) return 1;
+ break;
+ default:
+ xassert(mip != mip);
+ }
+ }
+ /* it is better; store it in the problem object */
+ if (tree->parm->msg_lev >= GLP_MSG_ON)
+ xprintf("Solution found by heuristic: %.12g\n", obj);
+ mip->mip_stat = GLP_FEAS;
+ mip->mip_obj = obj;
+ for (j = 1; j <= n; j++)
+ mip->col[j]->mipx = x[j];
+ for (i = 1; i <= m; i++)
+ { GLPROW *row = mip->row[i];
+ GLPAIJ *aij;
+ row->mipx = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ row->mipx += aij->val * aij->col->mipx;
+ }
+#if 1 /* 11/VII-2013 */
+ ios_process_sol(tree);
+#endif
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ios_terminate - terminate the solution process.
+*
+* SYNOPSIS
+*
+* void glp_ios_terminate(glp_tree *tree);
+*
+* DESCRIPTION
+*
+* The routine glp_ios_terminate sets a flag indicating that the MIP
+* solver should prematurely terminate the search. */
+
+void glp_ios_terminate(glp_tree *tree)
+{ if (tree->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("The search is prematurely terminated due to applicati"
+ "on request\n");
+ tree->stop = 1;
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glphbm.c b/test/monniaux/glpk-4.65/src/draft/glphbm.c
new file mode 100644
index 00000000..8b33c172
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glphbm.c
@@ -0,0 +1,533 @@
+/* glphbm.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glphbm.h"
+#include "misc.h"
+
+/***********************************************************************
+* NAME
+*
+* hbm_read_mat - read sparse matrix in Harwell-Boeing format
+*
+* SYNOPSIS
+*
+* #include "glphbm.h"
+* HBM *hbm_read_mat(const char *fname);
+*
+* DESCRIPTION
+*
+* The routine hbm_read_mat reads a sparse matrix in the Harwell-Boeing
+* format from a text file whose name is the character string fname.
+*
+* Detailed description of the Harwell-Boeing format recognised by this
+* routine is given in the following report:
+*
+* I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
+* Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
+*
+* RETURNS
+*
+* If no error occured, the routine hbm_read_mat returns a pointer to
+* a data structure containing the matrix. In case of error the routine
+* prints an appropriate error message and returns NULL. */
+
+struct dsa
+{ /* working area used by routine hbm_read_mat */
+ const char *fname;
+ /* name of input text file */
+ FILE *fp;
+ /* stream assigned to input text file */
+ int seqn;
+ /* card sequential number */
+ char card[80+1];
+ /* card image buffer */
+ int fmt_p;
+ /* scale factor */
+ int fmt_k;
+ /* iterator */
+ int fmt_f;
+ /* format code */
+ int fmt_w;
+ /* field width */
+ int fmt_d;
+ /* number of decimal places after point */
+};
+
+/***********************************************************************
+* read_card - read next data card
+*
+* This routine reads the next 80-column card from the input text file
+* and stores its image into the character string card. If the card was
+* read successfully, the routine returns zero, otherwise non-zero. */
+
+#if 1 /* 11/III-2012 */
+static int read_card(struct dsa *dsa)
+{ int c, len = 0;
+ char buf[255+1];
+ dsa->seqn++;
+ for (;;)
+ { c = fgetc(dsa->fp);
+ if (c == EOF)
+ { if (ferror(dsa->fp))
+ xprintf("%s:%d: read error\n",
+ dsa->fname, dsa->seqn);
+ else
+ xprintf("%s:%d: unexpected end-of-file\n",
+ dsa->fname, dsa->seqn);
+ return 1;
+ }
+ else if (c == '\r')
+ /* nop */;
+ else if (c == '\n')
+ break;
+ else if (iscntrl(c))
+ { xprintf("%s:%d: invalid control character\n",
+ dsa->fname, dsa->seqn, c);
+ return 1;
+ }
+ else
+ { if (len == sizeof(buf)-1)
+ goto err;
+ buf[len++] = (char)c;
+ }
+ }
+ /* remove trailing spaces */
+ while (len > 80 && buf[len-1] == ' ')
+ len--;
+ buf[len] = '\0';
+ /* line should not be longer than 80 chars */
+ if (len > 80)
+err: { xerror("%s:%d: card image too long\n",
+ dsa->fname, dsa->seqn);
+ return 1;
+ }
+ /* padd by spaces to 80-column card image */
+ strcpy(dsa->card, buf);
+ memset(&dsa->card[len], ' ', 80 - len);
+ dsa->card[80] = '\0';
+ return 0;
+}
+#endif
+
+/***********************************************************************
+* scan_int - scan integer value from the current card
+*
+* This routine scans an integer value from the current card, where fld
+* is the name of the field, pos is the position of the field, width is
+* the width of the field, val points to a location to which the scanned
+* value should be stored. If the value was scanned successfully, the
+* routine returns zero, otherwise non-zero. */
+
+static int scan_int(struct dsa *dsa, char *fld, int pos, int width,
+ int *val)
+{ char str[80+1];
+ xassert(1 <= width && width <= 80);
+ memcpy(str, dsa->card + pos, width), str[width] = '\0';
+ if (str2int(strspx(str), val))
+ { xprintf("%s:%d: field '%s' contains invalid value '%s'\n",
+ dsa->fname, dsa->seqn, fld, str);
+ return 1;
+ }
+ return 0;
+}
+
+/***********************************************************************
+* parse_fmt - parse Fortran format specification
+*
+* This routine parses the Fortran format specification represented as
+* character string which fmt points to and stores format elements into
+* appropriate static locations. Should note that not all valid Fortran
+* format specifications may be recognised. If the format specification
+* was recognised, the routine returns zero, otherwise non-zero. */
+
+static int parse_fmt(struct dsa *dsa, char *fmt)
+{ int k, s, val;
+ char str[80+1];
+ /* first character should be left parenthesis */
+ if (fmt[0] != '(')
+fail: { xprintf("hbm_read_mat: format '%s' not recognised\n", fmt);
+ return 1;
+ }
+ k = 1;
+ /* optional scale factor */
+ dsa->fmt_p = 0;
+ if (isdigit((unsigned char)fmt[k]))
+ { s = 0;
+ while (isdigit((unsigned char)fmt[k]))
+ { if (s == 80) goto fail;
+ str[s++] = fmt[k++];
+ }
+ str[s] = '\0';
+ if (str2int(str, &val)) goto fail;
+ if (toupper((unsigned char)fmt[k]) != 'P') goto iter;
+ dsa->fmt_p = val, k++;
+ if (!(0 <= dsa->fmt_p && dsa->fmt_p <= 255)) goto fail;
+ /* optional comma may follow scale factor */
+ if (fmt[k] == ',') k++;
+ }
+ /* optional iterator */
+ dsa->fmt_k = 1;
+ if (isdigit((unsigned char)fmt[k]))
+ { s = 0;
+ while (isdigit((unsigned char)fmt[k]))
+ { if (s == 80) goto fail;
+ str[s++] = fmt[k++];
+ }
+ str[s] = '\0';
+ if (str2int(str, &val)) goto fail;
+iter: dsa->fmt_k = val;
+ if (!(1 <= dsa->fmt_k && dsa->fmt_k <= 255)) goto fail;
+ }
+ /* format code */
+ dsa->fmt_f = toupper((unsigned char)fmt[k++]);
+ if (!(dsa->fmt_f == 'D' || dsa->fmt_f == 'E' ||
+ dsa->fmt_f == 'F' || dsa->fmt_f == 'G' ||
+ dsa->fmt_f == 'I')) goto fail;
+ /* field width */
+ if (!isdigit((unsigned char)fmt[k])) goto fail;
+ s = 0;
+ while (isdigit((unsigned char)fmt[k]))
+ { if (s == 80) goto fail;
+ str[s++] = fmt[k++];
+ }
+ str[s] = '\0';
+ if (str2int(str, &dsa->fmt_w)) goto fail;
+ if (!(1 <= dsa->fmt_w && dsa->fmt_w <= 255)) goto fail;
+ /* optional number of decimal places after point */
+ dsa->fmt_d = 0;
+ if (fmt[k] == '.')
+ { k++;
+ if (!isdigit((unsigned char)fmt[k])) goto fail;
+ s = 0;
+ while (isdigit((unsigned char)fmt[k]))
+ { if (s == 80) goto fail;
+ str[s++] = fmt[k++];
+ }
+ str[s] = '\0';
+ if (str2int(str, &dsa->fmt_d)) goto fail;
+ if (!(0 <= dsa->fmt_d && dsa->fmt_d <= 255)) goto fail;
+ }
+ /* last character should be right parenthesis */
+ if (!(fmt[k] == ')' && fmt[k+1] == '\0')) goto fail;
+ return 0;
+}
+
+/***********************************************************************
+* read_int_array - read array of integer type
+*
+* This routine reads an integer array from the input text file, where
+* name is array name, fmt is Fortran format specification that controls
+* reading, n is number of array elements, val is array of integer type.
+* If the array was read successful, the routine returns zero, otherwise
+* non-zero. */
+
+static int read_int_array(struct dsa *dsa, char *name, char *fmt,
+ int n, int val[])
+{ int k, pos;
+ char str[80+1];
+ if (parse_fmt(dsa, fmt)) return 1;
+ if (!(dsa->fmt_f == 'I' && dsa->fmt_w <= 80 &&
+ dsa->fmt_k * dsa->fmt_w <= 80))
+ { xprintf(
+ "%s:%d: can't read array '%s' - invalid format '%s'\n",
+ dsa->fname, dsa->seqn, name, fmt);
+ return 1;
+ }
+ for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
+ { if (pos >= dsa->fmt_k)
+ { if (read_card(dsa)) return 1;
+ pos = 0;
+ }
+ memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
+ str[dsa->fmt_w] = '\0';
+ strspx(str);
+ if (str2int(str, &val[k]))
+ { xprintf(
+ "%s:%d: can't read array '%s' - invalid value '%s'\n",
+ dsa->fname, dsa->seqn, name, str);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* read_real_array - read array of real type
+*
+* This routine reads a real array from the input text file, where name
+* is array name, fmt is Fortran format specification that controls
+* reading, n is number of array elements, val is array of real type.
+* If the array was read successful, the routine returns zero, otherwise
+* non-zero. */
+
+static int read_real_array(struct dsa *dsa, char *name, char *fmt,
+ int n, double val[])
+{ int k, pos;
+ char str[80+1], *ptr;
+ if (parse_fmt(dsa, fmt)) return 1;
+ if (!(dsa->fmt_f != 'I' && dsa->fmt_w <= 80 &&
+ dsa->fmt_k * dsa->fmt_w <= 80))
+ { xprintf(
+ "%s:%d: can't read array '%s' - invalid format '%s'\n",
+ dsa->fname, dsa->seqn, name, fmt);
+ return 1;
+ }
+ for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
+ { if (pos >= dsa->fmt_k)
+ { if (read_card(dsa)) return 1;
+ pos = 0;
+ }
+ memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
+ str[dsa->fmt_w] = '\0';
+ strspx(str);
+ if (strchr(str, '.') == NULL && strcmp(str, "0"))
+ { xprintf("%s(%d): can't read array '%s' - value '%s' has no "
+ "decimal point\n", dsa->fname, dsa->seqn, name, str);
+ return 1;
+ }
+ /* sometimes lower case letters appear */
+ for (ptr = str; *ptr; ptr++)
+ *ptr = (char)toupper((unsigned char)*ptr);
+ ptr = strchr(str, 'D');
+ if (ptr != NULL) *ptr = 'E';
+ /* value may appear with decimal exponent but without letters
+ E or D (for example, -123.456-012), so missing letter should
+ be inserted */
+ ptr = strchr(str+1, '+');
+ if (ptr == NULL) ptr = strchr(str+1, '-');
+ if (ptr != NULL && *(ptr-1) != 'E')
+ { xassert(strlen(str) < 80);
+ memmove(ptr+1, ptr, strlen(ptr)+1);
+ *ptr = 'E';
+ }
+ if (str2num(str, &val[k]))
+ { xprintf(
+ "%s:%d: can't read array '%s' - invalid value '%s'\n",
+ dsa->fname, dsa->seqn, name, str);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+HBM *hbm_read_mat(const char *fname)
+{ struct dsa _dsa, *dsa = &_dsa;
+ HBM *hbm = NULL;
+ dsa->fname = fname;
+ xprintf("hbm_read_mat: reading matrix from '%s'...\n",
+ dsa->fname);
+ dsa->fp = fopen(dsa->fname, "r");
+ if (dsa->fp == NULL)
+ { xprintf("hbm_read_mat: unable to open '%s' - %s\n",
+#if 0 /* 29/I-2017 */
+ dsa->fname, strerror(errno));
+#else
+ dsa->fname, xstrerr(errno));
+#endif
+ goto fail;
+ }
+ dsa->seqn = 0;
+ hbm = xmalloc(sizeof(HBM));
+ memset(hbm, 0, sizeof(HBM));
+ /* read the first heading card */
+ if (read_card(dsa)) goto fail;
+ memcpy(hbm->title, dsa->card, 72), hbm->title[72] = '\0';
+ strtrim(hbm->title);
+ xprintf("%s\n", hbm->title);
+ memcpy(hbm->key, dsa->card+72, 8), hbm->key[8] = '\0';
+ strspx(hbm->key);
+ xprintf("key = %s\n", hbm->key);
+ /* read the second heading card */
+ if (read_card(dsa)) goto fail;
+ if (scan_int(dsa, "totcrd", 0, 14, &hbm->totcrd)) goto fail;
+ if (scan_int(dsa, "ptrcrd", 14, 14, &hbm->ptrcrd)) goto fail;
+ if (scan_int(dsa, "indcrd", 28, 14, &hbm->indcrd)) goto fail;
+ if (scan_int(dsa, "valcrd", 42, 14, &hbm->valcrd)) goto fail;
+ if (scan_int(dsa, "rhscrd", 56, 14, &hbm->rhscrd)) goto fail;
+ xprintf("totcrd = %d; ptrcrd = %d; indcrd = %d; valcrd = %d; rhsc"
+ "rd = %d\n", hbm->totcrd, hbm->ptrcrd, hbm->indcrd,
+ hbm->valcrd, hbm->rhscrd);
+ /* read the third heading card */
+ if (read_card(dsa)) goto fail;
+ memcpy(hbm->mxtype, dsa->card, 3), hbm->mxtype[3] = '\0';
+ if (strchr("RCP", hbm->mxtype[0]) == NULL ||
+ strchr("SUHZR", hbm->mxtype[1]) == NULL ||
+ strchr("AE", hbm->mxtype[2]) == NULL)
+ { xprintf("%s:%d: matrix type '%s' not recognised\n",
+ dsa->fname, dsa->seqn, hbm->mxtype);
+ goto fail;
+ }
+ if (scan_int(dsa, "nrow", 14, 14, &hbm->nrow)) goto fail;
+ if (scan_int(dsa, "ncol", 28, 14, &hbm->ncol)) goto fail;
+ if (scan_int(dsa, "nnzero", 42, 14, &hbm->nnzero)) goto fail;
+ if (scan_int(dsa, "neltvl", 56, 14, &hbm->neltvl)) goto fail;
+ xprintf("mxtype = %s; nrow = %d; ncol = %d; nnzero = %d; neltvl ="
+ " %d\n", hbm->mxtype, hbm->nrow, hbm->ncol, hbm->nnzero,
+ hbm->neltvl);
+ /* read the fourth heading card */
+ if (read_card(dsa)) goto fail;
+ memcpy(hbm->ptrfmt, dsa->card, 16), hbm->ptrfmt[16] = '\0';
+ strspx(hbm->ptrfmt);
+ memcpy(hbm->indfmt, dsa->card+16, 16), hbm->indfmt[16] = '\0';
+ strspx(hbm->indfmt);
+ memcpy(hbm->valfmt, dsa->card+32, 20), hbm->valfmt[20] = '\0';
+ strspx(hbm->valfmt);
+ memcpy(hbm->rhsfmt, dsa->card+52, 20), hbm->rhsfmt[20] = '\0';
+ strspx(hbm->rhsfmt);
+ xprintf("ptrfmt = %s; indfmt = %s; valfmt = %s; rhsfmt = %s\n",
+ hbm->ptrfmt, hbm->indfmt, hbm->valfmt, hbm->rhsfmt);
+ /* read the fifth heading card (optional) */
+ if (hbm->rhscrd <= 0)
+ { strcpy(hbm->rhstyp, "???");
+ hbm->nrhs = 0;
+ hbm->nrhsix = 0;
+ }
+ else
+ { if (read_card(dsa)) goto fail;
+ memcpy(hbm->rhstyp, dsa->card, 3), hbm->rhstyp[3] = '\0';
+ if (scan_int(dsa, "nrhs", 14, 14, &hbm->nrhs)) goto fail;
+ if (scan_int(dsa, "nrhsix", 28, 14, &hbm->nrhsix)) goto fail;
+ xprintf("rhstyp = '%s'; nrhs = %d; nrhsix = %d\n",
+ hbm->rhstyp, hbm->nrhs, hbm->nrhsix);
+ }
+ /* read matrix structure */
+ hbm->colptr = xcalloc(1+hbm->ncol+1, sizeof(int));
+ if (read_int_array(dsa, "colptr", hbm->ptrfmt, hbm->ncol+1,
+ hbm->colptr)) goto fail;
+ hbm->rowind = xcalloc(1+hbm->nnzero, sizeof(int));
+ if (read_int_array(dsa, "rowind", hbm->indfmt, hbm->nnzero,
+ hbm->rowind)) goto fail;
+ /* read matrix values */
+ if (hbm->valcrd <= 0) goto done;
+ if (hbm->mxtype[2] == 'A')
+ { /* assembled matrix */
+ hbm->values = xcalloc(1+hbm->nnzero, sizeof(double));
+ if (read_real_array(dsa, "values", hbm->valfmt, hbm->nnzero,
+ hbm->values)) goto fail;
+ }
+ else
+ { /* elemental (unassembled) matrix */
+ hbm->values = xcalloc(1+hbm->neltvl, sizeof(double));
+ if (read_real_array(dsa, "values", hbm->valfmt, hbm->neltvl,
+ hbm->values)) goto fail;
+ }
+ /* read right-hand sides */
+ if (hbm->nrhs <= 0) goto done;
+ if (hbm->rhstyp[0] == 'F')
+ { /* dense format */
+ hbm->nrhsvl = hbm->nrow * hbm->nrhs;
+ hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
+ if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
+ hbm->rhsval)) goto fail;
+ }
+ else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'A')
+ { /* sparse format */
+ /* read pointers */
+ hbm->rhsptr = xcalloc(1+hbm->nrhs+1, sizeof(int));
+ if (read_int_array(dsa, "rhsptr", hbm->ptrfmt, hbm->nrhs+1,
+ hbm->rhsptr)) goto fail;
+ /* read sparsity pattern */
+ hbm->rhsind = xcalloc(1+hbm->nrhsix, sizeof(int));
+ if (read_int_array(dsa, "rhsind", hbm->indfmt, hbm->nrhsix,
+ hbm->rhsind)) goto fail;
+ /* read values */
+ hbm->rhsval = xcalloc(1+hbm->nrhsix, sizeof(double));
+ if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsix,
+ hbm->rhsval)) goto fail;
+ }
+ else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'E')
+ { /* elemental format */
+ hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
+ if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
+ hbm->rhsval)) goto fail;
+ }
+ else
+ { xprintf("%s:%d: right-hand side type '%c' not recognised\n",
+ dsa->fname, dsa->seqn, hbm->rhstyp[0]);
+ goto fail;
+ }
+ /* read starting guesses */
+ if (hbm->rhstyp[1] == 'G')
+ { hbm->nguess = hbm->nrow * hbm->nrhs;
+ hbm->sguess = xcalloc(1+hbm->nguess, sizeof(double));
+ if (read_real_array(dsa, "sguess", hbm->rhsfmt, hbm->nguess,
+ hbm->sguess)) goto fail;
+ }
+ /* read solution vectors */
+ if (hbm->rhstyp[2] == 'X')
+ { hbm->nexact = hbm->nrow * hbm->nrhs;
+ hbm->xexact = xcalloc(1+hbm->nexact, sizeof(double));
+ if (read_real_array(dsa, "xexact", hbm->rhsfmt, hbm->nexact,
+ hbm->xexact)) goto fail;
+ }
+done: /* reading has been completed */
+ xprintf("hbm_read_mat: %d cards were read\n", dsa->seqn);
+ fclose(dsa->fp);
+ return hbm;
+fail: /* something wrong in Danish kingdom */
+ if (hbm != NULL)
+ { if (hbm->colptr != NULL) xfree(hbm->colptr);
+ if (hbm->rowind != NULL) xfree(hbm->rowind);
+ if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
+ if (hbm->rhsind != NULL) xfree(hbm->rhsind);
+ if (hbm->values != NULL) xfree(hbm->values);
+ if (hbm->rhsval != NULL) xfree(hbm->rhsval);
+ if (hbm->sguess != NULL) xfree(hbm->sguess);
+ if (hbm->xexact != NULL) xfree(hbm->xexact);
+ xfree(hbm);
+ }
+ if (dsa->fp != NULL) fclose(dsa->fp);
+ return NULL;
+}
+
+/***********************************************************************
+* NAME
+*
+* hbm_free_mat - free sparse matrix in Harwell-Boeing format
+*
+* SYNOPSIS
+*
+* #include "glphbm.h"
+* void hbm_free_mat(HBM *hbm);
+*
+* DESCRIPTION
+*
+* The hbm_free_mat routine frees all the memory allocated to the data
+* structure containing a sparse matrix in the Harwell-Boeing format. */
+
+void hbm_free_mat(HBM *hbm)
+{ if (hbm->colptr != NULL) xfree(hbm->colptr);
+ if (hbm->rowind != NULL) xfree(hbm->rowind);
+ if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
+ if (hbm->rhsind != NULL) xfree(hbm->rhsind);
+ if (hbm->values != NULL) xfree(hbm->values);
+ if (hbm->rhsval != NULL) xfree(hbm->rhsval);
+ if (hbm->sguess != NULL) xfree(hbm->sguess);
+ if (hbm->xexact != NULL) xfree(hbm->xexact);
+ xfree(hbm);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glphbm.h b/test/monniaux/glpk-4.65/src/draft/glphbm.h
new file mode 100644
index 00000000..688a78ec
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glphbm.h
@@ -0,0 +1,127 @@
+/* glphbm.h (Harwell-Boeing sparse matrix format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#ifndef GLPHBM_H
+#define GLPHBM_H
+
+typedef struct HBM HBM;
+
+struct HBM
+{ /* sparse matrix in Harwell-Boeing format; for details see the
+ report: I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the
+ Harwell-Boeing Sparse Matrix Collection (Release I), 1992 */
+ char title[72+1];
+ /* matrix title (informative) */
+ char key[8+1];
+ /* matrix key (informative) */
+ char mxtype[3+1];
+ /* matrix type:
+ R.. real matrix
+ C.. complex matrix
+ P.. pattern only (no numerical values supplied)
+ .S. symmetric (lower triangle + main diagonal)
+ .U. unsymmetric
+ .H. hermitian (lower triangle + main diagonal)
+ .Z. skew symmetric (lower triangle only)
+ .R. rectangular
+ ..A assembled
+ ..E elemental (unassembled) */
+ char rhstyp[3+1];
+ /* optional types:
+ F.. right-hand sides in dense format
+ M.. right-hand sides in same format as matrix
+ .G. starting vector(s) (guess) is supplied
+ ..X exact solution vector(s) is supplied */
+ char ptrfmt[16+1];
+ /* format for pointers */
+ char indfmt[16+1];
+ /* format for row (or variable) indices */
+ char valfmt[20+1];
+ /* format for numerical values of coefficient matrix */
+ char rhsfmt[20+1];
+ /* format for numerical values of right-hand sides */
+ int totcrd;
+ /* total number of cards excluding header */
+ int ptrcrd;
+ /* number of cards for ponters */
+ int indcrd;
+ /* number of cards for row (or variable) indices */
+ int valcrd;
+ /* number of cards for numerical values */
+ int rhscrd;
+ /* number of lines for right-hand sides;
+ including starting guesses and solution vectors if present;
+ zero indicates no right-hand side data is present */
+ int nrow;
+ /* number of rows (or variables) */
+ int ncol;
+ /* number of columns (or elements) */
+ int nnzero;
+ /* number of row (or variable) indices;
+ equal to number of entries for assembled matrix */
+ int neltvl;
+ /* number of elemental matrix entries;
+ zero in case of assembled matrix */
+ int nrhs;
+ /* number of right-hand sides */
+ int nrhsix;
+ /* number of row indices;
+ ignored in case of unassembled matrix */
+ int nrhsvl;
+ /* total number of entries in all right-hand sides */
+ int nguess;
+ /* total number of entries in all starting guesses */
+ int nexact;
+ /* total number of entries in all solution vectors */
+ int *colptr; /* alias: eltptr */
+ /* column pointers (in case of assembled matrix);
+ elemental matrix pointers (in case of unassembled matrix) */
+ int *rowind; /* alias: varind */
+ /* row indices (in case of assembled matrix);
+ variable indices (in case of unassembled matrix) */
+ int *rhsptr;
+ /* right-hand side pointers */
+ int *rhsind;
+ /* right-hand side indices */
+ double *values;
+ /* matrix values */
+ double *rhsval;
+ /* right-hand side values */
+ double *sguess;
+ /* starting guess values */
+ double *xexact;
+ /* solution vector values */
+};
+
+#define hbm_read_mat _glp_hbm_read_mat
+HBM *hbm_read_mat(const char *fname);
+/* read sparse matrix in Harwell-Boeing format */
+
+#define hbm_free_mat _glp_hbm_free_mat
+void hbm_free_mat(HBM *hbm);
+/* free sparse matrix in Harwell-Boeing format */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpios01.c b/test/monniaux/glpk-4.65/src/draft/glpios01.c
new file mode 100644
index 00000000..cb1a0dab
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpios01.c
@@ -0,0 +1,1685 @@
+/* glpios01.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+#include "misc.h"
+
+static int lpx_eval_tab_row(glp_prob *lp, int k, int ind[],
+ double val[])
+{ /* compute row of the simplex tableau */
+ return glp_eval_tab_row(lp, k, ind, val);
+}
+
+static int lpx_dual_ratio_test(glp_prob *lp, int len, const int ind[],
+ const double val[], int how, double tol)
+{ /* perform dual ratio test */
+ int piv;
+ piv = glp_dual_rtest(lp, len, ind, val, how, tol);
+ xassert(0 <= piv && piv <= len);
+ return piv == 0 ? 0 : ind[piv];
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_create_tree - create branch-and-bound tree
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
+*
+* DESCRIPTION
+*
+* The routine ios_create_tree creates the branch-and-bound tree.
+*
+* Being created the tree consists of the only root subproblem whose
+* reference number is 1. Note that initially the root subproblem is in
+* frozen state and therefore needs to be revived.
+*
+* RETURNS
+*
+* The routine returns a pointer to the tree created. */
+
+static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent);
+
+glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm)
+{ int m = mip->m;
+ int n = mip->n;
+ glp_tree *tree;
+ int i, j;
+ xassert(mip->tree == NULL);
+ mip->tree = tree = xmalloc(sizeof(glp_tree));
+ tree->pool = dmp_create_pool();
+ tree->n = n;
+ /* save original problem components */
+ tree->orig_m = m;
+ tree->orig_type = xcalloc(1+m+n, sizeof(char));
+ tree->orig_lb = xcalloc(1+m+n, sizeof(double));
+ tree->orig_ub = xcalloc(1+m+n, sizeof(double));
+ tree->orig_stat = xcalloc(1+m+n, sizeof(char));
+ tree->orig_prim = xcalloc(1+m+n, sizeof(double));
+ tree->orig_dual = xcalloc(1+m+n, sizeof(double));
+ for (i = 1; i <= m; i++)
+ { GLPROW *row = mip->row[i];
+ tree->orig_type[i] = (char)row->type;
+ tree->orig_lb[i] = row->lb;
+ tree->orig_ub[i] = row->ub;
+ tree->orig_stat[i] = (char)row->stat;
+ tree->orig_prim[i] = row->prim;
+ tree->orig_dual[i] = row->dual;
+ }
+ for (j = 1; j <= n; j++)
+ { GLPCOL *col = mip->col[j];
+ tree->orig_type[m+j] = (char)col->type;
+ tree->orig_lb[m+j] = col->lb;
+ tree->orig_ub[m+j] = col->ub;
+ tree->orig_stat[m+j] = (char)col->stat;
+ tree->orig_prim[m+j] = col->prim;
+ tree->orig_dual[m+j] = col->dual;
+ }
+ tree->orig_obj = mip->obj_val;
+ /* initialize the branch-and-bound tree */
+ tree->nslots = 0;
+ tree->avail = 0;
+ tree->slot = NULL;
+ tree->head = tree->tail = NULL;
+ tree->a_cnt = tree->n_cnt = tree->t_cnt = 0;
+ /* the root subproblem is not solved yet, so its final components
+ are unknown so far */
+ tree->root_m = 0;
+ tree->root_type = NULL;
+ tree->root_lb = tree->root_ub = NULL;
+ tree->root_stat = NULL;
+ /* the current subproblem does not exist yet */
+ tree->curr = NULL;
+ tree->mip = mip;
+ /*tree->solved = 0;*/
+ tree->non_int = xcalloc(1+n, sizeof(char));
+ memset(&tree->non_int[1], 0, n);
+ /* arrays to save parent subproblem components will be allocated
+ later */
+ tree->pred_m = tree->pred_max = 0;
+ tree->pred_type = NULL;
+ tree->pred_lb = tree->pred_ub = NULL;
+ tree->pred_stat = NULL;
+ /* cut generators */
+ tree->local = ios_create_pool(tree);
+ /*tree->first_attempt = 1;*/
+ /*tree->max_added_cuts = 0;*/
+ /*tree->min_eff = 0.0;*/
+ /*tree->miss = 0;*/
+ /*tree->just_selected = 0;*/
+#ifdef NEW_COVER /* 13/II-2018 */
+ tree->cov_gen = NULL;
+#endif
+ tree->mir_gen = NULL;
+ tree->clq_gen = NULL;
+ /*tree->round = 0;*/
+#if 0
+ /* create the conflict graph */
+ tree->n_ref = xcalloc(1+n, sizeof(int));
+ memset(&tree->n_ref[1], 0, n * sizeof(int));
+ tree->c_ref = xcalloc(1+n, sizeof(int));
+ memset(&tree->c_ref[1], 0, n * sizeof(int));
+ tree->g = scg_create_graph(0);
+ tree->j_ref = xcalloc(1+tree->g->n_max, sizeof(int));
+#endif
+ /* pseudocost branching */
+ tree->pcost = NULL;
+ tree->iwrk = xcalloc(1+n, sizeof(int));
+ tree->dwrk = xcalloc(1+n, sizeof(double));
+ /* initialize control parameters */
+ tree->parm = parm;
+ tree->tm_beg = xtime();
+#if 0 /* 10/VI-2013 */
+ tree->tm_lag = xlset(0);
+#else
+ tree->tm_lag = 0.0;
+#endif
+ tree->sol_cnt = 0;
+#if 1 /* 11/VII-2013 */
+ tree->P = NULL;
+ tree->npp = NULL;
+ tree->save_sol = parm->save_sol;
+ tree->save_cnt = 0;
+#endif
+ /* initialize advanced solver interface */
+ tree->reason = 0;
+ tree->reopt = 0;
+ tree->reinv = 0;
+ tree->br_var = 0;
+ tree->br_sel = 0;
+ tree->child = 0;
+ tree->next_p = 0;
+ /*tree->btrack = NULL;*/
+ tree->stop = 0;
+ /* create the root subproblem, which initially is identical to
+ the original MIP */
+ new_node(tree, NULL);
+ return tree;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_revive_node - revive specified subproblem
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void ios_revive_node(glp_tree *tree, int p);
+*
+* DESCRIPTION
+*
+* The routine ios_revive_node revives the specified subproblem, whose
+* reference number is p, and thereby makes it the current subproblem.
+* Note that the specified subproblem must be active. Besides, if the
+* current subproblem already exists, it must be frozen before reviving
+* another subproblem. */
+
+void ios_revive_node(glp_tree *tree, int p)
+{ glp_prob *mip = tree->mip;
+ IOSNPD *node, *root;
+ /* obtain pointer to the specified subproblem */
+ xassert(1 <= p && p <= tree->nslots);
+ node = tree->slot[p].node;
+ xassert(node != NULL);
+ /* the specified subproblem must be active */
+ xassert(node->count == 0);
+ /* the current subproblem must not exist */
+ xassert(tree->curr == NULL);
+ /* the specified subproblem becomes current */
+ tree->curr = node;
+ /*tree->solved = 0;*/
+ /* obtain pointer to the root subproblem */
+ root = tree->slot[1].node;
+ xassert(root != NULL);
+ /* at this point problem object components correspond to the root
+ subproblem, so if the root subproblem should be revived, there
+ is nothing more to do */
+ if (node == root) goto done;
+ xassert(mip->m == tree->root_m);
+ /* build path from the root to the current node */
+ node->temp = NULL;
+ for (node = node; node != NULL; node = node->up)
+ { if (node->up == NULL)
+ xassert(node == root);
+ else
+ node->up->temp = node;
+ }
+ /* go down from the root to the current node and make necessary
+ changes to restore components of the current subproblem */
+ for (node = root; node != NULL; node = node->temp)
+ { int m = mip->m;
+ int n = mip->n;
+ /* if the current node is reached, the problem object at this
+ point corresponds to its parent, so save attributes of rows
+ and columns for the parent subproblem */
+ if (node->temp == NULL)
+ { int i, j;
+ tree->pred_m = m;
+ /* allocate/reallocate arrays, if necessary */
+ if (tree->pred_max < m + n)
+ { int new_size = m + n + 100;
+ if (tree->pred_type != NULL) xfree(tree->pred_type);
+ if (tree->pred_lb != NULL) xfree(tree->pred_lb);
+ if (tree->pred_ub != NULL) xfree(tree->pred_ub);
+ if (tree->pred_stat != NULL) xfree(tree->pred_stat);
+ tree->pred_max = new_size;
+ tree->pred_type = xcalloc(1+new_size, sizeof(char));
+ tree->pred_lb = xcalloc(1+new_size, sizeof(double));
+ tree->pred_ub = xcalloc(1+new_size, sizeof(double));
+ tree->pred_stat = xcalloc(1+new_size, sizeof(char));
+ }
+ /* save row attributes */
+ for (i = 1; i <= m; i++)
+ { GLPROW *row = mip->row[i];
+ tree->pred_type[i] = (char)row->type;
+ tree->pred_lb[i] = row->lb;
+ tree->pred_ub[i] = row->ub;
+ tree->pred_stat[i] = (char)row->stat;
+ }
+ /* save column attributes */
+ for (j = 1; j <= n; j++)
+ { GLPCOL *col = mip->col[j];
+ tree->pred_type[mip->m+j] = (char)col->type;
+ tree->pred_lb[mip->m+j] = col->lb;
+ tree->pred_ub[mip->m+j] = col->ub;
+ tree->pred_stat[mip->m+j] = (char)col->stat;
+ }
+ }
+ /* change bounds of rows and columns */
+ { IOSBND *b;
+ for (b = node->b_ptr; b != NULL; b = b->next)
+ { if (b->k <= m)
+ glp_set_row_bnds(mip, b->k, b->type, b->lb, b->ub);
+ else
+ glp_set_col_bnds(mip, b->k-m, b->type, b->lb, b->ub);
+ }
+ }
+ /* change statuses of rows and columns */
+ { IOSTAT *s;
+ for (s = node->s_ptr; s != NULL; s = s->next)
+ { if (s->k <= m)
+ glp_set_row_stat(mip, s->k, s->stat);
+ else
+ glp_set_col_stat(mip, s->k-m, s->stat);
+ }
+ }
+ /* add new rows */
+ if (node->r_ptr != NULL)
+ { IOSROW *r;
+ IOSAIJ *a;
+ int i, len, *ind;
+ double *val;
+ ind = xcalloc(1+n, sizeof(int));
+ val = xcalloc(1+n, sizeof(double));
+ for (r = node->r_ptr; r != NULL; r = r->next)
+ { i = glp_add_rows(mip, 1);
+ glp_set_row_name(mip, i, r->name);
+#if 1 /* 20/IX-2008 */
+ xassert(mip->row[i]->level == 0);
+ mip->row[i]->level = node->level;
+ mip->row[i]->origin = r->origin;
+ mip->row[i]->klass = r->klass;
+#endif
+ glp_set_row_bnds(mip, i, r->type, r->lb, r->ub);
+ len = 0;
+ for (a = r->ptr; a != NULL; a = a->next)
+ len++, ind[len] = a->j, val[len] = a->val;
+ glp_set_mat_row(mip, i, len, ind, val);
+ glp_set_rii(mip, i, r->rii);
+ glp_set_row_stat(mip, i, r->stat);
+ }
+ xfree(ind);
+ xfree(val);
+ }
+#if 0
+ /* add new edges to the conflict graph */
+ /* add new cliques to the conflict graph */
+ /* (not implemented yet) */
+ xassert(node->own_nn == 0);
+ xassert(node->own_nc == 0);
+ xassert(node->e_ptr == NULL);
+#endif
+ }
+ /* the specified subproblem has been revived */
+ node = tree->curr;
+ /* delete its bound change list */
+ while (node->b_ptr != NULL)
+ { IOSBND *b;
+ b = node->b_ptr;
+ node->b_ptr = b->next;
+ dmp_free_atom(tree->pool, b, sizeof(IOSBND));
+ }
+ /* delete its status change list */
+ while (node->s_ptr != NULL)
+ { IOSTAT *s;
+ s = node->s_ptr;
+ node->s_ptr = s->next;
+ dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
+ }
+#if 1 /* 20/XI-2009 */
+ /* delete its row addition list (additional rows may appear, for
+ example, due to branching on GUB constraints */
+ while (node->r_ptr != NULL)
+ { IOSROW *r;
+ r = node->r_ptr;
+ node->r_ptr = r->next;
+ xassert(r->name == NULL);
+ while (r->ptr != NULL)
+ { IOSAIJ *a;
+ a = r->ptr;
+ r->ptr = a->next;
+ dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
+ }
+ dmp_free_atom(tree->pool, r, sizeof(IOSROW));
+ }
+#endif
+done: return;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_freeze_node - freeze current subproblem
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void ios_freeze_node(glp_tree *tree);
+*
+* DESCRIPTION
+*
+* The routine ios_freeze_node freezes the current subproblem. */
+
+void ios_freeze_node(glp_tree *tree)
+{ glp_prob *mip = tree->mip;
+ int m = mip->m;
+ int n = mip->n;
+ IOSNPD *node;
+ /* obtain pointer to the current subproblem */
+ node = tree->curr;
+ xassert(node != NULL);
+ if (node->up == NULL)
+ { /* freeze the root subproblem */
+ int k;
+ xassert(node->p == 1);
+ xassert(tree->root_m == 0);
+ xassert(tree->root_type == NULL);
+ xassert(tree->root_lb == NULL);
+ xassert(tree->root_ub == NULL);
+ xassert(tree->root_stat == NULL);
+ tree->root_m = m;
+ tree->root_type = xcalloc(1+m+n, sizeof(char));
+ tree->root_lb = xcalloc(1+m+n, sizeof(double));
+ tree->root_ub = xcalloc(1+m+n, sizeof(double));
+ tree->root_stat = xcalloc(1+m+n, sizeof(char));
+ for (k = 1; k <= m+n; k++)
+ { if (k <= m)
+ { GLPROW *row = mip->row[k];
+ tree->root_type[k] = (char)row->type;
+ tree->root_lb[k] = row->lb;
+ tree->root_ub[k] = row->ub;
+ tree->root_stat[k] = (char)row->stat;
+ }
+ else
+ { GLPCOL *col = mip->col[k-m];
+ tree->root_type[k] = (char)col->type;
+ tree->root_lb[k] = col->lb;
+ tree->root_ub[k] = col->ub;
+ tree->root_stat[k] = (char)col->stat;
+ }
+ }
+ }
+ else
+ { /* freeze non-root subproblem */
+ int root_m = tree->root_m;
+ int pred_m = tree->pred_m;
+ int i, j, k;
+ xassert(pred_m <= m);
+ /* build change lists for rows and columns which exist in the
+ parent subproblem */
+ xassert(node->b_ptr == NULL);
+ xassert(node->s_ptr == NULL);
+ for (k = 1; k <= pred_m + n; k++)
+ { int pred_type, pred_stat, type, stat;
+ double pred_lb, pred_ub, lb, ub;
+ /* determine attributes in the parent subproblem */
+ pred_type = tree->pred_type[k];
+ pred_lb = tree->pred_lb[k];
+ pred_ub = tree->pred_ub[k];
+ pred_stat = tree->pred_stat[k];
+ /* determine attributes in the current subproblem */
+ if (k <= pred_m)
+ { GLPROW *row = mip->row[k];
+ type = row->type;
+ lb = row->lb;
+ ub = row->ub;
+ stat = row->stat;
+ }
+ else
+ { GLPCOL *col = mip->col[k - pred_m];
+ type = col->type;
+ lb = col->lb;
+ ub = col->ub;
+ stat = col->stat;
+ }
+ /* save type and bounds of a row/column, if changed */
+ if (!(pred_type == type && pred_lb == lb && pred_ub == ub))
+ { IOSBND *b;
+ b = dmp_get_atom(tree->pool, sizeof(IOSBND));
+ b->k = k;
+ b->type = (unsigned char)type;
+ b->lb = lb;
+ b->ub = ub;
+ b->next = node->b_ptr;
+ node->b_ptr = b;
+ }
+ /* save status of a row/column, if changed */
+ if (pred_stat != stat)
+ { IOSTAT *s;
+ s = dmp_get_atom(tree->pool, sizeof(IOSTAT));
+ s->k = k;
+ s->stat = (unsigned char)stat;
+ s->next = node->s_ptr;
+ node->s_ptr = s;
+ }
+ }
+ /* save new rows added to the current subproblem */
+ xassert(node->r_ptr == NULL);
+ if (pred_m < m)
+ { int i, len, *ind;
+ double *val;
+ ind = xcalloc(1+n, sizeof(int));
+ val = xcalloc(1+n, sizeof(double));
+ for (i = m; i > pred_m; i--)
+ { GLPROW *row = mip->row[i];
+ IOSROW *r;
+ const char *name;
+ r = dmp_get_atom(tree->pool, sizeof(IOSROW));
+ name = glp_get_row_name(mip, i);
+ if (name == NULL)
+ r->name = NULL;
+ else
+ { r->name = dmp_get_atom(tree->pool, strlen(name)+1);
+ strcpy(r->name, name);
+ }
+#if 1 /* 20/IX-2008 */
+ r->origin = row->origin;
+ r->klass = row->klass;
+#endif
+ r->type = (unsigned char)row->type;
+ r->lb = row->lb;
+ r->ub = row->ub;
+ r->ptr = NULL;
+ len = glp_get_mat_row(mip, i, ind, val);
+ for (k = 1; k <= len; k++)
+ { IOSAIJ *a;
+ a = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
+ a->j = ind[k];
+ a->val = val[k];
+ a->next = r->ptr;
+ r->ptr = a;
+ }
+ r->rii = row->rii;
+ r->stat = (unsigned char)row->stat;
+ r->next = node->r_ptr;
+ node->r_ptr = r;
+ }
+ xfree(ind);
+ xfree(val);
+ }
+ /* remove all rows missing in the root subproblem */
+ if (m != root_m)
+ { int nrs, *num;
+ nrs = m - root_m;
+ xassert(nrs > 0);
+ num = xcalloc(1+nrs, sizeof(int));
+ for (i = 1; i <= nrs; i++) num[i] = root_m + i;
+ glp_del_rows(mip, nrs, num);
+ xfree(num);
+ }
+ m = mip->m;
+ /* and restore attributes of all rows and columns for the root
+ subproblem */
+ xassert(m == root_m);
+ for (i = 1; i <= m; i++)
+ { glp_set_row_bnds(mip, i, tree->root_type[i],
+ tree->root_lb[i], tree->root_ub[i]);
+ glp_set_row_stat(mip, i, tree->root_stat[i]);
+ }
+ for (j = 1; j <= n; j++)
+ { glp_set_col_bnds(mip, j, tree->root_type[m+j],
+ tree->root_lb[m+j], tree->root_ub[m+j]);
+ glp_set_col_stat(mip, j, tree->root_stat[m+j]);
+ }
+#if 1
+ /* remove all edges and cliques missing in the conflict graph
+ for the root subproblem */
+ /* (not implemented yet) */
+#endif
+ }
+ /* the current subproblem has been frozen */
+ tree->curr = NULL;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_clone_node - clone specified subproblem
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
+*
+* DESCRIPTION
+*
+* The routine ios_clone_node clones the specified subproblem, whose
+* reference number is p, creating its nnn exact copies. Note that the
+* specified subproblem must be active and must be in the frozen state
+* (i.e. it must not be the current subproblem).
+*
+* Each clone, an exact copy of the specified subproblem, becomes a new
+* active subproblem added to the end of the active list. After cloning
+* the specified subproblem becomes inactive.
+*
+* The reference numbers of clone subproblems are stored to locations
+* ref[1], ..., ref[nnn]. */
+
+static int get_slot(glp_tree *tree)
+{ int p;
+ /* if no free slots are available, increase the room */
+ if (tree->avail == 0)
+ { int nslots = tree->nslots;
+ IOSLOT *save = tree->slot;
+ if (nslots == 0)
+ tree->nslots = 20;
+ else
+ { tree->nslots = nslots + nslots;
+ xassert(tree->nslots > nslots);
+ }
+ tree->slot = xcalloc(1+tree->nslots, sizeof(IOSLOT));
+ if (save != NULL)
+ { memcpy(&tree->slot[1], &save[1], nslots * sizeof(IOSLOT));
+ xfree(save);
+ }
+ /* push more free slots into the stack */
+ for (p = tree->nslots; p > nslots; p--)
+ { tree->slot[p].node = NULL;
+ tree->slot[p].next = tree->avail;
+ tree->avail = p;
+ }
+ }
+ /* pull a free slot from the stack */
+ p = tree->avail;
+ tree->avail = tree->slot[p].next;
+ xassert(tree->slot[p].node == NULL);
+ tree->slot[p].next = 0;
+ return p;
+}
+
+static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent)
+{ IOSNPD *node;
+ int p;
+ /* pull a free slot for the new node */
+ p = get_slot(tree);
+ /* create descriptor of the new subproblem */
+ node = dmp_get_atom(tree->pool, sizeof(IOSNPD));
+ tree->slot[p].node = node;
+ node->p = p;
+ node->up = parent;
+ node->level = (parent == NULL ? 0 : parent->level + 1);
+ node->count = 0;
+ node->b_ptr = NULL;
+ node->s_ptr = NULL;
+ node->r_ptr = NULL;
+ node->solved = 0;
+#if 0
+ node->own_nn = node->own_nc = 0;
+ node->e_ptr = NULL;
+#endif
+#if 1 /* 04/X-2008 */
+ node->lp_obj = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
+ -DBL_MAX : +DBL_MAX) : parent->lp_obj);
+#endif
+ node->bound = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
+ -DBL_MAX : +DBL_MAX) : parent->bound);
+ node->br_var = 0;
+ node->br_val = 0.0;
+ node->ii_cnt = 0;
+ node->ii_sum = 0.0;
+#if 1 /* 30/XI-2009 */
+ node->changed = 0;
+#endif
+ if (tree->parm->cb_size == 0)
+ node->data = NULL;
+ else
+ { node->data = dmp_get_atom(tree->pool, tree->parm->cb_size);
+ memset(node->data, 0, tree->parm->cb_size);
+ }
+ node->temp = NULL;
+ node->prev = tree->tail;
+ node->next = NULL;
+ /* add the new subproblem to the end of the active list */
+ if (tree->head == NULL)
+ tree->head = node;
+ else
+ tree->tail->next = node;
+ tree->tail = node;
+ tree->a_cnt++;
+ tree->n_cnt++;
+ tree->t_cnt++;
+ /* increase the number of child subproblems */
+ if (parent == NULL)
+ xassert(p == 1);
+ else
+ parent->count++;
+ return node;
+}
+
+void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[])
+{ IOSNPD *node;
+ int k;
+ /* obtain pointer to the subproblem to be cloned */
+ xassert(1 <= p && p <= tree->nslots);
+ node = tree->slot[p].node;
+ xassert(node != NULL);
+ /* the specified subproblem must be active */
+ xassert(node->count == 0);
+ /* and must be in the frozen state */
+ xassert(tree->curr != node);
+ /* remove the specified subproblem from the active list, because
+ it becomes inactive */
+ if (node->prev == NULL)
+ tree->head = node->next;
+ else
+ node->prev->next = node->next;
+ if (node->next == NULL)
+ tree->tail = node->prev;
+ else
+ node->next->prev = node->prev;
+ node->prev = node->next = NULL;
+ tree->a_cnt--;
+ /* create clone subproblems */
+ xassert(nnn > 0);
+ for (k = 1; k <= nnn; k++)
+ ref[k] = new_node(tree, node)->p;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_delete_node - delete specified subproblem
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void ios_delete_node(glp_tree *tree, int p);
+*
+* DESCRIPTION
+*
+* The routine ios_delete_node deletes the specified subproblem, whose
+* reference number is p. The subproblem must be active and must be in
+* the frozen state (i.e. it must not be the current subproblem).
+*
+* Note that deletion is performed recursively, i.e. if a subproblem to
+* be deleted is the only child of its parent, the parent subproblem is
+* also deleted, etc. */
+
+void ios_delete_node(glp_tree *tree, int p)
+{ IOSNPD *node, *temp;
+ /* obtain pointer to the subproblem to be deleted */
+ xassert(1 <= p && p <= tree->nslots);
+ node = tree->slot[p].node;
+ xassert(node != NULL);
+ /* the specified subproblem must be active */
+ xassert(node->count == 0);
+ /* and must be in the frozen state */
+ xassert(tree->curr != node);
+ /* remove the specified subproblem from the active list, because
+ it is gone from the tree */
+ if (node->prev == NULL)
+ tree->head = node->next;
+ else
+ node->prev->next = node->next;
+ if (node->next == NULL)
+ tree->tail = node->prev;
+ else
+ node->next->prev = node->prev;
+ node->prev = node->next = NULL;
+ tree->a_cnt--;
+loop: /* recursive deletion starts here */
+ /* delete the bound change list */
+ { IOSBND *b;
+ while (node->b_ptr != NULL)
+ { b = node->b_ptr;
+ node->b_ptr = b->next;
+ dmp_free_atom(tree->pool, b, sizeof(IOSBND));
+ }
+ }
+ /* delete the status change list */
+ { IOSTAT *s;
+ while (node->s_ptr != NULL)
+ { s = node->s_ptr;
+ node->s_ptr = s->next;
+ dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
+ }
+ }
+ /* delete the row addition list */
+ while (node->r_ptr != NULL)
+ { IOSROW *r;
+ r = node->r_ptr;
+ if (r->name != NULL)
+ dmp_free_atom(tree->pool, r->name, strlen(r->name)+1);
+ while (r->ptr != NULL)
+ { IOSAIJ *a;
+ a = r->ptr;
+ r->ptr = a->next;
+ dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
+ }
+ node->r_ptr = r->next;
+ dmp_free_atom(tree->pool, r, sizeof(IOSROW));
+ }
+#if 0
+ /* delete the edge addition list */
+ /* delete the clique addition list */
+ /* (not implemented yet) */
+ xassert(node->own_nn == 0);
+ xassert(node->own_nc == 0);
+ xassert(node->e_ptr == NULL);
+#endif
+ /* free application-specific data */
+ if (tree->parm->cb_size == 0)
+ xassert(node->data == NULL);
+ else
+ dmp_free_atom(tree->pool, node->data, tree->parm->cb_size);
+ /* free the corresponding node slot */
+ p = node->p;
+ xassert(tree->slot[p].node == node);
+ tree->slot[p].node = NULL;
+ tree->slot[p].next = tree->avail;
+ tree->avail = p;
+ /* save pointer to the parent subproblem */
+ temp = node->up;
+ /* delete the subproblem descriptor */
+ dmp_free_atom(tree->pool, node, sizeof(IOSNPD));
+ tree->n_cnt--;
+ /* take pointer to the parent subproblem */
+ node = temp;
+ if (node != NULL)
+ { /* the parent subproblem exists; decrease the number of its
+ child subproblems */
+ xassert(node->count > 0);
+ node->count--;
+ /* if now the parent subproblem has no childs, it also must be
+ deleted */
+ if (node->count == 0) goto loop;
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_delete_tree - delete branch-and-bound tree
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void ios_delete_tree(glp_tree *tree);
+*
+* DESCRIPTION
+*
+* The routine ios_delete_tree deletes the branch-and-bound tree, which
+* the parameter tree points to, and frees all the memory allocated to
+* this program object.
+*
+* On exit components of the problem object are restored to correspond
+* to the original MIP passed to the routine ios_create_tree. */
+
+void ios_delete_tree(glp_tree *tree)
+{ glp_prob *mip = tree->mip;
+ int i, j;
+ int m = mip->m;
+ int n = mip->n;
+ xassert(mip->tree == tree);
+ /* remove all additional rows */
+ if (m != tree->orig_m)
+ { int nrs, *num;
+ nrs = m - tree->orig_m;
+ xassert(nrs > 0);
+ num = xcalloc(1+nrs, sizeof(int));
+ for (i = 1; i <= nrs; i++) num[i] = tree->orig_m + i;
+ glp_del_rows(mip, nrs, num);
+ xfree(num);
+ }
+ m = tree->orig_m;
+ /* restore original attributes of rows and columns */
+ xassert(m == tree->orig_m);
+ xassert(n == tree->n);
+ for (i = 1; i <= m; i++)
+ { glp_set_row_bnds(mip, i, tree->orig_type[i],
+ tree->orig_lb[i], tree->orig_ub[i]);
+ glp_set_row_stat(mip, i, tree->orig_stat[i]);
+ mip->row[i]->prim = tree->orig_prim[i];
+ mip->row[i]->dual = tree->orig_dual[i];
+ }
+ for (j = 1; j <= n; j++)
+ { glp_set_col_bnds(mip, j, tree->orig_type[m+j],
+ tree->orig_lb[m+j], tree->orig_ub[m+j]);
+ glp_set_col_stat(mip, j, tree->orig_stat[m+j]);
+ mip->col[j]->prim = tree->orig_prim[m+j];
+ mip->col[j]->dual = tree->orig_dual[m+j];
+ }
+ mip->pbs_stat = mip->dbs_stat = GLP_FEAS;
+ mip->obj_val = tree->orig_obj;
+ /* delete the branch-and-bound tree */
+ xassert(tree->local != NULL);
+ ios_delete_pool(tree, tree->local);
+ dmp_delete_pool(tree->pool);
+ xfree(tree->orig_type);
+ xfree(tree->orig_lb);
+ xfree(tree->orig_ub);
+ xfree(tree->orig_stat);
+ xfree(tree->orig_prim);
+ xfree(tree->orig_dual);
+ xfree(tree->slot);
+ if (tree->root_type != NULL) xfree(tree->root_type);
+ if (tree->root_lb != NULL) xfree(tree->root_lb);
+ if (tree->root_ub != NULL) xfree(tree->root_ub);
+ if (tree->root_stat != NULL) xfree(tree->root_stat);
+ xfree(tree->non_int);
+#if 0
+ xfree(tree->n_ref);
+ xfree(tree->c_ref);
+ xfree(tree->j_ref);
+#endif
+ if (tree->pcost != NULL) ios_pcost_free(tree);
+ xfree(tree->iwrk);
+ xfree(tree->dwrk);
+#if 0
+ scg_delete_graph(tree->g);
+#endif
+ if (tree->pred_type != NULL) xfree(tree->pred_type);
+ if (tree->pred_lb != NULL) xfree(tree->pred_lb);
+ if (tree->pred_ub != NULL) xfree(tree->pred_ub);
+ if (tree->pred_stat != NULL) xfree(tree->pred_stat);
+#if 0
+ xassert(tree->cut_gen == NULL);
+#endif
+ xassert(tree->mir_gen == NULL);
+ xassert(tree->clq_gen == NULL);
+ xfree(tree);
+ mip->tree = NULL;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_eval_degrad - estimate obj. degrad. for down- and up-branches
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
+*
+* DESCRIPTION
+*
+* Given optimal basis to LP relaxation of the current subproblem the
+* routine ios_eval_degrad performs the dual ratio test to compute the
+* objective values in the adjacent basis for down- and up-branches,
+* which are stored in locations *dn and *up, assuming that x[j] is a
+* variable chosen to branch upon. */
+
+void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up)
+{ glp_prob *mip = tree->mip;
+ int m = mip->m, n = mip->n;
+ int len, kase, k, t, stat;
+ double alfa, beta, gamma, delta, dz;
+ int *ind = tree->iwrk;
+ double *val = tree->dwrk;
+ /* current basis must be optimal */
+ xassert(glp_get_status(mip) == GLP_OPT);
+ /* basis factorization must exist */
+ xassert(glp_bf_exists(mip));
+ /* obtain (fractional) value of x[j] in optimal basic solution
+ to LP relaxation of the current subproblem */
+ xassert(1 <= j && j <= n);
+ beta = mip->col[j]->prim;
+ /* since the value of x[j] is fractional, it is basic; compute
+ corresponding row of the simplex table */
+ len = lpx_eval_tab_row(mip, m+j, ind, val);
+ /* kase < 0 means down-branch; kase > 0 means up-branch */
+ for (kase = -1; kase <= +1; kase += 2)
+ { /* for down-branch we introduce new upper bound floor(beta)
+ for x[j]; similarly, for up-branch we introduce new lower
+ bound ceil(beta) for x[j]; in the current basis this new
+ upper/lower bound is violated, so in the adjacent basis
+ x[j] will leave the basis and go to its new upper/lower
+ bound; we need to know which non-basic variable x[k] should
+ enter the basis to keep dual feasibility */
+#if 0 /* 23/XI-2009 */
+ k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-7);
+#else
+ k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-9);
+#endif
+ /* if no variable has been chosen, current basis being primal
+ infeasible due to the new upper/lower bound of x[j] is dual
+ unbounded, therefore, LP relaxation to corresponding branch
+ has no primal feasible solution */
+ if (k == 0)
+ { if (mip->dir == GLP_MIN)
+ { if (kase < 0)
+ *dn = +DBL_MAX;
+ else
+ *up = +DBL_MAX;
+ }
+ else if (mip->dir == GLP_MAX)
+ { if (kase < 0)
+ *dn = -DBL_MAX;
+ else
+ *up = -DBL_MAX;
+ }
+ else
+ xassert(mip != mip);
+ continue;
+ }
+ xassert(1 <= k && k <= m+n);
+ /* row of the simplex table corresponding to specified basic
+ variable x[j] is the following:
+ x[j] = ... + alfa * x[k] + ... ;
+ we need to know influence coefficient, alfa, at non-basic
+ variable x[k] chosen with the dual ratio test */
+ for (t = 1; t <= len; t++)
+ if (ind[t] == k) break;
+ xassert(1 <= t && t <= len);
+ alfa = val[t];
+ /* determine status and reduced cost of variable x[k] */
+ if (k <= m)
+ { stat = mip->row[k]->stat;
+ gamma = mip->row[k]->dual;
+ }
+ else
+ { stat = mip->col[k-m]->stat;
+ gamma = mip->col[k-m]->dual;
+ }
+ /* x[k] cannot be basic or fixed non-basic */
+ xassert(stat == GLP_NL || stat == GLP_NU || stat == GLP_NF);
+ /* if the current basis is dual degenerative, some reduced
+ costs, which are close to zero, may have wrong sign due to
+ round-off errors, so correct the sign of gamma */
+ if (mip->dir == GLP_MIN)
+ { if (stat == GLP_NL && gamma < 0.0 ||
+ stat == GLP_NU && gamma > 0.0 ||
+ stat == GLP_NF) gamma = 0.0;
+ }
+ else if (mip->dir == GLP_MAX)
+ { if (stat == GLP_NL && gamma > 0.0 ||
+ stat == GLP_NU && gamma < 0.0 ||
+ stat == GLP_NF) gamma = 0.0;
+ }
+ else
+ xassert(mip != mip);
+ /* determine the change of x[j] in the adjacent basis:
+ delta x[j] = new x[j] - old x[j] */
+ delta = (kase < 0 ? floor(beta) : ceil(beta)) - beta;
+ /* compute the change of x[k] in the adjacent basis:
+ delta x[k] = new x[k] - old x[k] = delta x[j] / alfa */
+ delta /= alfa;
+ /* compute the change of the objective in the adjacent basis:
+ delta z = new z - old z = gamma * delta x[k] */
+ dz = gamma * delta;
+ if (mip->dir == GLP_MIN)
+ xassert(dz >= 0.0);
+ else if (mip->dir == GLP_MAX)
+ xassert(dz <= 0.0);
+ else
+ xassert(mip != mip);
+ /* compute the new objective value in the adjacent basis:
+ new z = old z + delta z */
+ if (kase < 0)
+ *dn = mip->obj_val + dz;
+ else
+ *up = mip->obj_val + dz;
+ }
+ /*xprintf("obj = %g; dn = %g; up = %g\n",
+ mip->obj_val, *dn, *up);*/
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_round_bound - improve local bound by rounding
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* double ios_round_bound(glp_tree *tree, double bound);
+*
+* RETURNS
+*
+* For the given local bound for any integer feasible solution to the
+* current subproblem the routine ios_round_bound returns an improved
+* local bound for the same integer feasible solution.
+*
+* BACKGROUND
+*
+* Let the current subproblem has the following objective function:
+*
+* z = sum c[j] * x[j] + s >= b, (1)
+* j in J
+*
+* where J = {j: c[j] is non-zero and integer, x[j] is integer}, s is
+* the sum of terms corresponding to fixed variables, b is an initial
+* local bound (minimization).
+*
+* From (1) it follows that:
+*
+* d * sum (c[j] / d) * x[j] + s >= b, (2)
+* j in J
+*
+* or, equivalently,
+*
+* sum (c[j] / d) * x[j] >= (b - s) / d = h, (3)
+* j in J
+*
+* where d = gcd(c[j]). Since the left-hand side of (3) is integer,
+* h = (b - s) / d can be rounded up to the nearest integer:
+*
+* h' = ceil(h) = (b' - s) / d, (4)
+*
+* that gives an rounded, improved local bound:
+*
+* b' = d * h' + s. (5)
+*
+* In case of maximization '>=' in (1) should be replaced by '<=' that
+* leads to the following formula:
+*
+* h' = floor(h) = (b' - s) / d, (6)
+*
+* which should used in the same way as (4).
+*
+* NOTE: If b is a valid local bound for a child of the current
+* subproblem, b' is also valid for that child subproblem. */
+
+double ios_round_bound(glp_tree *tree, double bound)
+{ glp_prob *mip = tree->mip;
+ int n = mip->n;
+ int d, j, nn, *c = tree->iwrk;
+ double s, h;
+ /* determine c[j] and compute s */
+ nn = 0, s = mip->c0, d = 0;
+ for (j = 1; j <= n; j++)
+ { GLPCOL *col = mip->col[j];
+ if (col->coef == 0.0) continue;
+ if (col->type == GLP_FX)
+ { /* fixed variable */
+ s += col->coef * col->prim;
+ }
+ else
+ { /* non-fixed variable */
+ if (col->kind != GLP_IV) goto skip;
+ if (col->coef != floor(col->coef)) goto skip;
+ if (fabs(col->coef) <= (double)INT_MAX)
+ c[++nn] = (int)fabs(col->coef);
+ else
+ d = 1;
+ }
+ }
+ /* compute d = gcd(c[1],...c[nn]) */
+ if (d == 0)
+ { if (nn == 0) goto skip;
+ d = gcdn(nn, c);
+ }
+ xassert(d > 0);
+ /* compute new local bound */
+ if (mip->dir == GLP_MIN)
+ { if (bound != +DBL_MAX)
+ { h = (bound - s) / (double)d;
+ if (h >= floor(h) + 0.001)
+ { /* round up */
+ h = ceil(h);
+ /*xprintf("d = %d; old = %g; ", d, bound);*/
+ bound = (double)d * h + s;
+ /*xprintf("new = %g\n", bound);*/
+ }
+ }
+ }
+ else if (mip->dir == GLP_MAX)
+ { if (bound != -DBL_MAX)
+ { h = (bound - s) / (double)d;
+ if (h <= ceil(h) - 0.001)
+ { /* round down */
+ h = floor(h);
+ bound = (double)d * h + s;
+ }
+ }
+ }
+ else
+ xassert(mip != mip);
+skip: return bound;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_is_hopeful - check if subproblem is hopeful
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* int ios_is_hopeful(glp_tree *tree, double bound);
+*
+* DESCRIPTION
+*
+* Given the local bound of a subproblem the routine ios_is_hopeful
+* checks if the subproblem can have an integer optimal solution which
+* is better than the best one currently known.
+*
+* RETURNS
+*
+* If the subproblem can have a better integer optimal solution, the
+* routine returns non-zero; otherwise, if the corresponding branch can
+* be pruned, the routine returns zero. */
+
+int ios_is_hopeful(glp_tree *tree, double bound)
+{ glp_prob *mip = tree->mip;
+ int ret = 1;
+ double eps;
+ if (mip->mip_stat == GLP_FEAS)
+ { eps = tree->parm->tol_obj * (1.0 + fabs(mip->mip_obj));
+ switch (mip->dir)
+ { case GLP_MIN:
+ if (bound >= mip->mip_obj - eps) ret = 0;
+ break;
+ case GLP_MAX:
+ if (bound <= mip->mip_obj + eps) ret = 0;
+ break;
+ default:
+ xassert(mip != mip);
+ }
+ }
+ else
+ { switch (mip->dir)
+ { case GLP_MIN:
+ if (bound == +DBL_MAX) ret = 0;
+ break;
+ case GLP_MAX:
+ if (bound == -DBL_MAX) ret = 0;
+ break;
+ default:
+ xassert(mip != mip);
+ }
+ }
+ return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_best_node - find active node with best local bound
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* int ios_best_node(glp_tree *tree);
+*
+* DESCRIPTION
+*
+* The routine ios_best_node finds an active node whose local bound is
+* best among other active nodes.
+*
+* It is understood that the integer optimal solution of the original
+* mip problem cannot be better than the best bound, so the best bound
+* is an lower (minimization) or upper (maximization) global bound for
+* the original problem.
+*
+* RETURNS
+*
+* The routine ios_best_node returns the subproblem reference number
+* for the best node. However, if the tree is empty, it returns zero. */
+
+int ios_best_node(glp_tree *tree)
+{ IOSNPD *node, *best = NULL;
+ switch (tree->mip->dir)
+ { case GLP_MIN:
+ /* minimization */
+ for (node = tree->head; node != NULL; node = node->next)
+ if (best == NULL || best->bound > node->bound)
+ best = node;
+ break;
+ case GLP_MAX:
+ /* maximization */
+ for (node = tree->head; node != NULL; node = node->next)
+ if (best == NULL || best->bound < node->bound)
+ best = node;
+ break;
+ default:
+ xassert(tree != tree);
+ }
+ return best == NULL ? 0 : best->p;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_relative_gap - compute relative mip gap
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* double ios_relative_gap(glp_tree *tree);
+*
+* DESCRIPTION
+*
+* The routine ios_relative_gap computes the relative mip gap using the
+* formula:
+*
+* gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
+*
+* where best_mip is the best integer feasible solution found so far,
+* best_bnd is the best (global) bound. If no integer feasible solution
+* has been found yet, rel_gap is set to DBL_MAX.
+*
+* RETURNS
+*
+* The routine ios_relative_gap returns the relative mip gap. */
+
+double ios_relative_gap(glp_tree *tree)
+{ glp_prob *mip = tree->mip;
+ int p;
+ double best_mip, best_bnd, gap;
+ if (mip->mip_stat == GLP_FEAS)
+ { best_mip = mip->mip_obj;
+ p = ios_best_node(tree);
+ if (p == 0)
+ { /* the tree is empty */
+ gap = 0.0;
+ }
+ else
+ { best_bnd = tree->slot[p].node->bound;
+ gap = fabs(best_mip - best_bnd) / (fabs(best_mip) +
+ DBL_EPSILON);
+ }
+ }
+ else
+ { /* no integer feasible solution has been found yet */
+ gap = DBL_MAX;
+ }
+ return gap;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_solve_node - solve LP relaxation of current subproblem
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* int ios_solve_node(glp_tree *tree);
+*
+* DESCRIPTION
+*
+* The routine ios_solve_node re-optimizes LP relaxation of the current
+* subproblem using the dual simplex method.
+*
+* RETURNS
+*
+* The routine returns the code which is reported by glp_simplex. */
+
+int ios_solve_node(glp_tree *tree)
+{ glp_prob *mip = tree->mip;
+ glp_smcp parm;
+ int ret;
+ /* the current subproblem must exist */
+ xassert(tree->curr != NULL);
+ /* set some control parameters */
+ glp_init_smcp(&parm);
+ switch (tree->parm->msg_lev)
+ { case GLP_MSG_OFF:
+ parm.msg_lev = GLP_MSG_OFF; break;
+ case GLP_MSG_ERR:
+ parm.msg_lev = GLP_MSG_ERR; break;
+ case GLP_MSG_ON:
+ case GLP_MSG_ALL:
+ parm.msg_lev = GLP_MSG_ON; break;
+ case GLP_MSG_DBG:
+ parm.msg_lev = GLP_MSG_ALL; break;
+ default:
+ xassert(tree != tree);
+ }
+ parm.meth = GLP_DUALP;
+#if 1 /* 16/III-2016 */
+ if (tree->parm->flip)
+ parm.r_test = GLP_RT_FLIP;
+#endif
+ /* respect time limit */
+ if (tree->parm->tm_lim < INT_MAX)
+ parm.tm_lim = tree->parm->tm_lim - (glp_time() - tree->tm_beg);
+ if (parm.tm_lim < 0)
+ parm.tm_lim = 0;
+ if (tree->parm->msg_lev < GLP_MSG_DBG)
+ parm.out_dly = tree->parm->out_dly;
+ else
+ parm.out_dly = 0;
+ /* if the incumbent objective value is already known, use it to
+ prematurely terminate the dual simplex search */
+ if (mip->mip_stat == GLP_FEAS)
+ { switch (tree->mip->dir)
+ { case GLP_MIN:
+ parm.obj_ul = mip->mip_obj;
+ break;
+ case GLP_MAX:
+ parm.obj_ll = mip->mip_obj;
+ break;
+ default:
+ xassert(mip != mip);
+ }
+ }
+ /* try to solve/re-optimize the LP relaxation */
+ ret = glp_simplex(mip, &parm);
+#if 1 /* 21/II-2016 by Chris */
+ if (ret == GLP_EFAIL)
+ { /* retry with a new basis */
+ glp_adv_basis(mip, 0);
+ ret = glp_simplex(mip, &parm);
+ }
+#endif
+ tree->curr->solved++;
+#if 0
+ xprintf("ret = %d; status = %d; pbs = %d; dbs = %d; some = %d\n",
+ ret, glp_get_status(mip), mip->pbs_stat, mip->dbs_stat,
+ mip->some);
+ lpx_print_sol(mip, "sol");
+#endif
+ return ret;
+}
+
+/**********************************************************************/
+
+#ifdef NEW_LOCAL /* 02/II-2018 */
+IOSPOOL *ios_create_pool(glp_tree *tree)
+{ /* create cut pool */
+ IOSPOOL *pool;
+ pool = glp_create_prob();
+ glp_add_cols(pool, tree->mip->n);
+ return pool;
+}
+#else
+IOSPOOL *ios_create_pool(glp_tree *tree)
+{ /* create cut pool */
+ IOSPOOL *pool;
+#if 0
+ pool = dmp_get_atom(tree->pool, sizeof(IOSPOOL));
+#else
+ xassert(tree == tree);
+ pool = xmalloc(sizeof(IOSPOOL));
+#endif
+ pool->size = 0;
+ pool->head = pool->tail = NULL;
+ pool->ord = 0, pool->curr = NULL;
+ return pool;
+}
+#endif
+
+#ifdef NEW_LOCAL /* 02/II-2018 */
+int ios_add_row(glp_tree *tree, IOSPOOL *pool,
+ const char *name, int klass, int flags, int len, const int ind[],
+ const double val[], int type, double rhs)
+{ /* add row (constraint) to the cut pool */
+ int i;
+ i = glp_add_rows(pool, 1);
+ glp_set_row_name(pool, i, name);
+ pool->row[i]->klass = klass;
+ xassert(flags == 0);
+ glp_set_mat_row(pool, i, len, ind, val);
+ glp_set_row_bnds(pool, i, type, rhs, rhs);
+ return i;
+}
+#else
+int ios_add_row(glp_tree *tree, IOSPOOL *pool,
+ const char *name, int klass, int flags, int len, const int ind[],
+ const double val[], int type, double rhs)
+{ /* add row (constraint) to the cut pool */
+ IOSCUT *cut;
+ IOSAIJ *aij;
+ int k;
+ xassert(pool != NULL);
+ cut = dmp_get_atom(tree->pool, sizeof(IOSCUT));
+ if (name == NULL || name[0] == '\0')
+ cut->name = NULL;
+ else
+ { for (k = 0; name[k] != '\0'; k++)
+ { if (k == 256)
+ xerror("glp_ios_add_row: cut name too long\n");
+ if (iscntrl((unsigned char)name[k]))
+ xerror("glp_ios_add_row: cut name contains invalid chara"
+ "cter(s)\n");
+ }
+ cut->name = dmp_get_atom(tree->pool, strlen(name)+1);
+ strcpy(cut->name, name);
+ }
+ if (!(0 <= klass && klass <= 255))
+ xerror("glp_ios_add_row: klass = %d; invalid cut class\n",
+ klass);
+ cut->klass = (unsigned char)klass;
+ if (flags != 0)
+ xerror("glp_ios_add_row: flags = %d; invalid cut flags\n",
+ flags);
+ cut->ptr = NULL;
+ if (!(0 <= len && len <= tree->n))
+ xerror("glp_ios_add_row: len = %d; invalid cut length\n",
+ len);
+ for (k = 1; k <= len; k++)
+ { aij = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
+ if (!(1 <= ind[k] && ind[k] <= tree->n))
+ xerror("glp_ios_add_row: ind[%d] = %d; column index out of "
+ "range\n", k, ind[k]);
+ aij->j = ind[k];
+ aij->val = val[k];
+ aij->next = cut->ptr;
+ cut->ptr = aij;
+ }
+ if (!(type == GLP_LO || type == GLP_UP || type == GLP_FX))
+ xerror("glp_ios_add_row: type = %d; invalid cut type\n",
+ type);
+ cut->type = (unsigned char)type;
+ cut->rhs = rhs;
+ cut->prev = pool->tail;
+ cut->next = NULL;
+ if (cut->prev == NULL)
+ pool->head = cut;
+ else
+ cut->prev->next = cut;
+ pool->tail = cut;
+ pool->size++;
+ return pool->size;
+}
+#endif
+
+#ifdef NEW_LOCAL /* 02/II-2018 */
+IOSCUT *ios_find_row(IOSPOOL *pool, int i)
+{ /* find row (constraint) in the cut pool */
+ xassert(0);
+}
+#else
+IOSCUT *ios_find_row(IOSPOOL *pool, int i)
+{ /* find row (constraint) in the cut pool */
+ /* (smart linear search) */
+ xassert(pool != NULL);
+ xassert(1 <= i && i <= pool->size);
+ if (pool->ord == 0)
+ { xassert(pool->curr == NULL);
+ pool->ord = 1;
+ pool->curr = pool->head;
+ }
+ xassert(pool->curr != NULL);
+ if (i < pool->ord)
+ { if (i < pool->ord - i)
+ { pool->ord = 1;
+ pool->curr = pool->head;
+ while (pool->ord != i)
+ { pool->ord++;
+ xassert(pool->curr != NULL);
+ pool->curr = pool->curr->next;
+ }
+ }
+ else
+ { while (pool->ord != i)
+ { pool->ord--;
+ xassert(pool->curr != NULL);
+ pool->curr = pool->curr->prev;
+ }
+ }
+ }
+ else if (i > pool->ord)
+ { if (i - pool->ord < pool->size - i)
+ { while (pool->ord != i)
+ { pool->ord++;
+ xassert(pool->curr != NULL);
+ pool->curr = pool->curr->next;
+ }
+ }
+ else
+ { pool->ord = pool->size;
+ pool->curr = pool->tail;
+ while (pool->ord != i)
+ { pool->ord--;
+ xassert(pool->curr != NULL);
+ pool->curr = pool->curr->prev;
+ }
+ }
+ }
+ xassert(pool->ord == i);
+ xassert(pool->curr != NULL);
+ return pool->curr;
+}
+#endif
+
+#ifdef NEW_LOCAL /* 02/II-2018 */
+void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i)
+{ /* remove row (constraint) from the cut pool */
+ xassert(0);
+}
+#else
+void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i)
+{ /* remove row (constraint) from the cut pool */
+ IOSCUT *cut;
+ IOSAIJ *aij;
+ xassert(pool != NULL);
+ if (!(1 <= i && i <= pool->size))
+ xerror("glp_ios_del_row: i = %d; cut number out of range\n",
+ i);
+ cut = ios_find_row(pool, i);
+ xassert(pool->curr == cut);
+ if (cut->next != NULL)
+ pool->curr = cut->next;
+ else if (cut->prev != NULL)
+ pool->ord--, pool->curr = cut->prev;
+ else
+ pool->ord = 0, pool->curr = NULL;
+ if (cut->name != NULL)
+ dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
+ if (cut->prev == NULL)
+ { xassert(pool->head == cut);
+ pool->head = cut->next;
+ }
+ else
+ { xassert(cut->prev->next == cut);
+ cut->prev->next = cut->next;
+ }
+ if (cut->next == NULL)
+ { xassert(pool->tail == cut);
+ pool->tail = cut->prev;
+ }
+ else
+ { xassert(cut->next->prev == cut);
+ cut->next->prev = cut->prev;
+ }
+ while (cut->ptr != NULL)
+ { aij = cut->ptr;
+ cut->ptr = aij->next;
+ dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
+ }
+ dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
+ pool->size--;
+ return;
+}
+#endif
+
+#ifdef NEW_LOCAL /* 02/II-2018 */
+void ios_clear_pool(glp_tree *tree, IOSPOOL *pool)
+{ /* remove all rows (constraints) from the cut pool */
+ if (pool->m > 0)
+ { int i, *num;
+ num = talloc(1+pool->m, int);
+ for (i = 1; i <= pool->m; i++)
+ num[i] = i;
+ glp_del_rows(pool, pool->m, num);
+ tfree(num);
+ }
+ return;
+}
+#else
+void ios_clear_pool(glp_tree *tree, IOSPOOL *pool)
+{ /* remove all rows (constraints) from the cut pool */
+ xassert(pool != NULL);
+ while (pool->head != NULL)
+ { IOSCUT *cut = pool->head;
+ pool->head = cut->next;
+ if (cut->name != NULL)
+ dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
+ while (cut->ptr != NULL)
+ { IOSAIJ *aij = cut->ptr;
+ cut->ptr = aij->next;
+ dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
+ }
+ dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
+ }
+ pool->size = 0;
+ pool->head = pool->tail = NULL;
+ pool->ord = 0, pool->curr = NULL;
+ return;
+}
+#endif
+
+#ifdef NEW_LOCAL /* 02/II-2018 */
+void ios_delete_pool(glp_tree *tree, IOSPOOL *pool)
+{ /* delete cut pool */
+ xassert(pool != NULL);
+ glp_delete_prob(pool);
+ return;
+}
+#else
+void ios_delete_pool(glp_tree *tree, IOSPOOL *pool)
+{ /* delete cut pool */
+ xassert(pool != NULL);
+ ios_clear_pool(tree, pool);
+ xfree(pool);
+ return;
+}
+#endif
+
+#if 1 /* 11/VII-2013 */
+#include "npp.h"
+
+void ios_process_sol(glp_tree *T)
+{ /* process integer feasible solution just found */
+ if (T->npp != NULL)
+ { /* postprocess solution from transformed mip */
+ npp_postprocess(T->npp, T->mip);
+ /* store solution to problem passed to glp_intopt */
+ npp_unload_sol(T->npp, T->P);
+ }
+ xassert(T->P != NULL);
+ /* save solution to text file, if requested */
+ if (T->save_sol != NULL)
+ { char *fn, *mark;
+ fn = talloc(strlen(T->save_sol) + 50, char);
+ mark = strrchr(T->save_sol, '*');
+ if (mark == NULL)
+ strcpy(fn, T->save_sol);
+ else
+ { memcpy(fn, T->save_sol, mark - T->save_sol);
+ fn[mark - T->save_sol] = '\0';
+ sprintf(fn + strlen(fn), "%03d", ++(T->save_cnt));
+ strcat(fn, &mark[1]);
+ }
+ glp_write_mip(T->P, fn);
+ tfree(fn);
+ }
+ return;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpios02.c b/test/monniaux/glpk-4.65/src/draft/glpios02.c
new file mode 100644
index 00000000..a73458aa
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpios02.c
@@ -0,0 +1,826 @@
+/* glpios02.c (preprocess current subproblem) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+
+/***********************************************************************
+* prepare_row_info - prepare row info to determine implied bounds
+*
+* Given a row (linear form)
+*
+* n
+* sum a[j] * x[j] (1)
+* j=1
+*
+* and bounds of columns (variables)
+*
+* l[j] <= x[j] <= u[j] (2)
+*
+* this routine computes f_min, j_min, f_max, j_max needed to determine
+* implied bounds.
+*
+* ALGORITHM
+*
+* Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}.
+*
+* Parameters f_min and j_min are computed as follows:
+*
+* 1) if there is no x[k] such that k in J+ and l[k] = -inf or k in J-
+* and u[k] = +inf, then
+*
+* f_min := sum a[j] * l[j] + sum a[j] * u[j]
+* j in J+ j in J-
+* (3)
+* j_min := 0
+*
+* 2) if there is exactly one x[k] such that k in J+ and l[k] = -inf
+* or k in J- and u[k] = +inf, then
+*
+* f_min := sum a[j] * l[j] + sum a[j] * u[j]
+* j in J+\{k} j in J-\{k}
+* (4)
+* j_min := k
+*
+* 3) if there are two or more x[k] such that k in J+ and l[k] = -inf
+* or k in J- and u[k] = +inf, then
+*
+* f_min := -inf
+* (5)
+* j_min := 0
+*
+* Parameters f_max and j_max are computed in a similar way as follows:
+*
+* 1) if there is no x[k] such that k in J+ and u[k] = +inf or k in J-
+* and l[k] = -inf, then
+*
+* f_max := sum a[j] * u[j] + sum a[j] * l[j]
+* j in J+ j in J-
+* (6)
+* j_max := 0
+*
+* 2) if there is exactly one x[k] such that k in J+ and u[k] = +inf
+* or k in J- and l[k] = -inf, then
+*
+* f_max := sum a[j] * u[j] + sum a[j] * l[j]
+* j in J+\{k} j in J-\{k}
+* (7)
+* j_max := k
+*
+* 3) if there are two or more x[k] such that k in J+ and u[k] = +inf
+* or k in J- and l[k] = -inf, then
+*
+* f_max := +inf
+* (8)
+* j_max := 0 */
+
+struct f_info
+{ int j_min, j_max;
+ double f_min, f_max;
+};
+
+static void prepare_row_info(int n, const double a[], const double l[],
+ const double u[], struct f_info *f)
+{ int j, j_min, j_max;
+ double f_min, f_max;
+ xassert(n >= 0);
+ /* determine f_min and j_min */
+ f_min = 0.0, j_min = 0;
+ for (j = 1; j <= n; j++)
+ { if (a[j] > 0.0)
+ { if (l[j] == -DBL_MAX)
+ { if (j_min == 0)
+ j_min = j;
+ else
+ { f_min = -DBL_MAX, j_min = 0;
+ break;
+ }
+ }
+ else
+ f_min += a[j] * l[j];
+ }
+ else if (a[j] < 0.0)
+ { if (u[j] == +DBL_MAX)
+ { if (j_min == 0)
+ j_min = j;
+ else
+ { f_min = -DBL_MAX, j_min = 0;
+ break;
+ }
+ }
+ else
+ f_min += a[j] * u[j];
+ }
+ else
+ xassert(a != a);
+ }
+ f->f_min = f_min, f->j_min = j_min;
+ /* determine f_max and j_max */
+ f_max = 0.0, j_max = 0;
+ for (j = 1; j <= n; j++)
+ { if (a[j] > 0.0)
+ { if (u[j] == +DBL_MAX)
+ { if (j_max == 0)
+ j_max = j;
+ else
+ { f_max = +DBL_MAX, j_max = 0;
+ break;
+ }
+ }
+ else
+ f_max += a[j] * u[j];
+ }
+ else if (a[j] < 0.0)
+ { if (l[j] == -DBL_MAX)
+ { if (j_max == 0)
+ j_max = j;
+ else
+ { f_max = +DBL_MAX, j_max = 0;
+ break;
+ }
+ }
+ else
+ f_max += a[j] * l[j];
+ }
+ else
+ xassert(a != a);
+ }
+ f->f_max = f_max, f->j_max = j_max;
+ return;
+}
+
+/***********************************************************************
+* row_implied_bounds - determine row implied bounds
+*
+* Given a row (linear form)
+*
+* n
+* sum a[j] * x[j]
+* j=1
+*
+* and bounds of columns (variables)
+*
+* l[j] <= x[j] <= u[j]
+*
+* this routine determines implied bounds of the row.
+*
+* ALGORITHM
+*
+* Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}.
+*
+* The implied lower bound of the row is computed as follows:
+*
+* L' := sum a[j] * l[j] + sum a[j] * u[j] (9)
+* j in J+ j in J-
+*
+* and as it follows from (3), (4), and (5):
+*
+* L' := if j_min = 0 then f_min else -inf (10)
+*
+* The implied upper bound of the row is computed as follows:
+*
+* U' := sum a[j] * u[j] + sum a[j] * l[j] (11)
+* j in J+ j in J-
+*
+* and as it follows from (6), (7), and (8):
+*
+* U' := if j_max = 0 then f_max else +inf (12)
+*
+* The implied bounds are stored in locations LL and UU. */
+
+static void row_implied_bounds(const struct f_info *f, double *LL,
+ double *UU)
+{ *LL = (f->j_min == 0 ? f->f_min : -DBL_MAX);
+ *UU = (f->j_max == 0 ? f->f_max : +DBL_MAX);
+ return;
+}
+
+/***********************************************************************
+* col_implied_bounds - determine column implied bounds
+*
+* Given a row (constraint)
+*
+* n
+* L <= sum a[j] * x[j] <= U (13)
+* j=1
+*
+* and bounds of columns (variables)
+*
+* l[j] <= x[j] <= u[j]
+*
+* this routine determines implied bounds of variable x[k].
+*
+* It is assumed that if L != -inf, the lower bound of the row can be
+* active, and if U != +inf, the upper bound of the row can be active.
+*
+* ALGORITHM
+*
+* From (13) it follows that
+*
+* L <= sum a[j] * x[j] + a[k] * x[k] <= U
+* j!=k
+* or
+*
+* L - sum a[j] * x[j] <= a[k] * x[k] <= U - sum a[j] * x[j]
+* j!=k j!=k
+*
+* Thus, if the row lower bound L can be active, implied lower bound of
+* term a[k] * x[k] can be determined as follows:
+*
+* ilb(a[k] * x[k]) = min(L - sum a[j] * x[j]) =
+* j!=k
+* (14)
+* = L - max sum a[j] * x[j]
+* j!=k
+*
+* where, as it follows from (6), (7), and (8)
+*
+* / f_max - a[k] * u[k], j_max = 0, a[k] > 0
+* |
+* | f_max - a[k] * l[k], j_max = 0, a[k] < 0
+* max sum a[j] * x[j] = {
+* j!=k | f_max, j_max = k
+* |
+* \ +inf, j_max != 0
+*
+* and if the upper bound U can be active, implied upper bound of term
+* a[k] * x[k] can be determined as follows:
+*
+* iub(a[k] * x[k]) = max(U - sum a[j] * x[j]) =
+* j!=k
+* (15)
+* = U - min sum a[j] * x[j]
+* j!=k
+*
+* where, as it follows from (3), (4), and (5)
+*
+* / f_min - a[k] * l[k], j_min = 0, a[k] > 0
+* |
+* | f_min - a[k] * u[k], j_min = 0, a[k] < 0
+* min sum a[j] * x[j] = {
+* j!=k | f_min, j_min = k
+* |
+* \ -inf, j_min != 0
+*
+* Since
+*
+* ilb(a[k] * x[k]) <= a[k] * x[k] <= iub(a[k] * x[k])
+*
+* implied lower and upper bounds of x[k] are determined as follows:
+*
+* l'[k] := if a[k] > 0 then ilb / a[k] else ulb / a[k] (16)
+*
+* u'[k] := if a[k] > 0 then ulb / a[k] else ilb / a[k] (17)
+*
+* The implied bounds are stored in locations ll and uu. */
+
+static void col_implied_bounds(const struct f_info *f, int n,
+ const double a[], double L, double U, const double l[],
+ const double u[], int k, double *ll, double *uu)
+{ double ilb, iub;
+ xassert(n >= 0);
+ xassert(1 <= k && k <= n);
+ /* determine implied lower bound of term a[k] * x[k] (14) */
+ if (L == -DBL_MAX || f->f_max == +DBL_MAX)
+ ilb = -DBL_MAX;
+ else if (f->j_max == 0)
+ { if (a[k] > 0.0)
+ { xassert(u[k] != +DBL_MAX);
+ ilb = L - (f->f_max - a[k] * u[k]);
+ }
+ else if (a[k] < 0.0)
+ { xassert(l[k] != -DBL_MAX);
+ ilb = L - (f->f_max - a[k] * l[k]);
+ }
+ else
+ xassert(a != a);
+ }
+ else if (f->j_max == k)
+ ilb = L - f->f_max;
+ else
+ ilb = -DBL_MAX;
+ /* determine implied upper bound of term a[k] * x[k] (15) */
+ if (U == +DBL_MAX || f->f_min == -DBL_MAX)
+ iub = +DBL_MAX;
+ else if (f->j_min == 0)
+ { if (a[k] > 0.0)
+ { xassert(l[k] != -DBL_MAX);
+ iub = U - (f->f_min - a[k] * l[k]);
+ }
+ else if (a[k] < 0.0)
+ { xassert(u[k] != +DBL_MAX);
+ iub = U - (f->f_min - a[k] * u[k]);
+ }
+ else
+ xassert(a != a);
+ }
+ else if (f->j_min == k)
+ iub = U - f->f_min;
+ else
+ iub = +DBL_MAX;
+ /* determine implied bounds of x[k] (16) and (17) */
+#if 1
+ /* do not use a[k] if it has small magnitude to prevent wrong
+ implied bounds; for example, 1e-15 * x1 >= x2 + x3, where
+ x1 >= -10, x2, x3 >= 0, would lead to wrong conclusion that
+ x1 >= 0 */
+ if (fabs(a[k]) < 1e-6)
+ *ll = -DBL_MAX, *uu = +DBL_MAX; else
+#endif
+ if (a[k] > 0.0)
+ { *ll = (ilb == -DBL_MAX ? -DBL_MAX : ilb / a[k]);
+ *uu = (iub == +DBL_MAX ? +DBL_MAX : iub / a[k]);
+ }
+ else if (a[k] < 0.0)
+ { *ll = (iub == +DBL_MAX ? -DBL_MAX : iub / a[k]);
+ *uu = (ilb == -DBL_MAX ? +DBL_MAX : ilb / a[k]);
+ }
+ else
+ xassert(a != a);
+ return;
+}
+
+/***********************************************************************
+* check_row_bounds - check and relax original row bounds
+*
+* Given a row (constraint)
+*
+* n
+* L <= sum a[j] * x[j] <= U
+* j=1
+*
+* and bounds of columns (variables)
+*
+* l[j] <= x[j] <= u[j]
+*
+* this routine checks the original row bounds L and U for feasibility
+* and redundancy. If the original lower bound L or/and upper bound U
+* cannot be active due to bounds of variables, the routine remove them
+* replacing by -inf or/and +inf, respectively.
+*
+* If no primal infeasibility is detected, the routine returns zero,
+* otherwise non-zero. */
+
+static int check_row_bounds(const struct f_info *f, double *L_,
+ double *U_)
+{ int ret = 0;
+ double L = *L_, U = *U_, LL, UU;
+ /* determine implied bounds of the row */
+ row_implied_bounds(f, &LL, &UU);
+ /* check if the original lower bound is infeasible */
+ if (L != -DBL_MAX)
+ { double eps = 1e-3 * (1.0 + fabs(L));
+ if (UU < L - eps)
+ { ret = 1;
+ goto done;
+ }
+ }
+ /* check if the original upper bound is infeasible */
+ if (U != +DBL_MAX)
+ { double eps = 1e-3 * (1.0 + fabs(U));
+ if (LL > U + eps)
+ { ret = 1;
+ goto done;
+ }
+ }
+ /* check if the original lower bound is redundant */
+ if (L != -DBL_MAX)
+ { double eps = 1e-12 * (1.0 + fabs(L));
+ if (LL > L - eps)
+ { /* it cannot be active, so remove it */
+ *L_ = -DBL_MAX;
+ }
+ }
+ /* check if the original upper bound is redundant */
+ if (U != +DBL_MAX)
+ { double eps = 1e-12 * (1.0 + fabs(U));
+ if (UU < U + eps)
+ { /* it cannot be active, so remove it */
+ *U_ = +DBL_MAX;
+ }
+ }
+done: return ret;
+}
+
+/***********************************************************************
+* check_col_bounds - check and tighten original column bounds
+*
+* Given a row (constraint)
+*
+* n
+* L <= sum a[j] * x[j] <= U
+* j=1
+*
+* and bounds of columns (variables)
+*
+* l[j] <= x[j] <= u[j]
+*
+* for column (variable) x[j] this routine checks the original column
+* bounds l[j] and u[j] for feasibility and redundancy. If the original
+* lower bound l[j] or/and upper bound u[j] cannot be active due to
+* bounds of the constraint and other variables, the routine tighten
+* them replacing by corresponding implied bounds, if possible.
+*
+* NOTE: It is assumed that if L != -inf, the row lower bound can be
+* active, and if U != +inf, the row upper bound can be active.
+*
+* The flag means that variable x[j] is required to be integer.
+*
+* New actual bounds for x[j] are stored in locations lj and uj.
+*
+* If no primal infeasibility is detected, the routine returns zero,
+* otherwise non-zero. */
+
+static int check_col_bounds(const struct f_info *f, int n,
+ const double a[], double L, double U, const double l[],
+ const double u[], int flag, int j, double *_lj, double *_uj)
+{ int ret = 0;
+ double lj, uj, ll, uu;
+ xassert(n >= 0);
+ xassert(1 <= j && j <= n);
+ lj = l[j], uj = u[j];
+ /* determine implied bounds of the column */
+ col_implied_bounds(f, n, a, L, U, l, u, j, &ll, &uu);
+ /* if x[j] is integral, round its implied bounds */
+ if (flag)
+ { if (ll != -DBL_MAX)
+ ll = (ll - floor(ll) < 1e-3 ? floor(ll) : ceil(ll));
+ if (uu != +DBL_MAX)
+ uu = (ceil(uu) - uu < 1e-3 ? ceil(uu) : floor(uu));
+ }
+ /* check if the original lower bound is infeasible */
+ if (lj != -DBL_MAX)
+ { double eps = 1e-3 * (1.0 + fabs(lj));
+ if (uu < lj - eps)
+ { ret = 1;
+ goto done;
+ }
+ }
+ /* check if the original upper bound is infeasible */
+ if (uj != +DBL_MAX)
+ { double eps = 1e-3 * (1.0 + fabs(uj));
+ if (ll > uj + eps)
+ { ret = 1;
+ goto done;
+ }
+ }
+ /* check if the original lower bound is redundant */
+ if (ll != -DBL_MAX)
+ { double eps = 1e-3 * (1.0 + fabs(ll));
+ if (lj < ll - eps)
+ { /* it cannot be active, so tighten it */
+ lj = ll;
+ }
+ }
+ /* check if the original upper bound is redundant */
+ if (uu != +DBL_MAX)
+ { double eps = 1e-3 * (1.0 + fabs(uu));
+ if (uj > uu + eps)
+ { /* it cannot be active, so tighten it */
+ uj = uu;
+ }
+ }
+ /* due to round-off errors it may happen that lj > uj (although
+ lj < uj + eps, since no primal infeasibility is detected), so
+ adjuct the new actual bounds to provide lj <= uj */
+ if (!(lj == -DBL_MAX || uj == +DBL_MAX))
+ { double t1 = fabs(lj), t2 = fabs(uj);
+ double eps = 1e-10 * (1.0 + (t1 <= t2 ? t1 : t2));
+ if (lj > uj - eps)
+ { if (lj == l[j])
+ uj = lj;
+ else if (uj == u[j])
+ lj = uj;
+ else if (t1 <= t2)
+ uj = lj;
+ else
+ lj = uj;
+ }
+ }
+ *_lj = lj, *_uj = uj;
+done: return ret;
+}
+
+/***********************************************************************
+* check_efficiency - check if change in column bounds is efficient
+*
+* Given the original bounds of a column l and u and its new actual
+* bounds l' and u' (possibly tighten by the routine check_col_bounds)
+* this routine checks if the change in the column bounds is efficient
+* enough. If so, the routine returns non-zero, otherwise zero.
+*
+* The flag means that the variable is required to be integer. */
+
+static int check_efficiency(int flag, double l, double u, double ll,
+ double uu)
+{ int eff = 0;
+ /* check efficiency for lower bound */
+ if (l < ll)
+ { if (flag || l == -DBL_MAX)
+ eff++;
+ else
+ { double r;
+ if (u == +DBL_MAX)
+ r = 1.0 + fabs(l);
+ else
+ r = 1.0 + (u - l);
+ if (ll - l >= 0.25 * r)
+ eff++;
+ }
+ }
+ /* check efficiency for upper bound */
+ if (u > uu)
+ { if (flag || u == +DBL_MAX)
+ eff++;
+ else
+ { double r;
+ if (l == -DBL_MAX)
+ r = 1.0 + fabs(u);
+ else
+ r = 1.0 + (u - l);
+ if (u - uu >= 0.25 * r)
+ eff++;
+ }
+ }
+ return eff;
+}
+
+/***********************************************************************
+* basic_preprocessing - perform basic preprocessing
+*
+* This routine performs basic preprocessing of the specified MIP that
+* includes relaxing some row bounds and tightening some column bounds.
+*
+* On entry the arrays L and U contains original row bounds, and the
+* arrays l and u contains original column bounds:
+*
+* L[0] is the lower bound of the objective row;
+* L[i], i = 1,...,m, is the lower bound of i-th row;
+* U[0] is the upper bound of the objective row;
+* U[i], i = 1,...,m, is the upper bound of i-th row;
+* l[0] is not used;
+* l[j], j = 1,...,n, is the lower bound of j-th column;
+* u[0] is not used;
+* u[j], j = 1,...,n, is the upper bound of j-th column.
+*
+* On exit the arrays L, U, l, and u contain new actual bounds of rows
+* and column in the same locations.
+*
+* The parameters nrs and num specify an initial list of rows to be
+* processed:
+*
+* nrs is the number of rows in the initial list, 0 <= nrs <= m+1;
+* num[0] is not used;
+* num[1,...,nrs] are row numbers (0 means the objective row).
+*
+* The parameter max_pass specifies the maximal number of times that
+* each row can be processed, max_pass > 0.
+*
+* If no primal infeasibility is detected, the routine returns zero,
+* otherwise non-zero. */
+
+static int basic_preprocessing(glp_prob *mip, double L[], double U[],
+ double l[], double u[], int nrs, const int num[], int max_pass)
+{ int m = mip->m;
+ int n = mip->n;
+ struct f_info f;
+ int i, j, k, len, size, ret = 0;
+ int *ind, *list, *mark, *pass;
+ double *val, *lb, *ub;
+ xassert(0 <= nrs && nrs <= m+1);
+ xassert(max_pass > 0);
+ /* allocate working arrays */
+ ind = xcalloc(1+n, sizeof(int));
+ list = xcalloc(1+m+1, sizeof(int));
+ mark = xcalloc(1+m+1, sizeof(int));
+ memset(&mark[0], 0, (m+1) * sizeof(int));
+ pass = xcalloc(1+m+1, sizeof(int));
+ memset(&pass[0], 0, (m+1) * sizeof(int));
+ val = xcalloc(1+n, sizeof(double));
+ lb = xcalloc(1+n, sizeof(double));
+ ub = xcalloc(1+n, sizeof(double));
+ /* initialize the list of rows to be processed */
+ size = 0;
+ for (k = 1; k <= nrs; k++)
+ { i = num[k];
+ xassert(0 <= i && i <= m);
+ /* duplicate row numbers are not allowed */
+ xassert(!mark[i]);
+ list[++size] = i, mark[i] = 1;
+ }
+ xassert(size == nrs);
+ /* process rows in the list until it becomes empty */
+ while (size > 0)
+ { /* get a next row from the list */
+ i = list[size--], mark[i] = 0;
+ /* increase the row processing count */
+ pass[i]++;
+ /* if the row is free, skip it */
+ if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue;
+ /* obtain coefficients of the row */
+ len = 0;
+ if (i == 0)
+ { for (j = 1; j <= n; j++)
+ { GLPCOL *col = mip->col[j];
+ if (col->coef != 0.0)
+ len++, ind[len] = j, val[len] = col->coef;
+ }
+ }
+ else
+ { GLPROW *row = mip->row[i];
+ GLPAIJ *aij;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ len++, ind[len] = aij->col->j, val[len] = aij->val;
+ }
+ /* determine lower and upper bounds of columns corresponding
+ to non-zero row coefficients */
+ for (k = 1; k <= len; k++)
+ j = ind[k], lb[k] = l[j], ub[k] = u[j];
+ /* prepare the row info to determine implied bounds */
+ prepare_row_info(len, val, lb, ub, &f);
+ /* check and relax bounds of the row */
+ if (check_row_bounds(&f, &L[i], &U[i]))
+ { /* the feasible region is empty */
+ ret = 1;
+ goto done;
+ }
+ /* if the row became free, drop it */
+ if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue;
+ /* process columns having non-zero coefficients in the row */
+ for (k = 1; k <= len; k++)
+ { GLPCOL *col;
+ int flag, eff;
+ double ll, uu;
+ /* take a next column in the row */
+ j = ind[k], col = mip->col[j];
+ flag = col->kind != GLP_CV;
+ /* check and tighten bounds of the column */
+ if (check_col_bounds(&f, len, val, L[i], U[i], lb, ub,
+ flag, k, &ll, &uu))
+ { /* the feasible region is empty */
+ ret = 1;
+ goto done;
+ }
+ /* check if change in the column bounds is efficient */
+ eff = check_efficiency(flag, l[j], u[j], ll, uu);
+ /* set new actual bounds of the column */
+ l[j] = ll, u[j] = uu;
+ /* if the change is efficient, add all rows affected by the
+ corresponding column, to the list */
+ if (eff > 0)
+ { GLPAIJ *aij;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ { int ii = aij->row->i;
+ /* if the row was processed maximal number of times,
+ skip it */
+ if (pass[ii] >= max_pass) continue;
+ /* if the row is free, skip it */
+ if (L[ii] == -DBL_MAX && U[ii] == +DBL_MAX) continue;
+ /* put the row into the list */
+ if (mark[ii] == 0)
+ { xassert(size <= m);
+ list[++size] = ii, mark[ii] = 1;
+ }
+ }
+ }
+ }
+ }
+done: /* free working arrays */
+ xfree(ind);
+ xfree(list);
+ xfree(mark);
+ xfree(pass);
+ xfree(val);
+ xfree(lb);
+ xfree(ub);
+ return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_preprocess_node - preprocess current subproblem
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* int ios_preprocess_node(glp_tree *tree, int max_pass);
+*
+* DESCRIPTION
+*
+* The routine ios_preprocess_node performs basic preprocessing of the
+* current subproblem.
+*
+* RETURNS
+*
+* If no primal infeasibility is detected, the routine returns zero,
+* otherwise non-zero. */
+
+int ios_preprocess_node(glp_tree *tree, int max_pass)
+{ glp_prob *mip = tree->mip;
+ int m = mip->m;
+ int n = mip->n;
+ int i, j, nrs, *num, ret = 0;
+ double *L, *U, *l, *u;
+ /* the current subproblem must exist */
+ xassert(tree->curr != NULL);
+ /* determine original row bounds */
+ L = xcalloc(1+m, sizeof(double));
+ U = xcalloc(1+m, sizeof(double));
+ switch (mip->mip_stat)
+ { case GLP_UNDEF:
+ L[0] = -DBL_MAX, U[0] = +DBL_MAX;
+ break;
+ case GLP_FEAS:
+ switch (mip->dir)
+ { case GLP_MIN:
+ L[0] = -DBL_MAX, U[0] = mip->mip_obj - mip->c0;
+ break;
+ case GLP_MAX:
+ L[0] = mip->mip_obj - mip->c0, U[0] = +DBL_MAX;
+ break;
+ default:
+ xassert(mip != mip);
+ }
+ break;
+ default:
+ xassert(mip != mip);
+ }
+ for (i = 1; i <= m; i++)
+ { L[i] = glp_get_row_lb(mip, i);
+ U[i] = glp_get_row_ub(mip, i);
+ }
+ /* determine original column bounds */
+ l = xcalloc(1+n, sizeof(double));
+ u = xcalloc(1+n, sizeof(double));
+ for (j = 1; j <= n; j++)
+ { l[j] = glp_get_col_lb(mip, j);
+ u[j] = glp_get_col_ub(mip, j);
+ }
+ /* build the initial list of rows to be analyzed */
+ nrs = m + 1;
+ num = xcalloc(1+nrs, sizeof(int));
+ for (i = 1; i <= nrs; i++) num[i] = i - 1;
+ /* perform basic preprocessing */
+ if (basic_preprocessing(mip , L, U, l, u, nrs, num, max_pass))
+ { ret = 1;
+ goto done;
+ }
+ /* set new actual (relaxed) row bounds */
+ for (i = 1; i <= m; i++)
+ { /* consider only non-active rows to keep dual feasibility */
+ if (glp_get_row_stat(mip, i) == GLP_BS)
+ { if (L[i] == -DBL_MAX && U[i] == +DBL_MAX)
+ glp_set_row_bnds(mip, i, GLP_FR, 0.0, 0.0);
+ else if (U[i] == +DBL_MAX)
+ glp_set_row_bnds(mip, i, GLP_LO, L[i], 0.0);
+ else if (L[i] == -DBL_MAX)
+ glp_set_row_bnds(mip, i, GLP_UP, 0.0, U[i]);
+ }
+ }
+ /* set new actual (tightened) column bounds */
+ for (j = 1; j <= n; j++)
+ { int type;
+ if (l[j] == -DBL_MAX && u[j] == +DBL_MAX)
+ type = GLP_FR;
+ else if (u[j] == +DBL_MAX)
+ type = GLP_LO;
+ else if (l[j] == -DBL_MAX)
+ type = GLP_UP;
+ else if (l[j] != u[j])
+ type = GLP_DB;
+ else
+ type = GLP_FX;
+ glp_set_col_bnds(mip, j, type, l[j], u[j]);
+ }
+done: /* free working arrays and return */
+ xfree(L);
+ xfree(U);
+ xfree(l);
+ xfree(u);
+ xfree(num);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpios03.c b/test/monniaux/glpk-4.65/src/draft/glpios03.c
new file mode 100644
index 00000000..21d6a000
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpios03.c
@@ -0,0 +1,1512 @@
+/* glpios03.c (branch-and-cut driver) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+
+/***********************************************************************
+* show_progress - display current progress of the search
+*
+* This routine displays some information about current progress of the
+* search.
+*
+* The information includes:
+*
+* the current number of iterations performed by the simplex solver;
+*
+* the objective value for the best known integer feasible solution,
+* which is upper (minimization) or lower (maximization) global bound
+* for optimal solution of the original mip problem;
+*
+* the best local bound for active nodes, which is lower (minimization)
+* or upper (maximization) global bound for optimal solution of the
+* original mip problem;
+*
+* the relative mip gap, in percents;
+*
+* the number of open (active) subproblems;
+*
+* the number of completely explored subproblems, i.e. whose nodes have
+* been removed from the tree. */
+
+static void show_progress(glp_tree *T, int bingo)
+{ int p;
+ double temp;
+ char best_mip[50], best_bound[50], *rho, rel_gap[50];
+ /* format the best known integer feasible solution */
+ if (T->mip->mip_stat == GLP_FEAS)
+ sprintf(best_mip, "%17.9e", T->mip->mip_obj);
+ else
+ sprintf(best_mip, "%17s", "not found yet");
+ /* determine reference number of an active subproblem whose local
+ bound is best */
+ p = ios_best_node(T);
+ /* format the best bound */
+ if (p == 0)
+ sprintf(best_bound, "%17s", "tree is empty");
+ else
+ { temp = T->slot[p].node->bound;
+ if (temp == -DBL_MAX)
+ sprintf(best_bound, "%17s", "-inf");
+ else if (temp == +DBL_MAX)
+ sprintf(best_bound, "%17s", "+inf");
+ else
+ { if (fabs(temp) < 1e-9)
+ temp = 0;
+ sprintf(best_bound, "%17.9e", temp);
+ }
+ }
+ /* choose the relation sign between global bounds */
+ if (T->mip->dir == GLP_MIN)
+ rho = ">=";
+ else if (T->mip->dir == GLP_MAX)
+ rho = "<=";
+ else
+ xassert(T != T);
+ /* format the relative mip gap */
+ temp = ios_relative_gap(T);
+ if (temp == 0.0)
+ sprintf(rel_gap, " 0.0%%");
+ else if (temp < 0.001)
+ sprintf(rel_gap, "< 0.1%%");
+ else if (temp <= 9.999)
+ sprintf(rel_gap, "%5.1f%%", 100.0 * temp);
+ else
+ sprintf(rel_gap, "%6s", "");
+ /* display progress of the search */
+ xprintf("+%6d: %s %s %s %s %s (%d; %d)\n",
+ T->mip->it_cnt, bingo ? ">>>>>" : "mip =", best_mip, rho,
+ best_bound, rel_gap, T->a_cnt, T->t_cnt - T->n_cnt);
+ T->tm_lag = xtime();
+ return;
+}
+
+/***********************************************************************
+* is_branch_hopeful - check if specified branch is hopeful
+*
+* This routine checks if the specified subproblem can have an integer
+* optimal solution which is better than the best known one.
+*
+* The check is based on comparison of the local objective bound stored
+* in the subproblem descriptor and the incumbent objective value which
+* is the global objective bound.
+*
+* If there is a chance that the specified subproblem can have a better
+* integer optimal solution, the routine returns non-zero. Otherwise, if
+* the corresponding branch can pruned, zero is returned. */
+
+static int is_branch_hopeful(glp_tree *T, int p)
+{ xassert(1 <= p && p <= T->nslots);
+ xassert(T->slot[p].node != NULL);
+ return ios_is_hopeful(T, T->slot[p].node->bound);
+}
+
+/***********************************************************************
+* check_integrality - check integrality of basic solution
+*
+* This routine checks if the basic solution of LP relaxation of the
+* current subproblem satisfies to integrality conditions, i.e. that all
+* variables of integer kind have integral primal values. (The solution
+* is assumed to be optimal.)
+*
+* For each variable of integer kind the routine computes the following
+* quantity:
+*
+* ii(x[j]) = min(x[j] - floor(x[j]), ceil(x[j]) - x[j]), (1)
+*
+* which is a measure of the integer infeasibility (non-integrality) of
+* x[j] (for example, ii(2.1) = 0.1, ii(3.7) = 0.3, ii(5.0) = 0). It is
+* understood that 0 <= ii(x[j]) <= 0.5, and variable x[j] is integer
+* feasible if ii(x[j]) = 0. However, due to floating-point arithmetic
+* the routine checks less restrictive condition:
+*
+* ii(x[j]) <= tol_int, (2)
+*
+* where tol_int is a given tolerance (small positive number) and marks
+* each variable which does not satisfy to (2) as integer infeasible by
+* setting its fractionality flag.
+*
+* In order to characterize integer infeasibility of the basic solution
+* in the whole the routine computes two parameters: ii_cnt, which is
+* the number of variables with the fractionality flag set, and ii_sum,
+* which is the sum of integer infeasibilities (1). */
+
+static void check_integrality(glp_tree *T)
+{ glp_prob *mip = T->mip;
+ int j, type, ii_cnt = 0;
+ double lb, ub, x, temp1, temp2, ii_sum = 0.0;
+ /* walk through the set of columns (structural variables) */
+ for (j = 1; j <= mip->n; j++)
+ { GLPCOL *col = mip->col[j];
+ T->non_int[j] = 0;
+ /* if the column is not integer, skip it */
+ if (col->kind != GLP_IV) continue;
+ /* if the column is non-basic, it is integer feasible */
+ if (col->stat != GLP_BS) continue;
+ /* obtain the type and bounds of the column */
+ type = col->type, lb = col->lb, ub = col->ub;
+ /* obtain value of the column in optimal basic solution */
+ x = col->prim;
+ /* if the column's primal value is close to the lower bound,
+ the column is integer feasible within given tolerance */
+ if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+ { temp1 = lb - T->parm->tol_int;
+ temp2 = lb + T->parm->tol_int;
+ if (temp1 <= x && x <= temp2) continue;
+#if 0
+ /* the lower bound must not be violated */
+ xassert(x >= lb);
+#else
+ if (x < lb) continue;
+#endif
+ }
+ /* if the column's primal value is close to the upper bound,
+ the column is integer feasible within given tolerance */
+ if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+ { temp1 = ub - T->parm->tol_int;
+ temp2 = ub + T->parm->tol_int;
+ if (temp1 <= x && x <= temp2) continue;
+#if 0
+ /* the upper bound must not be violated */
+ xassert(x <= ub);
+#else
+ if (x > ub) continue;
+#endif
+ }
+ /* if the column's primal value is close to nearest integer,
+ the column is integer feasible within given tolerance */
+ temp1 = floor(x + 0.5) - T->parm->tol_int;
+ temp2 = floor(x + 0.5) + T->parm->tol_int;
+ if (temp1 <= x && x <= temp2) continue;
+ /* otherwise the column is integer infeasible */
+ T->non_int[j] = 1;
+ /* increase the number of fractional-valued columns */
+ ii_cnt++;
+ /* compute the sum of integer infeasibilities */
+ temp1 = x - floor(x);
+ temp2 = ceil(x) - x;
+ xassert(temp1 > 0.0 && temp2 > 0.0);
+ ii_sum += (temp1 <= temp2 ? temp1 : temp2);
+ }
+ /* store ii_cnt and ii_sum to the current problem descriptor */
+ xassert(T->curr != NULL);
+ T->curr->ii_cnt = ii_cnt;
+ T->curr->ii_sum = ii_sum;
+ /* and also display these parameters */
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ { if (ii_cnt == 0)
+ xprintf("There are no fractional columns\n");
+ else if (ii_cnt == 1)
+ xprintf("There is one fractional column, integer infeasibil"
+ "ity is %.3e\n", ii_sum);
+ else
+ xprintf("There are %d fractional columns, integer infeasibi"
+ "lity is %.3e\n", ii_cnt, ii_sum);
+ }
+ return;
+}
+
+/***********************************************************************
+* record_solution - record better integer feasible solution
+*
+* This routine records optimal basic solution of LP relaxation of the
+* current subproblem, which being integer feasible is better than the
+* best known integer feasible solution. */
+
+static void record_solution(glp_tree *T)
+{ glp_prob *mip = T->mip;
+ int i, j;
+ mip->mip_stat = GLP_FEAS;
+ mip->mip_obj = mip->obj_val;
+ for (i = 1; i <= mip->m; i++)
+ { GLPROW *row = mip->row[i];
+ row->mipx = row->prim;
+ }
+ for (j = 1; j <= mip->n; j++)
+ { GLPCOL *col = mip->col[j];
+ if (col->kind == GLP_CV)
+ col->mipx = col->prim;
+ else if (col->kind == GLP_IV)
+ { /* value of the integer column must be integral */
+ col->mipx = floor(col->prim + 0.5);
+ }
+ else
+ xassert(col != col);
+ }
+ T->sol_cnt++;
+ return;
+}
+
+/***********************************************************************
+* fix_by_red_cost - fix non-basic integer columns by reduced costs
+*
+* This routine fixes some non-basic integer columns if their reduced
+* costs indicate that increasing (decreasing) the column at least by
+* one involves the objective value becoming worse than the incumbent
+* objective value. */
+
+static void fix_by_red_cost(glp_tree *T)
+{ glp_prob *mip = T->mip;
+ int j, stat, fixed = 0;
+ double obj, lb, ub, dj;
+ /* the global bound must exist */
+ xassert(T->mip->mip_stat == GLP_FEAS);
+ /* basic solution of LP relaxation must be optimal */
+ xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS);
+ /* determine the objective function value */
+ obj = mip->obj_val;
+ /* walk through the column list */
+ for (j = 1; j <= mip->n; j++)
+ { GLPCOL *col = mip->col[j];
+ /* if the column is not integer, skip it */
+ if (col->kind != GLP_IV) continue;
+ /* obtain bounds of j-th column */
+ lb = col->lb, ub = col->ub;
+ /* and determine its status and reduced cost */
+ stat = col->stat, dj = col->dual;
+ /* analyze the reduced cost */
+ switch (mip->dir)
+ { case GLP_MIN:
+ /* minimization */
+ if (stat == GLP_NL)
+ { /* j-th column is non-basic on its lower bound */
+ if (dj < 0.0) dj = 0.0;
+ if (obj + dj >= mip->mip_obj)
+ glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++;
+ }
+ else if (stat == GLP_NU)
+ { /* j-th column is non-basic on its upper bound */
+ if (dj > 0.0) dj = 0.0;
+ if (obj - dj >= mip->mip_obj)
+ glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++;
+ }
+ break;
+ case GLP_MAX:
+ /* maximization */
+ if (stat == GLP_NL)
+ { /* j-th column is non-basic on its lower bound */
+ if (dj > 0.0) dj = 0.0;
+ if (obj + dj <= mip->mip_obj)
+ glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++;
+ }
+ else if (stat == GLP_NU)
+ { /* j-th column is non-basic on its upper bound */
+ if (dj < 0.0) dj = 0.0;
+ if (obj - dj <= mip->mip_obj)
+ glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++;
+ }
+ break;
+ default:
+ xassert(T != T);
+ }
+ }
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ { if (fixed == 0)
+ /* nothing to say */;
+ else if (fixed == 1)
+ xprintf("One column has been fixed by reduced cost\n");
+ else
+ xprintf("%d columns have been fixed by reduced costs\n",
+ fixed);
+ }
+ /* fixing non-basic columns on their current bounds does not
+ change the basic solution */
+ xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS);
+ return;
+}
+
+/***********************************************************************
+* branch_on - perform branching on specified variable
+*
+* This routine performs branching on j-th column (structural variable)
+* of the current subproblem. The specified column must be of integer
+* kind and must have a fractional value in optimal basic solution of
+* LP relaxation of the current subproblem (i.e. only columns for which
+* the flag non_int[j] is set are valid candidates to branch on).
+*
+* Let x be j-th structural variable, and beta be its primal fractional
+* value in the current basic solution. Branching on j-th variable is
+* dividing the current subproblem into two new subproblems, which are
+* identical to the current subproblem with the following exception: in
+* the first subproblem that begins the down-branch x has a new upper
+* bound x <= floor(beta), and in the second subproblem that begins the
+* up-branch x has a new lower bound x >= ceil(beta).
+*
+* Depending on estimation of local bounds for down- and up-branches
+* this routine returns the following:
+*
+* 0 - both branches have been created;
+* 1 - one branch is hopeless and has been pruned, so now the current
+* subproblem is other branch;
+* 2 - both branches are hopeless and have been pruned; new subproblem
+* selection is needed to continue the search. */
+
+static int branch_on(glp_tree *T, int j, int next)
+{ glp_prob *mip = T->mip;
+ IOSNPD *node;
+ int m = mip->m;
+ int n = mip->n;
+ int type, dn_type, up_type, dn_bad, up_bad, p, ret, clone[1+2];
+ double lb, ub, beta, new_ub, new_lb, dn_lp, up_lp, dn_bnd, up_bnd;
+ /* determine bounds and value of x[j] in optimal solution to LP
+ relaxation of the current subproblem */
+ xassert(1 <= j && j <= n);
+ type = mip->col[j]->type;
+ lb = mip->col[j]->lb;
+ ub = mip->col[j]->ub;
+ beta = mip->col[j]->prim;
+ /* determine new bounds of x[j] for down- and up-branches */
+ new_ub = floor(beta);
+ new_lb = ceil(beta);
+ switch (type)
+ { case GLP_FR:
+ dn_type = GLP_UP;
+ up_type = GLP_LO;
+ break;
+ case GLP_LO:
+ xassert(lb <= new_ub);
+ dn_type = (lb == new_ub ? GLP_FX : GLP_DB);
+ xassert(lb + 1.0 <= new_lb);
+ up_type = GLP_LO;
+ break;
+ case GLP_UP:
+ xassert(new_ub <= ub - 1.0);
+ dn_type = GLP_UP;
+ xassert(new_lb <= ub);
+ up_type = (new_lb == ub ? GLP_FX : GLP_DB);
+ break;
+ case GLP_DB:
+ xassert(lb <= new_ub && new_ub <= ub - 1.0);
+ dn_type = (lb == new_ub ? GLP_FX : GLP_DB);
+ xassert(lb + 1.0 <= new_lb && new_lb <= ub);
+ up_type = (new_lb == ub ? GLP_FX : GLP_DB);
+ break;
+ default:
+ xassert(type != type);
+ }
+ /* compute local bounds to LP relaxation for both branches */
+ ios_eval_degrad(T, j, &dn_lp, &up_lp);
+ /* and improve them by rounding */
+ dn_bnd = ios_round_bound(T, dn_lp);
+ up_bnd = ios_round_bound(T, up_lp);
+ /* check local bounds for down- and up-branches */
+ dn_bad = !ios_is_hopeful(T, dn_bnd);
+ up_bad = !ios_is_hopeful(T, up_bnd);
+ if (dn_bad && up_bad)
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Both down- and up-branches are hopeless\n");
+ ret = 2;
+ goto done;
+ }
+ else if (up_bad)
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Up-branch is hopeless\n");
+ glp_set_col_bnds(mip, j, dn_type, lb, new_ub);
+ T->curr->lp_obj = dn_lp;
+ if (mip->dir == GLP_MIN)
+ { if (T->curr->bound < dn_bnd)
+ T->curr->bound = dn_bnd;
+ }
+ else if (mip->dir == GLP_MAX)
+ { if (T->curr->bound > dn_bnd)
+ T->curr->bound = dn_bnd;
+ }
+ else
+ xassert(mip != mip);
+ ret = 1;
+ goto done;
+ }
+ else if (dn_bad)
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Down-branch is hopeless\n");
+ glp_set_col_bnds(mip, j, up_type, new_lb, ub);
+ T->curr->lp_obj = up_lp;
+ if (mip->dir == GLP_MIN)
+ { if (T->curr->bound < up_bnd)
+ T->curr->bound = up_bnd;
+ }
+ else if (mip->dir == GLP_MAX)
+ { if (T->curr->bound > up_bnd)
+ T->curr->bound = up_bnd;
+ }
+ else
+ xassert(mip != mip);
+ ret = 1;
+ goto done;
+ }
+ /* both down- and up-branches seem to be hopeful */
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Branching on column %d, primal value is %.9e\n",
+ j, beta);
+ /* determine the reference number of the current subproblem */
+ xassert(T->curr != NULL);
+ p = T->curr->p;
+ T->curr->br_var = j;
+ T->curr->br_val = beta;
+ /* freeze the current subproblem */
+ ios_freeze_node(T);
+ /* create two clones of the current subproblem; the first clone
+ begins the down-branch, the second one begins the up-branch */
+ ios_clone_node(T, p, 2, clone);
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Node %d begins down branch, node %d begins up branch "
+ "\n", clone[1], clone[2]);
+ /* set new upper bound of j-th column in the down-branch */
+ node = T->slot[clone[1]].node;
+ xassert(node != NULL);
+ xassert(node->up != NULL);
+ xassert(node->b_ptr == NULL);
+ node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND));
+ node->b_ptr->k = m + j;
+ node->b_ptr->type = (unsigned char)dn_type;
+ node->b_ptr->lb = lb;
+ node->b_ptr->ub = new_ub;
+ node->b_ptr->next = NULL;
+ node->lp_obj = dn_lp;
+ if (mip->dir == GLP_MIN)
+ { if (node->bound < dn_bnd)
+ node->bound = dn_bnd;
+ }
+ else if (mip->dir == GLP_MAX)
+ { if (node->bound > dn_bnd)
+ node->bound = dn_bnd;
+ }
+ else
+ xassert(mip != mip);
+ /* set new lower bound of j-th column in the up-branch */
+ node = T->slot[clone[2]].node;
+ xassert(node != NULL);
+ xassert(node->up != NULL);
+ xassert(node->b_ptr == NULL);
+ node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND));
+ node->b_ptr->k = m + j;
+ node->b_ptr->type = (unsigned char)up_type;
+ node->b_ptr->lb = new_lb;
+ node->b_ptr->ub = ub;
+ node->b_ptr->next = NULL;
+ node->lp_obj = up_lp;
+ if (mip->dir == GLP_MIN)
+ { if (node->bound < up_bnd)
+ node->bound = up_bnd;
+ }
+ else if (mip->dir == GLP_MAX)
+ { if (node->bound > up_bnd)
+ node->bound = up_bnd;
+ }
+ else
+ xassert(mip != mip);
+ /* suggest the subproblem to be solved next */
+ xassert(T->child == 0);
+ if (next == GLP_NO_BRNCH)
+ T->child = 0;
+ else if (next == GLP_DN_BRNCH)
+ T->child = clone[1];
+ else if (next == GLP_UP_BRNCH)
+ T->child = clone[2];
+ else
+ xassert(next != next);
+ ret = 0;
+done: return ret;
+}
+
+/***********************************************************************
+* cleanup_the_tree - prune hopeless branches from the tree
+*
+* This routine walks through the active list and checks the local
+* bound for every active subproblem. If the local bound indicates that
+* the subproblem cannot have integer optimal solution better than the
+* incumbent objective value, the routine deletes such subproblem that,
+* in turn, involves pruning the corresponding branch of the tree. */
+
+static void cleanup_the_tree(glp_tree *T)
+{ IOSNPD *node, *next_node;
+ int count = 0;
+ /* the global bound must exist */
+ xassert(T->mip->mip_stat == GLP_FEAS);
+ /* walk through the list of active subproblems */
+ for (node = T->head; node != NULL; node = next_node)
+ { /* deleting some active problem node may involve deleting its
+ parents recursively; however, all its parents being created
+ *before* it are always *precede* it in the node list, so
+ the next problem node is never affected by such deletion */
+ next_node = node->next;
+ /* if the branch is hopeless, prune it */
+ if (!is_branch_hopeful(T, node->p))
+ ios_delete_node(T, node->p), count++;
+ }
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ { if (count == 1)
+ xprintf("One hopeless branch has been pruned\n");
+ else if (count > 1)
+ xprintf("%d hopeless branches have been pruned\n", count);
+ }
+ return;
+}
+
+/***********************************************************************
+* round_heur - simple rounding heuristic
+*
+* This routine attempts to guess an integer feasible solution by
+* simple rounding values of all integer variables in basic solution to
+* nearest integers. */
+
+static int round_heur(glp_tree *T)
+{ glp_prob *P = T->mip;
+ /*int m = P->m;*/
+ int n = P->n;
+ int i, j, ret;
+ double *x;
+ /* compute rounded values of variables */
+ x = talloc(1+n, double);
+ for (j = 1; j <= n; j++)
+ { GLPCOL *col = P->col[j];
+ if (col->kind == GLP_IV)
+ { /* integer variable */
+ x[j] = floor(col->prim + 0.5);
+ }
+ else if (col->type == GLP_FX)
+ { /* fixed variable */
+ x[j] = col->prim;
+ }
+ else
+ { /* non-integer non-fixed variable */
+ ret = 3;
+ goto done;
+ }
+ }
+ /* check that no constraints are violated */
+ for (i = 1; i <= T->orig_m; i++)
+ { int type = T->orig_type[i];
+ GLPAIJ *aij;
+ double sum;
+ if (type == GLP_FR)
+ continue;
+ /* compute value of linear form */
+ sum = 0.0;
+ for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ sum += aij->val * x[aij->col->j];
+ /* check lower bound */
+ if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+ { if (sum < T->orig_lb[i] - 1e-9)
+ { /* lower bound is violated */
+ ret = 2;
+ goto done;
+ }
+ }
+ /* check upper bound */
+ if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+ { if (sum > T->orig_ub[i] + 1e-9)
+ { /* upper bound is violated */
+ ret = 2;
+ goto done;
+ }
+ }
+ }
+ /* rounded solution is integer feasible */
+ if (glp_ios_heur_sol(T, x) == 0)
+ { /* solution is accepted */
+ ret = 0;
+ }
+ else
+ { /* solution is rejected */
+ ret = 1;
+ }
+done: tfree(x);
+ return ret;
+}
+
+/**********************************************************************/
+
+#if 1 /* 08/III-2016 */
+static void gmi_gen(glp_tree *T)
+{ /* generate Gomory's mixed integer cuts */
+ glp_prob *P, *pool;
+ P = T->mip;
+ pool = glp_create_prob();
+ glp_add_cols(pool, P->n);
+ glp_gmi_gen(P, pool, 50);
+ if (pool->m > 0)
+ { int i, len, *ind;
+ double *val;
+ ind = xcalloc(1+P->n, sizeof(int));
+ val = xcalloc(1+P->n, sizeof(double));
+ for (i = 1; i <= pool->m; i++)
+ { len = glp_get_mat_row(pool, i, ind, val);
+ glp_ios_add_row(T, NULL, GLP_RF_GMI, 0, len, ind, val,
+ GLP_LO, pool->row[i]->lb);
+ }
+ xfree(ind);
+ xfree(val);
+ }
+ glp_delete_prob(pool);
+ return;
+}
+#endif
+
+#ifdef NEW_COVER /* 13/II-2018 */
+static void cov_gen(glp_tree *T)
+{ /* generate cover cuts */
+ glp_prob *P, *pool;
+ if (T->cov_gen == NULL)
+ return;
+ P = T->mip;
+ pool = glp_create_prob();
+ glp_add_cols(pool, P->n);
+ glp_cov_gen1(P, T->cov_gen, pool);
+ if (pool->m > 0)
+ { int i, len, *ind;
+ double *val;
+ ind = xcalloc(1+P->n, sizeof(int));
+ val = xcalloc(1+P->n, sizeof(double));
+ for (i = 1; i <= pool->m; i++)
+ { len = glp_get_mat_row(pool, i, ind, val);
+ glp_ios_add_row(T, NULL, GLP_RF_COV, 0, len, ind, val,
+ GLP_UP, pool->row[i]->ub);
+ }
+ xfree(ind);
+ xfree(val);
+ }
+ glp_delete_prob(pool);
+ return;
+}
+#endif
+
+#if 1 /* 08/III-2016 */
+static void mir_gen(glp_tree *T)
+{ /* generate mixed integer rounding cuts */
+ glp_prob *P, *pool;
+ P = T->mip;
+ pool = glp_create_prob();
+ glp_add_cols(pool, P->n);
+ glp_mir_gen(P, T->mir_gen, pool);
+ if (pool->m > 0)
+ { int i, len, *ind;
+ double *val;
+ ind = xcalloc(1+P->n, sizeof(int));
+ val = xcalloc(1+P->n, sizeof(double));
+ for (i = 1; i <= pool->m; i++)
+ { len = glp_get_mat_row(pool, i, ind, val);
+ glp_ios_add_row(T, NULL, GLP_RF_MIR, 0, len, ind, val,
+ GLP_UP, pool->row[i]->ub);
+ }
+ xfree(ind);
+ xfree(val);
+ }
+ glp_delete_prob(pool);
+ return;
+}
+#endif
+
+#if 1 /* 08/III-2016 */
+static void clq_gen(glp_tree *T, glp_cfg *G)
+{ /* generate clique cut from conflict graph */
+ glp_prob *P = T->mip;
+ int n = P->n;
+ int len, *ind;
+ double *val;
+ ind = talloc(1+n, int);
+ val = talloc(1+n, double);
+ len = glp_clq_cut(T->mip, G, ind, val);
+ if (len > 0)
+ glp_ios_add_row(T, NULL, GLP_RF_CLQ, 0, len, ind, val, GLP_UP,
+ val[0]);
+ tfree(ind);
+ tfree(val);
+ return;
+}
+#endif
+
+static void generate_cuts(glp_tree *T)
+{ /* generate generic cuts with built-in generators */
+ if (!(T->parm->mir_cuts == GLP_ON ||
+ T->parm->gmi_cuts == GLP_ON ||
+ T->parm->cov_cuts == GLP_ON ||
+ T->parm->clq_cuts == GLP_ON)) goto done;
+#if 1 /* 20/IX-2008 */
+ { int i, max_cuts, added_cuts;
+ max_cuts = T->n;
+ if (max_cuts < 1000) max_cuts = 1000;
+ added_cuts = 0;
+ for (i = T->orig_m+1; i <= T->mip->m; i++)
+ { if (T->mip->row[i]->origin == GLP_RF_CUT)
+ added_cuts++;
+ }
+ /* xprintf("added_cuts = %d\n", added_cuts); */
+ if (added_cuts >= max_cuts) goto done;
+ }
+#endif
+ /* generate and add to POOL all cuts violated by x* */
+ if (T->parm->gmi_cuts == GLP_ON)
+ { if (T->curr->changed < 7)
+#if 0 /* 08/III-2016 */
+ ios_gmi_gen(T);
+#else
+ gmi_gen(T);
+#endif
+ }
+ if (T->parm->mir_cuts == GLP_ON)
+ { xassert(T->mir_gen != NULL);
+#if 0 /* 08/III-2016 */
+ ios_mir_gen(T, T->mir_gen);
+#else
+ mir_gen(T);
+#endif
+ }
+ if (T->parm->cov_cuts == GLP_ON)
+ { /* cover cuts works well along with mir cuts */
+#ifdef NEW_COVER /* 13/II-2018 */
+ cov_gen(T);
+#else
+ ios_cov_gen(T);
+#endif
+ }
+ if (T->parm->clq_cuts == GLP_ON)
+ { if (T->clq_gen != NULL)
+#if 0 /* 29/VI-2013 */
+ { if (T->curr->level == 0 && T->curr->changed < 50 ||
+ T->curr->level > 0 && T->curr->changed < 5)
+#else /* FIXME */
+ { if (T->curr->level == 0 && T->curr->changed < 500 ||
+ T->curr->level > 0 && T->curr->changed < 50)
+#endif
+#if 0 /* 08/III-2016 */
+ ios_clq_gen(T, T->clq_gen);
+#else
+ clq_gen(T, T->clq_gen);
+#endif
+ }
+ }
+done: return;
+}
+
+/**********************************************************************/
+
+static void remove_cuts(glp_tree *T)
+{ /* remove inactive cuts (some valueable globally valid cut might
+ be saved in the global cut pool) */
+ int i, cnt = 0, *num = NULL;
+ xassert(T->curr != NULL);
+ for (i = T->orig_m+1; i <= T->mip->m; i++)
+ { if (T->mip->row[i]->origin == GLP_RF_CUT &&
+ T->mip->row[i]->level == T->curr->level &&
+ T->mip->row[i]->stat == GLP_BS)
+ { if (num == NULL)
+ num = xcalloc(1+T->mip->m, sizeof(int));
+ num[++cnt] = i;
+ }
+ }
+ if (cnt > 0)
+ { glp_del_rows(T->mip, cnt, num);
+#if 0
+ xprintf("%d inactive cut(s) removed\n", cnt);
+#endif
+ xfree(num);
+ xassert(glp_factorize(T->mip) == 0);
+ }
+ return;
+}
+
+/**********************************************************************/
+
+static void display_cut_info(glp_tree *T)
+{ glp_prob *mip = T->mip;
+ int i, gmi = 0, mir = 0, cov = 0, clq = 0, app = 0;
+ for (i = mip->m; i > 0; i--)
+ { GLPROW *row;
+ row = mip->row[i];
+ /* if (row->level < T->curr->level) break; */
+ if (row->origin == GLP_RF_CUT)
+ { if (row->klass == GLP_RF_GMI)
+ gmi++;
+ else if (row->klass == GLP_RF_MIR)
+ mir++;
+ else if (row->klass == GLP_RF_COV)
+ cov++;
+ else if (row->klass == GLP_RF_CLQ)
+ clq++;
+ else
+ app++;
+ }
+ }
+ xassert(T->curr != NULL);
+ if (gmi + mir + cov + clq + app > 0)
+ { xprintf("Cuts on level %d:", T->curr->level);
+ if (gmi > 0) xprintf(" gmi = %d;", gmi);
+ if (mir > 0) xprintf(" mir = %d;", mir);
+ if (cov > 0) xprintf(" cov = %d;", cov);
+ if (clq > 0) xprintf(" clq = %d;", clq);
+ if (app > 0) xprintf(" app = %d;", app);
+ xprintf("\n");
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_driver - branch-and-cut driver
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* int ios_driver(glp_tree *T);
+*
+* DESCRIPTION
+*
+* The routine ios_driver is a branch-and-cut driver. It controls the
+* MIP solution process.
+*
+* RETURNS
+*
+* 0 The MIP problem instance has been successfully solved. This code
+* does not necessarily mean that the solver has found optimal
+* solution. It only means that the solution process was successful.
+*
+* GLP_EFAIL
+* The search was prematurely terminated due to the solver failure.
+*
+* GLP_EMIPGAP
+* The search was prematurely terminated, because the relative mip
+* gap tolerance has been reached.
+*
+* GLP_ETMLIM
+* The search was prematurely terminated, because the time limit has
+* been exceeded.
+*
+* GLP_ESTOP
+* The search was prematurely terminated by application. */
+
+int ios_driver(glp_tree *T)
+{ int p, curr_p, p_stat, d_stat, ret;
+#if 1 /* carry out to glp_tree */
+ int pred_p = 0;
+ /* if the current subproblem has been just created due to
+ branching, pred_p is the reference number of its parent
+ subproblem, otherwise pred_p is zero */
+#endif
+#if 1 /* 18/VII-2013 */
+ int bad_cut;
+ double old_obj;
+#endif
+#if 0 /* 10/VI-2013 */
+ glp_long ttt = T->tm_beg;
+#else
+ double ttt = T->tm_beg;
+#endif
+#if 1 /* 27/II-2016 by Chris */
+ int root_done = 0;
+#endif
+#if 0
+ ((glp_iocp *)T->parm)->msg_lev = GLP_MSG_DBG;
+#endif
+#if 1 /* 16/III-2016 */
+ if (((glp_iocp *)T->parm)->flip)
+#if 0 /* 20/I-2018 */
+ xprintf("WARNING: LONG-STEP DUAL SIMPLEX WILL BE USED\n");
+#else
+ xprintf("Long-step dual simplex will be used\n");
+#endif
+#endif
+ /* on entry to the B&B driver it is assumed that the active list
+ contains the only active (i.e. root) subproblem, which is the
+ original MIP problem to be solved */
+loop: /* main loop starts here */
+ /* at this point the current subproblem does not exist */
+ xassert(T->curr == NULL);
+ /* if the active list is empty, the search is finished */
+ if (T->head == NULL)
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Active list is empty!\n");
+#if 0 /* 10/VI-2013 */
+ xassert(dmp_in_use(T->pool).lo == 0);
+#else
+ xassert(dmp_in_use(T->pool) == 0);
+#endif
+ ret = 0;
+ goto done;
+ }
+ /* select some active subproblem to continue the search */
+ xassert(T->next_p == 0);
+ /* let the application program select subproblem */
+ if (T->parm->cb_func != NULL)
+ { xassert(T->reason == 0);
+ T->reason = GLP_ISELECT;
+ T->parm->cb_func(T, T->parm->cb_info);
+ T->reason = 0;
+ if (T->stop)
+ { ret = GLP_ESTOP;
+ goto done;
+ }
+ }
+ if (T->next_p != 0)
+ { /* the application program has selected something */
+ ;
+ }
+ else if (T->a_cnt == 1)
+ { /* the only active subproblem exists, so select it */
+ xassert(T->head->next == NULL);
+ T->next_p = T->head->p;
+ }
+ else if (T->child != 0)
+ { /* select one of branching childs suggested by the branching
+ heuristic */
+ T->next_p = T->child;
+ }
+ else
+ { /* select active subproblem as specified by the backtracking
+ technique option */
+ T->next_p = ios_choose_node(T);
+ }
+ /* the active subproblem just selected becomes current */
+ ios_revive_node(T, T->next_p);
+ T->next_p = T->child = 0;
+ /* invalidate pred_p, if it is not the reference number of the
+ parent of the current subproblem */
+ if (T->curr->up != NULL && T->curr->up->p != pred_p) pred_p = 0;
+ /* determine the reference number of the current subproblem */
+ p = T->curr->p;
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ { xprintf("-----------------------------------------------------"
+ "-------------------\n");
+ xprintf("Processing node %d at level %d\n", p, T->curr->level);
+ }
+#if 0
+ if (p == 1)
+ glp_write_lp(T->mip, NULL, "root.lp");
+#endif
+#if 1 /* 24/X-2015 */
+ if (p == 1)
+ { if (T->parm->sr_heur == GLP_OFF)
+ { if (T->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Simple rounding heuristic disabled\n");
+ }
+ }
+#endif
+ /* if it is the root subproblem, initialize cut generators */
+ if (p == 1)
+ { if (T->parm->gmi_cuts == GLP_ON)
+ { if (T->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Gomory's cuts enabled\n");
+ }
+ if (T->parm->mir_cuts == GLP_ON)
+ { if (T->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("MIR cuts enabled\n");
+ xassert(T->mir_gen == NULL);
+#if 0 /* 06/III-2016 */
+ T->mir_gen = ios_mir_init(T);
+#else
+ T->mir_gen = glp_mir_init(T->mip);
+#endif
+ }
+ if (T->parm->cov_cuts == GLP_ON)
+ { if (T->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Cover cuts enabled\n");
+#ifdef NEW_COVER /* 13/II-2018 */
+ xassert(T->cov_gen == NULL);
+ T->cov_gen = glp_cov_init(T->mip);
+#endif
+ }
+ if (T->parm->clq_cuts == GLP_ON)
+ { xassert(T->clq_gen == NULL);
+ if (T->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Clique cuts enabled\n");
+#if 0 /* 08/III-2016 */
+ T->clq_gen = ios_clq_init(T);
+#else
+ T->clq_gen = glp_cfg_init(T->mip);
+#endif
+ }
+ }
+#if 1 /* 18/VII-2013 */
+ bad_cut = 0;
+#endif
+more: /* minor loop starts here */
+ /* at this point the current subproblem needs either to be solved
+ for the first time or re-optimized due to reformulation */
+ /* display current progress of the search */
+ if (T->parm->msg_lev >= GLP_MSG_DBG ||
+ T->parm->msg_lev >= GLP_MSG_ON &&
+ (double)(T->parm->out_frq - 1) <=
+ 1000.0 * xdifftime(xtime(), T->tm_lag))
+ show_progress(T, 0);
+ if (T->parm->msg_lev >= GLP_MSG_ALL &&
+ xdifftime(xtime(), ttt) >= 60.0)
+#if 0 /* 16/II-2012 */
+ { glp_long total;
+ glp_mem_usage(NULL, NULL, &total, NULL);
+ xprintf("Time used: %.1f secs. Memory used: %.1f Mb.\n",
+ xdifftime(xtime(), T->tm_beg), xltod(total) / 1048576.0);
+ ttt = xtime();
+ }
+#else
+ { size_t total;
+ glp_mem_usage(NULL, NULL, &total, NULL);
+ xprintf("Time used: %.1f secs. Memory used: %.1f Mb.\n",
+ xdifftime(xtime(), T->tm_beg), (double)total / 1048576.0);
+ ttt = xtime();
+ }
+#endif
+ /* check the mip gap */
+ if (T->parm->mip_gap > 0.0 &&
+ ios_relative_gap(T) <= T->parm->mip_gap)
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Relative gap tolerance reached; search terminated "
+ "\n");
+ ret = GLP_EMIPGAP;
+ goto done;
+ }
+ /* check if the time limit has been exhausted */
+ if (T->parm->tm_lim < INT_MAX &&
+ (double)(T->parm->tm_lim - 1) <=
+ 1000.0 * xdifftime(xtime(), T->tm_beg))
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Time limit exhausted; search terminated\n");
+ ret = GLP_ETMLIM;
+ goto done;
+ }
+ /* let the application program preprocess the subproblem */
+ if (T->parm->cb_func != NULL)
+ { xassert(T->reason == 0);
+ T->reason = GLP_IPREPRO;
+ T->parm->cb_func(T, T->parm->cb_info);
+ T->reason = 0;
+ if (T->stop)
+ { ret = GLP_ESTOP;
+ goto done;
+ }
+ }
+ /* perform basic preprocessing */
+ if (T->parm->pp_tech == GLP_PP_NONE)
+ ;
+ else if (T->parm->pp_tech == GLP_PP_ROOT)
+#if 0 /* 27/II-2016 by Chris */
+ { if (T->curr->level == 0)
+#else
+ { if (!root_done)
+#endif
+ { if (ios_preprocess_node(T, 100))
+ goto fath;
+ }
+ }
+ else if (T->parm->pp_tech == GLP_PP_ALL)
+#if 0 /* 27/II-2016 by Chris */
+ { if (ios_preprocess_node(T, T->curr->level == 0 ? 100 : 10))
+#else
+ { if (ios_preprocess_node(T, !root_done ? 100 : 10))
+#endif
+ goto fath;
+ }
+ else
+ xassert(T != T);
+ /* preprocessing may improve the global bound */
+ if (!is_branch_hopeful(T, p))
+ { xprintf("*** not tested yet ***\n");
+ goto fath;
+ }
+ /* solve LP relaxation of the current subproblem */
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Solving LP relaxation...\n");
+ ret = ios_solve_node(T);
+ if (ret == GLP_ETMLIM)
+ goto done;
+ else if (!(ret == 0 || ret == GLP_EOBJLL || ret == GLP_EOBJUL))
+ { if (T->parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("ios_driver: unable to solve current LP relaxation;"
+ " glp_simplex returned %d\n", ret);
+ ret = GLP_EFAIL;
+ goto done;
+ }
+ /* analyze status of the basic solution to LP relaxation found */
+ p_stat = T->mip->pbs_stat;
+ d_stat = T->mip->dbs_stat;
+ if (p_stat == GLP_FEAS && d_stat == GLP_FEAS)
+ { /* LP relaxation has optimal solution */
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Found optimal solution to LP relaxation\n");
+ }
+ else if (d_stat == GLP_NOFEAS)
+ { /* LP relaxation has no dual feasible solution */
+ /* since the current subproblem cannot have a larger feasible
+ region than its parent, there is something wrong */
+ if (T->parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("ios_driver: current LP relaxation has no dual feas"
+ "ible solution\n");
+ ret = GLP_EFAIL;
+ goto done;
+ }
+ else if (p_stat == GLP_INFEAS && d_stat == GLP_FEAS)
+ { /* LP relaxation has no primal solution which is better than
+ the incumbent objective value */
+ xassert(T->mip->mip_stat == GLP_FEAS);
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("LP relaxation has no solution better than incumben"
+ "t objective value\n");
+ /* prune the branch */
+ goto fath;
+ }
+ else if (p_stat == GLP_NOFEAS)
+ { /* LP relaxation has no primal feasible solution */
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("LP relaxation has no feasible solution\n");
+ /* prune the branch */
+ goto fath;
+ }
+ else
+ { /* other cases cannot appear */
+ xassert(T->mip != T->mip);
+ }
+ /* at this point basic solution to LP relaxation of the current
+ subproblem is optimal */
+ xassert(p_stat == GLP_FEAS && d_stat == GLP_FEAS);
+ xassert(T->curr != NULL);
+ T->curr->lp_obj = T->mip->obj_val;
+ /* thus, it defines a local bound to integer optimal solution of
+ the current subproblem */
+ { double bound = T->mip->obj_val;
+ /* some local bound to the current subproblem could be already
+ set before, so we should only improve it */
+ bound = ios_round_bound(T, bound);
+ if (T->mip->dir == GLP_MIN)
+ { if (T->curr->bound < bound)
+ T->curr->bound = bound;
+ }
+ else if (T->mip->dir == GLP_MAX)
+ { if (T->curr->bound > bound)
+ T->curr->bound = bound;
+ }
+ else
+ xassert(T->mip != T->mip);
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Local bound is %.9e\n", bound);
+ }
+ /* if the local bound indicates that integer optimal solution of
+ the current subproblem cannot be better than the global bound,
+ prune the branch */
+ if (!is_branch_hopeful(T, p))
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Current branch is hopeless and can be pruned\n");
+ goto fath;
+ }
+ /* let the application program generate additional rows ("lazy"
+ constraints) */
+ xassert(T->reopt == 0);
+ xassert(T->reinv == 0);
+ if (T->parm->cb_func != NULL)
+ { xassert(T->reason == 0);
+ T->reason = GLP_IROWGEN;
+ T->parm->cb_func(T, T->parm->cb_info);
+ T->reason = 0;
+ if (T->stop)
+ { ret = GLP_ESTOP;
+ goto done;
+ }
+ if (T->reopt)
+ { /* some rows were added; re-optimization is needed */
+ T->reopt = T->reinv = 0;
+ goto more;
+ }
+ if (T->reinv)
+ { /* no rows were added, however, some inactive rows were
+ removed */
+ T->reinv = 0;
+ xassert(glp_factorize(T->mip) == 0);
+ }
+ }
+ /* check if the basic solution is integer feasible */
+ check_integrality(T);
+ /* if the basic solution satisfies to all integrality conditions,
+ it is a new, better integer feasible solution */
+ if (T->curr->ii_cnt == 0)
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("New integer feasible solution found\n");
+ if (T->parm->msg_lev >= GLP_MSG_ALL)
+ display_cut_info(T);
+ record_solution(T);
+ if (T->parm->msg_lev >= GLP_MSG_ON)
+ show_progress(T, 1);
+#if 1 /* 11/VII-2013 */
+ ios_process_sol(T);
+#endif
+ /* make the application program happy */
+ if (T->parm->cb_func != NULL)
+ { xassert(T->reason == 0);
+ T->reason = GLP_IBINGO;
+ T->parm->cb_func(T, T->parm->cb_info);
+ T->reason = 0;
+ if (T->stop)
+ { ret = GLP_ESTOP;
+ goto done;
+ }
+ }
+ /* since the current subproblem has been fathomed, prune its
+ branch */
+ goto fath;
+ }
+ /* at this point basic solution to LP relaxation of the current
+ subproblem is optimal, but integer infeasible */
+ /* try to fix some non-basic structural variables of integer kind
+ on their current bounds due to reduced costs */
+ if (T->mip->mip_stat == GLP_FEAS)
+ fix_by_red_cost(T);
+ /* let the application program try to find some solution to the
+ original MIP with a primal heuristic */
+ if (T->parm->cb_func != NULL)
+ { xassert(T->reason == 0);
+ T->reason = GLP_IHEUR;
+ T->parm->cb_func(T, T->parm->cb_info);
+ T->reason = 0;
+ if (T->stop)
+ { ret = GLP_ESTOP;
+ goto done;
+ }
+ /* check if the current branch became hopeless */
+ if (!is_branch_hopeful(T, p))
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Current branch became hopeless and can be prune"
+ "d\n");
+ goto fath;
+ }
+ }
+ /* try to find solution with the feasibility pump heuristic */
+#if 0 /* 27/II-2016 by Chris */
+ if (T->parm->fp_heur)
+#else
+ if (T->parm->fp_heur && !root_done)
+#endif
+ { xassert(T->reason == 0);
+ T->reason = GLP_IHEUR;
+ ios_feas_pump(T);
+ T->reason = 0;
+ /* check if the current branch became hopeless */
+ if (!is_branch_hopeful(T, p))
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Current branch became hopeless and can be prune"
+ "d\n");
+ goto fath;
+ }
+ }
+#if 1 /* 25/V-2013 */
+ /* try to find solution with the proximity search heuristic */
+#if 0 /* 27/II-2016 by Chris */
+ if (T->parm->ps_heur)
+#else
+ if (T->parm->ps_heur && !root_done)
+#endif
+ { xassert(T->reason == 0);
+ T->reason = GLP_IHEUR;
+ ios_proxy_heur(T);
+ T->reason = 0;
+ /* check if the current branch became hopeless */
+ if (!is_branch_hopeful(T, p))
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Current branch became hopeless and can be prune"
+ "d\n");
+ goto fath;
+ }
+ }
+#endif
+#if 1 /* 24/X-2015 */
+ /* try to find solution with a simple rounding heuristic */
+ if (T->parm->sr_heur)
+ { xassert(T->reason == 0);
+ T->reason = GLP_IHEUR;
+ round_heur(T);
+ T->reason = 0;
+ /* check if the current branch became hopeless */
+ if (!is_branch_hopeful(T, p))
+ { if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Current branch became hopeless and can be prune"
+ "d\n");
+ goto fath;
+ }
+ }
+#endif
+ /* it's time to generate cutting planes */
+ xassert(T->local != NULL);
+#ifdef NEW_LOCAL /* 02/II-2018 */
+ xassert(T->local->m == 0);
+#else
+ xassert(T->local->size == 0);
+#endif
+ /* let the application program generate some cuts; note that it
+ can add cuts either to the local cut pool or directly to the
+ current subproblem */
+ if (T->parm->cb_func != NULL)
+ { xassert(T->reason == 0);
+ T->reason = GLP_ICUTGEN;
+ T->parm->cb_func(T, T->parm->cb_info);
+ T->reason = 0;
+ if (T->stop)
+ { ret = GLP_ESTOP;
+ goto done;
+ }
+ }
+#if 1 /* 18/VII-2013 */
+ if (T->curr->changed > 0)
+ { double degrad = fabs(T->curr->lp_obj - old_obj);
+ if (degrad < 1e-4 * (1.0 + fabs(old_obj)))
+ bad_cut++;
+ else
+ bad_cut = 0;
+ }
+ old_obj = T->curr->lp_obj;
+#if 0 /* 27/II-2016 by Chris */
+ if (bad_cut == 0 || (T->curr->level == 0 && bad_cut <= 3))
+#else
+ if (bad_cut == 0 || (!root_done && bad_cut <= 3))
+#endif
+#endif
+ /* try to generate generic cuts with built-in generators
+ (as suggested by Prof. Fischetti et al. the built-in cuts are
+ not generated at each branching node; an intense attempt of
+ generating new cuts is only made at the root node, and then
+ a moderate effort is spent after each backtracking step) */
+#if 0 /* 27/II-2016 by Chris */
+ if (T->curr->level == 0 || pred_p == 0)
+#else
+ if (!root_done || pred_p == 0)
+#endif
+ { xassert(T->reason == 0);
+ T->reason = GLP_ICUTGEN;
+ generate_cuts(T);
+ T->reason = 0;
+ }
+ /* if the local cut pool is not empty, select useful cuts and add
+ them to the current subproblem */
+#ifdef NEW_LOCAL /* 02/II-2018 */
+ if (T->local->m > 0)
+#else
+ if (T->local->size > 0)
+#endif
+ { xassert(T->reason == 0);
+ T->reason = GLP_ICUTGEN;
+ ios_process_cuts(T);
+ T->reason = 0;
+ }
+ /* clear the local cut pool */
+ ios_clear_pool(T, T->local);
+ /* perform re-optimization, if necessary */
+ if (T->reopt)
+ { T->reopt = 0;
+ T->curr->changed++;
+ goto more;
+ }
+ /* no cuts were generated; remove inactive cuts */
+ remove_cuts(T);
+#if 0 /* 27/II-2016 by Chris */
+ if (T->parm->msg_lev >= GLP_MSG_ALL && T->curr->level == 0)
+#else
+ if (T->parm->msg_lev >= GLP_MSG_ALL && !root_done)
+#endif
+ display_cut_info(T);
+#if 1 /* 27/II-2016 by Chris */
+ /* the first node will not be treated as root any more */
+ if (!root_done) root_done = 1;
+#endif
+ /* update history information used on pseudocost branching */
+ if (T->pcost != NULL) ios_pcost_update(T);
+ /* it's time to perform branching */
+ xassert(T->br_var == 0);
+ xassert(T->br_sel == 0);
+ /* let the application program choose variable to branch on */
+ if (T->parm->cb_func != NULL)
+ { xassert(T->reason == 0);
+ xassert(T->br_var == 0);
+ xassert(T->br_sel == 0);
+ T->reason = GLP_IBRANCH;
+ T->parm->cb_func(T, T->parm->cb_info);
+ T->reason = 0;
+ if (T->stop)
+ { ret = GLP_ESTOP;
+ goto done;
+ }
+ }
+ /* if nothing has been chosen, choose some variable as specified
+ by the branching technique option */
+ if (T->br_var == 0)
+ T->br_var = ios_choose_var(T, &T->br_sel);
+ /* perform actual branching */
+ curr_p = T->curr->p;
+ ret = branch_on(T, T->br_var, T->br_sel);
+ T->br_var = T->br_sel = 0;
+ if (ret == 0)
+ { /* both branches have been created */
+ pred_p = curr_p;
+ goto loop;
+ }
+ else if (ret == 1)
+ { /* one branch is hopeless and has been pruned, so now the
+ current subproblem is other branch */
+ /* the current subproblem should be considered as a new one,
+ since one bound of the branching variable was changed */
+ T->curr->solved = T->curr->changed = 0;
+#if 1 /* 18/VII-2013 */
+ /* bad_cut = 0; */
+#endif
+ goto more;
+ }
+ else if (ret == 2)
+ { /* both branches are hopeless and have been pruned; new
+ subproblem selection is needed to continue the search */
+ goto fath;
+ }
+ else
+ xassert(ret != ret);
+fath: /* the current subproblem has been fathomed */
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("Node %d fathomed\n", p);
+ /* freeze the current subproblem */
+ ios_freeze_node(T);
+ /* and prune the corresponding branch of the tree */
+ ios_delete_node(T, p);
+ /* if a new integer feasible solution has just been found, other
+ branches may become hopeless and therefore must be pruned */
+ if (T->mip->mip_stat == GLP_FEAS) cleanup_the_tree(T);
+ /* new subproblem selection is needed due to backtracking */
+ pred_p = 0;
+ goto loop;
+done: /* display progress of the search on exit from the solver */
+ if (T->parm->msg_lev >= GLP_MSG_ON)
+ show_progress(T, 0);
+ if (T->mir_gen != NULL)
+#if 0 /* 06/III-2016 */
+ ios_mir_term(T->mir_gen), T->mir_gen = NULL;
+#else
+ glp_mir_free(T->mir_gen), T->mir_gen = NULL;
+#endif
+#ifdef NEW_COVER /* 13/II-2018 */
+ if (T->cov_gen != NULL)
+ glp_cov_free(T->cov_gen), T->cov_gen = NULL;
+#endif
+ if (T->clq_gen != NULL)
+#if 0 /* 08/III-2016 */
+ ios_clq_term(T->clq_gen), T->clq_gen = NULL;
+#else
+ glp_cfg_free(T->clq_gen), T->clq_gen = NULL;
+#endif
+ /* return to the calling program */
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpios07.c b/test/monniaux/glpk-4.65/src/draft/glpios07.c
new file mode 100644
index 00000000..f750e571
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpios07.c
@@ -0,0 +1,551 @@
+/* glpios07.c (mixed cover cut generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+
+/*----------------------------------------------------------------------
+-- COVER INEQUALITIES
+--
+-- Consider the set of feasible solutions to 0-1 knapsack problem:
+--
+-- sum a[j]*x[j] <= b, (1)
+-- j in J
+--
+-- x[j] is binary, (2)
+--
+-- where, wlog, we assume that a[j] > 0 (since 0-1 variables can be
+-- complemented) and a[j] <= b (since a[j] > b implies x[j] = 0).
+--
+-- A set C within J is called a cover if
+--
+-- sum a[j] > b. (3)
+-- j in C
+--
+-- For any cover C the inequality
+--
+-- sum x[j] <= |C| - 1 (4)
+-- j in C
+--
+-- is called a cover inequality and is valid for (1)-(2).
+--
+-- MIXED COVER INEQUALITIES
+--
+-- Consider the set of feasible solutions to mixed knapsack problem:
+--
+-- sum a[j]*x[j] + y <= b, (5)
+-- j in J
+--
+-- x[j] is binary, (6)
+--
+-- 0 <= y <= u is continuous, (7)
+--
+-- where again we assume that a[j] > 0.
+--
+-- Let C within J be some set. From (1)-(4) it follows that
+--
+-- sum a[j] > b - y (8)
+-- j in C
+--
+-- implies
+--
+-- sum x[j] <= |C| - 1. (9)
+-- j in C
+--
+-- Thus, we need to modify the inequality (9) in such a way that it be
+-- a constraint only if the condition (8) is satisfied.
+--
+-- Consider the following inequality:
+--
+-- sum x[j] <= |C| - t. (10)
+-- j in C
+--
+-- If 0 < t <= 1, then (10) is equivalent to (9), because all x[j] are
+-- binary variables. On the other hand, if t <= 0, (10) being satisfied
+-- for any values of x[j] is not a constraint.
+--
+-- Let
+--
+-- t' = sum a[j] + y - b. (11)
+-- j in C
+--
+-- It is understood that the condition t' > 0 is equivalent to (8).
+-- Besides, from (6)-(7) it follows that t' has an implied upper bound:
+--
+-- t'max = sum a[j] + u - b. (12)
+-- j in C
+--
+-- This allows to express the parameter t having desired properties:
+--
+-- t = t' / t'max. (13)
+--
+-- In fact, t <= 1 by definition, and t > 0 being equivalent to t' > 0
+-- is equivalent to (8).
+--
+-- Thus, the inequality (10), where t is given by formula (13) is valid
+-- for (5)-(7).
+--
+-- Note that if u = 0, then y = 0, so t = 1, and the conditions (8) and
+-- (10) is transformed to the conditions (3) and (4).
+--
+-- GENERATING MIXED COVER CUTS
+--
+-- To generate a mixed cover cut in the form (10) we need to find such
+-- set C which satisfies to the inequality (8) and for which, in turn,
+-- the inequality (10) is violated in the current point.
+--
+-- Substituting t from (13) to (10) gives:
+--
+-- 1
+-- sum x[j] <= |C| - ----- (sum a[j] + y - b), (14)
+-- j in C t'max j in C
+--
+-- and finally we have the cut inequality in the standard form:
+--
+-- sum x[j] + alfa * y <= beta, (15)
+-- j in C
+--
+-- where:
+--
+-- alfa = 1 / t'max, (16)
+--
+-- beta = |C| - alfa * (sum a[j] - b). (17)
+-- j in C */
+
+#if 1
+#define MAXTRY 1000
+#else
+#define MAXTRY 10000
+#endif
+
+static int cover2(int n, double a[], double b, double u, double x[],
+ double y, int cov[], double *_alfa, double *_beta)
+{ /* try to generate mixed cover cut using two-element cover */
+ int i, j, try = 0, ret = 0;
+ double eps, alfa, beta, temp, rmax = 0.001;
+ eps = 0.001 * (1.0 + fabs(b));
+ for (i = 0+1; i <= n; i++)
+ for (j = i+1; j <= n; j++)
+ { /* C = {i, j} */
+ try++;
+ if (try > MAXTRY) goto done;
+ /* check if condition (8) is satisfied */
+ if (a[i] + a[j] + y > b + eps)
+ { /* compute parameters for inequality (15) */
+ temp = a[i] + a[j] - b;
+ alfa = 1.0 / (temp + u);
+ beta = 2.0 - alfa * temp;
+ /* compute violation of inequality (15) */
+ temp = x[i] + x[j] + alfa * y - beta;
+ /* choose C providing maximum violation */
+ if (rmax < temp)
+ { rmax = temp;
+ cov[1] = i;
+ cov[2] = j;
+ *_alfa = alfa;
+ *_beta = beta;
+ ret = 1;
+ }
+ }
+ }
+done: return ret;
+}
+
+static int cover3(int n, double a[], double b, double u, double x[],
+ double y, int cov[], double *_alfa, double *_beta)
+{ /* try to generate mixed cover cut using three-element cover */
+ int i, j, k, try = 0, ret = 0;
+ double eps, alfa, beta, temp, rmax = 0.001;
+ eps = 0.001 * (1.0 + fabs(b));
+ for (i = 0+1; i <= n; i++)
+ for (j = i+1; j <= n; j++)
+ for (k = j+1; k <= n; k++)
+ { /* C = {i, j, k} */
+ try++;
+ if (try > MAXTRY) goto done;
+ /* check if condition (8) is satisfied */
+ if (a[i] + a[j] + a[k] + y > b + eps)
+ { /* compute parameters for inequality (15) */
+ temp = a[i] + a[j] + a[k] - b;
+ alfa = 1.0 / (temp + u);
+ beta = 3.0 - alfa * temp;
+ /* compute violation of inequality (15) */
+ temp = x[i] + x[j] + x[k] + alfa * y - beta;
+ /* choose C providing maximum violation */
+ if (rmax < temp)
+ { rmax = temp;
+ cov[1] = i;
+ cov[2] = j;
+ cov[3] = k;
+ *_alfa = alfa;
+ *_beta = beta;
+ ret = 1;
+ }
+ }
+ }
+done: return ret;
+}
+
+static int cover4(int n, double a[], double b, double u, double x[],
+ double y, int cov[], double *_alfa, double *_beta)
+{ /* try to generate mixed cover cut using four-element cover */
+ int i, j, k, l, try = 0, ret = 0;
+ double eps, alfa, beta, temp, rmax = 0.001;
+ eps = 0.001 * (1.0 + fabs(b));
+ for (i = 0+1; i <= n; i++)
+ for (j = i+1; j <= n; j++)
+ for (k = j+1; k <= n; k++)
+ for (l = k+1; l <= n; l++)
+ { /* C = {i, j, k, l} */
+ try++;
+ if (try > MAXTRY) goto done;
+ /* check if condition (8) is satisfied */
+ if (a[i] + a[j] + a[k] + a[l] + y > b + eps)
+ { /* compute parameters for inequality (15) */
+ temp = a[i] + a[j] + a[k] + a[l] - b;
+ alfa = 1.0 / (temp + u);
+ beta = 4.0 - alfa * temp;
+ /* compute violation of inequality (15) */
+ temp = x[i] + x[j] + x[k] + x[l] + alfa * y - beta;
+ /* choose C providing maximum violation */
+ if (rmax < temp)
+ { rmax = temp;
+ cov[1] = i;
+ cov[2] = j;
+ cov[3] = k;
+ cov[4] = l;
+ *_alfa = alfa;
+ *_beta = beta;
+ ret = 1;
+ }
+ }
+ }
+done: return ret;
+}
+
+static int cover(int n, double a[], double b, double u, double x[],
+ double y, int cov[], double *alfa, double *beta)
+{ /* try to generate mixed cover cut;
+ input (see (5)):
+ n is the number of binary variables;
+ a[1:n] are coefficients at binary variables;
+ b is the right-hand side;
+ u is upper bound of continuous variable;
+ x[1:n] are values of binary variables at current point;
+ y is value of continuous variable at current point;
+ output (see (15), (16), (17)):
+ cov[1:r] are indices of binary variables included in cover C,
+ where r is the set cardinality returned on exit;
+ alfa coefficient at continuous variable;
+ beta is the right-hand side; */
+ int j;
+ /* perform some sanity checks */
+ xassert(n >= 2);
+ for (j = 1; j <= n; j++) xassert(a[j] > 0.0);
+#if 1 /* ??? */
+ xassert(b > -1e-5);
+#else
+ xassert(b > 0.0);
+#endif
+ xassert(u >= 0.0);
+ for (j = 1; j <= n; j++) xassert(0.0 <= x[j] && x[j] <= 1.0);
+ xassert(0.0 <= y && y <= u);
+ /* try to generate mixed cover cut */
+ if (cover2(n, a, b, u, x, y, cov, alfa, beta)) return 2;
+ if (cover3(n, a, b, u, x, y, cov, alfa, beta)) return 3;
+ if (cover4(n, a, b, u, x, y, cov, alfa, beta)) return 4;
+ return 0;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_cover_cut - generate mixed cover cut.
+--
+-- SYNOPSIS
+--
+-- int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
+-- double work[]);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_cover_cut generates a mixed cover cut for a given
+-- row of the MIP problem.
+--
+-- The given row of the MIP problem should be explicitly specified in
+-- the form:
+--
+-- sum{j in J} a[j]*x[j] <= b. (1)
+--
+-- On entry indices (ordinal numbers) of structural variables, which
+-- have non-zero constraint coefficients, should be placed in locations
+-- ind[1], ..., ind[len], and corresponding constraint coefficients
+-- should be placed in locations val[1], ..., val[len]. The right-hand
+-- side b should be stored in location val[0].
+--
+-- The working array work should have at least nb locations, where nb
+-- is the number of binary variables in (1).
+--
+-- The routine generates a mixed cover cut in the same form as (1) and
+-- stores the cut coefficients and right-hand side in the same way as
+-- just described above.
+--
+-- RETURNS
+--
+-- If the cutting plane has been successfully generated, the routine
+-- returns 1 <= len' <= n, which is the number of non-zero coefficients
+-- in the inequality constraint. Otherwise, the routine returns zero. */
+
+static int lpx_cover_cut(glp_prob *lp, int len, int ind[],
+ double val[], double work[])
+{ int cov[1+4], j, k, nb, newlen, r;
+ double f_min, f_max, alfa, beta, u, *x = work, y;
+ /* substitute and remove fixed variables */
+ newlen = 0;
+ for (k = 1; k <= len; k++)
+ { j = ind[k];
+ if (glp_get_col_type(lp, j) == GLP_FX)
+ val[0] -= val[k] * glp_get_col_lb(lp, j);
+ else
+ { newlen++;
+ ind[newlen] = ind[k];
+ val[newlen] = val[k];
+ }
+ }
+ len = newlen;
+ /* move binary variables to the beginning of the list so that
+ elements 1, 2, ..., nb correspond to binary variables, and
+ elements nb+1, nb+2, ..., len correspond to rest variables */
+ nb = 0;
+ for (k = 1; k <= len; k++)
+ { j = ind[k];
+ if (glp_get_col_kind(lp, j) == GLP_BV)
+ { /* binary variable */
+ int ind_k;
+ double val_k;
+ nb++;
+ ind_k = ind[nb], val_k = val[nb];
+ ind[nb] = ind[k], val[nb] = val[k];
+ ind[k] = ind_k, val[k] = val_k;
+ }
+ }
+ /* now the specified row has the form:
+ sum a[j]*x[j] + sum a[j]*y[j] <= b,
+ where x[j] are binary variables, y[j] are rest variables */
+ /* at least two binary variables are needed */
+ if (nb < 2) return 0;
+ /* compute implied lower and upper bounds for sum a[j]*y[j] */
+ f_min = f_max = 0.0;
+ for (k = nb+1; k <= len; k++)
+ { j = ind[k];
+ /* both bounds must be finite */
+ if (glp_get_col_type(lp, j) != GLP_DB) return 0;
+ if (val[k] > 0.0)
+ { f_min += val[k] * glp_get_col_lb(lp, j);
+ f_max += val[k] * glp_get_col_ub(lp, j);
+ }
+ else
+ { f_min += val[k] * glp_get_col_ub(lp, j);
+ f_max += val[k] * glp_get_col_lb(lp, j);
+ }
+ }
+ /* sum a[j]*x[j] + sum a[j]*y[j] <= b ===>
+ sum a[j]*x[j] + (sum a[j]*y[j] - f_min) <= b - f_min ===>
+ sum a[j]*x[j] + y <= b - f_min,
+ where y = sum a[j]*y[j] - f_min;
+ note that 0 <= y <= u, u = f_max - f_min */
+ /* determine upper bound of y */
+ u = f_max - f_min;
+ /* determine value of y at the current point */
+ y = 0.0;
+ for (k = nb+1; k <= len; k++)
+ { j = ind[k];
+ y += val[k] * glp_get_col_prim(lp, j);
+ }
+ y -= f_min;
+ if (y < 0.0) y = 0.0;
+ if (y > u) y = u;
+ /* modify the right-hand side b */
+ val[0] -= f_min;
+ /* now the transformed row has the form:
+ sum a[j]*x[j] + y <= b, where 0 <= y <= u */
+ /* determine values of x[j] at the current point */
+ for (k = 1; k <= nb; k++)
+ { j = ind[k];
+ x[k] = glp_get_col_prim(lp, j);
+ if (x[k] < 0.0) x[k] = 0.0;
+ if (x[k] > 1.0) x[k] = 1.0;
+ }
+ /* if a[j] < 0, replace x[j] by its complement 1 - x'[j] */
+ for (k = 1; k <= nb; k++)
+ { if (val[k] < 0.0)
+ { ind[k] = - ind[k];
+ val[k] = - val[k];
+ val[0] += val[k];
+ x[k] = 1.0 - x[k];
+ }
+ }
+ /* try to generate a mixed cover cut for the transformed row */
+ r = cover(nb, val, val[0], u, x, y, cov, &alfa, &beta);
+ if (r == 0) return 0;
+ xassert(2 <= r && r <= 4);
+ /* now the cut is in the form:
+ sum{j in C} x[j] + alfa * y <= beta */
+ /* store the right-hand side beta */
+ ind[0] = 0, val[0] = beta;
+ /* restore the original ordinal numbers of x[j] */
+ for (j = 1; j <= r; j++) cov[j] = ind[cov[j]];
+ /* store cut coefficients at binary variables complementing back
+ the variables having negative row coefficients */
+ xassert(r <= nb);
+ for (k = 1; k <= r; k++)
+ { if (cov[k] > 0)
+ { ind[k] = +cov[k];
+ val[k] = +1.0;
+ }
+ else
+ { ind[k] = -cov[k];
+ val[k] = -1.0;
+ val[0] -= 1.0;
+ }
+ }
+ /* substitute y = sum a[j]*y[j] - f_min */
+ for (k = nb+1; k <= len; k++)
+ { r++;
+ ind[r] = ind[k];
+ val[r] = alfa * val[k];
+ }
+ val[0] += alfa * f_min;
+ xassert(r <= len);
+ len = r;
+ return len;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_eval_row - compute explictily specified row.
+--
+-- SYNOPSIS
+--
+-- double lpx_eval_row(LPX *lp, int len, int ind[], double val[]);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_eval_row computes the primal value of an explicitly
+-- specified row using current values of structural variables.
+--
+-- The explicitly specified row may be thought as a linear form:
+--
+-- y = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n],
+--
+-- where y is an auxiliary variable for this row, a[j] are coefficients
+-- of the linear form, x[m+j] are structural variables.
+--
+-- On entry column indices and numerical values of non-zero elements of
+-- the row should be stored in locations ind[1], ..., ind[len] and
+-- val[1], ..., val[len], where len is the number of non-zero elements.
+-- The array ind and val are not changed on exit.
+--
+-- RETURNS
+--
+-- The routine returns a computed value of y, the auxiliary variable of
+-- the specified row. */
+
+static double lpx_eval_row(glp_prob *lp, int len, int ind[],
+ double val[])
+{ int n = glp_get_num_cols(lp);
+ int j, k;
+ double sum = 0.0;
+ if (len < 0)
+ xerror("lpx_eval_row: len = %d; invalid row length\n", len);
+ for (k = 1; k <= len; k++)
+ { j = ind[k];
+ if (!(1 <= j && j <= n))
+ xerror("lpx_eval_row: j = %d; column number out of range\n",
+ j);
+ sum += val[k] * glp_get_col_prim(lp, j);
+ }
+ return sum;
+}
+
+/***********************************************************************
+* NAME
+*
+* ios_cov_gen - generate mixed cover cuts
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void ios_cov_gen(glp_tree *tree);
+*
+* DESCRIPTION
+*
+* The routine ios_cov_gen generates mixed cover cuts for the current
+* point and adds them to the cut pool. */
+
+void ios_cov_gen(glp_tree *tree)
+{ glp_prob *prob = tree->mip;
+ int m = glp_get_num_rows(prob);
+ int n = glp_get_num_cols(prob);
+ int i, k, type, kase, len, *ind;
+ double r, *val, *work;
+ xassert(glp_get_status(prob) == GLP_OPT);
+ /* allocate working arrays */
+ ind = xcalloc(1+n, sizeof(int));
+ val = xcalloc(1+n, sizeof(double));
+ work = xcalloc(1+n, sizeof(double));
+ /* look through all rows */
+ for (i = 1; i <= m; i++)
+ for (kase = 1; kase <= 2; kase++)
+ { type = glp_get_row_type(prob, i);
+ if (kase == 1)
+ { /* consider rows of '<=' type */
+ if (!(type == GLP_UP || type == GLP_DB)) continue;
+ len = glp_get_mat_row(prob, i, ind, val);
+ val[0] = glp_get_row_ub(prob, i);
+ }
+ else
+ { /* consider rows of '>=' type */
+ if (!(type == GLP_LO || type == GLP_DB)) continue;
+ len = glp_get_mat_row(prob, i, ind, val);
+ for (k = 1; k <= len; k++) val[k] = - val[k];
+ val[0] = - glp_get_row_lb(prob, i);
+ }
+ /* generate mixed cover cut:
+ sum{j in J} a[j] * x[j] <= b */
+ len = lpx_cover_cut(prob, len, ind, val, work);
+ if (len == 0) continue;
+ /* at the current point the cut inequality is violated, i.e.
+ sum{j in J} a[j] * x[j] - b > 0 */
+ r = lpx_eval_row(prob, len, ind, val) - val[0];
+ if (r < 1e-3) continue;
+ /* add the cut to the cut pool */
+ glp_ios_add_row(tree, NULL, GLP_RF_COV, 0, len, ind, val,
+ GLP_UP, val[0]);
+ }
+ /* free working arrays */
+ xfree(ind);
+ xfree(val);
+ xfree(work);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpios09.c b/test/monniaux/glpk-4.65/src/draft/glpios09.c
new file mode 100644
index 00000000..d80ed9a3
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpios09.c
@@ -0,0 +1,664 @@
+/* glpios09.c (branching heuristics) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+
+/***********************************************************************
+* NAME
+*
+* ios_choose_var - select variable to branch on
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* int ios_choose_var(glp_tree *T, int *next);
+*
+* The routine ios_choose_var chooses a variable from the candidate
+* list to branch on. Additionally the routine provides a flag stored
+* in the location next to suggests which of the child subproblems
+* should be solved next.
+*
+* RETURNS
+*
+* The routine ios_choose_var returns the ordinal number of the column
+* choosen. */
+
+static int branch_first(glp_tree *T, int *next);
+static int branch_last(glp_tree *T, int *next);
+static int branch_mostf(glp_tree *T, int *next);
+static int branch_drtom(glp_tree *T, int *next);
+
+int ios_choose_var(glp_tree *T, int *next)
+{ int j;
+ if (T->parm->br_tech == GLP_BR_FFV)
+ { /* branch on first fractional variable */
+ j = branch_first(T, next);
+ }
+ else if (T->parm->br_tech == GLP_BR_LFV)
+ { /* branch on last fractional variable */
+ j = branch_last(T, next);
+ }
+ else if (T->parm->br_tech == GLP_BR_MFV)
+ { /* branch on most fractional variable */
+ j = branch_mostf(T, next);
+ }
+ else if (T->parm->br_tech == GLP_BR_DTH)
+ { /* branch using the heuristic by Dreebeck and Tomlin */
+ j = branch_drtom(T, next);
+ }
+ else if (T->parm->br_tech == GLP_BR_PCH)
+ { /* hybrid pseudocost heuristic */
+ j = ios_pcost_branch(T, next);
+ }
+ else
+ xassert(T != T);
+ return j;
+}
+
+/***********************************************************************
+* branch_first - choose first branching variable
+*
+* This routine looks up the list of structural variables and chooses
+* the first one, which is of integer kind and has fractional value in
+* optimal solution to the current LP relaxation.
+*
+* This routine also selects the branch to be solved next where integer
+* infeasibility of the chosen variable is less than in other one. */
+
+static int branch_first(glp_tree *T, int *_next)
+{ int j, next;
+ double beta;
+ /* choose the column to branch on */
+ for (j = 1; j <= T->n; j++)
+ if (T->non_int[j]) break;
+ xassert(1 <= j && j <= T->n);
+ /* select the branch to be solved next */
+ beta = glp_get_col_prim(T->mip, j);
+ if (beta - floor(beta) < ceil(beta) - beta)
+ next = GLP_DN_BRNCH;
+ else
+ next = GLP_UP_BRNCH;
+ *_next = next;
+ return j;
+}
+
+/***********************************************************************
+* branch_last - choose last branching variable
+*
+* This routine looks up the list of structural variables and chooses
+* the last one, which is of integer kind and has fractional value in
+* optimal solution to the current LP relaxation.
+*
+* This routine also selects the branch to be solved next where integer
+* infeasibility of the chosen variable is less than in other one. */
+
+static int branch_last(glp_tree *T, int *_next)
+{ int j, next;
+ double beta;
+ /* choose the column to branch on */
+ for (j = T->n; j >= 1; j--)
+ if (T->non_int[j]) break;
+ xassert(1 <= j && j <= T->n);
+ /* select the branch to be solved next */
+ beta = glp_get_col_prim(T->mip, j);
+ if (beta - floor(beta) < ceil(beta) - beta)
+ next = GLP_DN_BRNCH;
+ else
+ next = GLP_UP_BRNCH;
+ *_next = next;
+ return j;
+}
+
+/***********************************************************************
+* branch_mostf - choose most fractional branching variable
+*
+* This routine looks up the list of structural variables and chooses
+* that one, which is of integer kind and has most fractional value in
+* optimal solution to the current LP relaxation.
+*
+* This routine also selects the branch to be solved next where integer
+* infeasibility of the chosen variable is less than in other one.
+*
+* (Alexander Martin notices that "...most infeasible is as good as
+* random...".) */
+
+static int branch_mostf(glp_tree *T, int *_next)
+{ int j, jj, next;
+ double beta, most, temp;
+ /* choose the column to branch on */
+ jj = 0, most = DBL_MAX;
+ for (j = 1; j <= T->n; j++)
+ { if (T->non_int[j])
+ { beta = glp_get_col_prim(T->mip, j);
+ temp = floor(beta) + 0.5;
+ if (most > fabs(beta - temp))
+ { jj = j, most = fabs(beta - temp);
+ if (beta < temp)
+ next = GLP_DN_BRNCH;
+ else
+ next = GLP_UP_BRNCH;
+ }
+ }
+ }
+ *_next = next;
+ return jj;
+}
+
+/***********************************************************************
+* branch_drtom - choose branching var using Driebeck-Tomlin heuristic
+*
+* This routine chooses a structural variable, which is required to be
+* integral and has fractional value in optimal solution of the current
+* LP relaxation, using a heuristic proposed by Driebeck and Tomlin.
+*
+* The routine also selects the branch to be solved next, again due to
+* Driebeck and Tomlin.
+*
+* This routine is based on the heuristic proposed in:
+*
+* Driebeck N.J. An algorithm for the solution of mixed-integer
+* programming problems, Management Science, 12: 576-87 (1966);
+*
+* and improved in:
+*
+* Tomlin J.A. Branch and bound methods for integer and non-convex
+* programming, in J.Abadie (ed.), Integer and Nonlinear Programming,
+* North-Holland, Amsterdam, pp. 437-50 (1970).
+*
+* Must note that this heuristic is time-expensive, because computing
+* one-step degradation (see the routine below) requires one BTRAN for
+* each fractional-valued structural variable. */
+
+static int branch_drtom(glp_tree *T, int *_next)
+{ glp_prob *mip = T->mip;
+ int m = mip->m;
+ int n = mip->n;
+ unsigned char *non_int = T->non_int;
+ int j, jj, k, t, next, kase, len, stat, *ind;
+ double x, dk, alfa, delta_j, delta_k, delta_z, dz_dn, dz_up,
+ dd_dn, dd_up, degrad, *val;
+ /* basic solution of LP relaxation must be optimal */
+ xassert(glp_get_status(mip) == GLP_OPT);
+ /* allocate working arrays */
+ ind = xcalloc(1+n, sizeof(int));
+ val = xcalloc(1+n, sizeof(double));
+ /* nothing has been chosen so far */
+ jj = 0, degrad = -1.0;
+ /* walk through the list of columns (structural variables) */
+ for (j = 1; j <= n; j++)
+ { /* if j-th column is not marked as fractional, skip it */
+ if (!non_int[j]) continue;
+ /* obtain (fractional) value of j-th column in basic solution
+ of LP relaxation */
+ x = glp_get_col_prim(mip, j);
+ /* since the value of j-th column is fractional, the column is
+ basic; compute corresponding row of the simplex table */
+ len = glp_eval_tab_row(mip, m+j, ind, val);
+ /* the following fragment computes a change in the objective
+ function: delta Z = new Z - old Z, where old Z is the
+ objective value in the current optimal basis, and new Z is
+ the objective value in the adjacent basis, for two cases:
+ 1) if new upper bound ub' = floor(x[j]) is introduced for
+ j-th column (down branch);
+ 2) if new lower bound lb' = ceil(x[j]) is introduced for
+ j-th column (up branch);
+ since in both cases the solution remaining dual feasible
+ becomes primal infeasible, one implicit simplex iteration
+ is performed to determine the change delta Z;
+ it is obvious that new Z, which is never better than old Z,
+ is a lower (minimization) or upper (maximization) bound of
+ the objective function for down- and up-branches. */
+ for (kase = -1; kase <= +1; kase += 2)
+ { /* if kase < 0, the new upper bound of x[j] is introduced;
+ in this case x[j] should decrease in order to leave the
+ basis and go to its new upper bound */
+ /* if kase > 0, the new lower bound of x[j] is introduced;
+ in this case x[j] should increase in order to leave the
+ basis and go to its new lower bound */
+ /* apply the dual ratio test in order to determine which
+ auxiliary or structural variable should enter the basis
+ to keep dual feasibility */
+ k = glp_dual_rtest(mip, len, ind, val, kase, 1e-9);
+ if (k != 0) k = ind[k];
+ /* if no non-basic variable has been chosen, LP relaxation
+ of corresponding branch being primal infeasible and dual
+ unbounded has no primal feasible solution; in this case
+ the change delta Z is formally set to infinity */
+ if (k == 0)
+ { delta_z =
+ (T->mip->dir == GLP_MIN ? +DBL_MAX : -DBL_MAX);
+ goto skip;
+ }
+ /* row of the simplex table that corresponds to non-basic
+ variable x[k] choosen by the dual ratio test is:
+ x[j] = ... + alfa * x[k] + ...
+ where alfa is the influence coefficient (an element of
+ the simplex table row) */
+ /* determine the coefficient alfa */
+ for (t = 1; t <= len; t++) if (ind[t] == k) break;
+ xassert(1 <= t && t <= len);
+ alfa = val[t];
+ /* since in the adjacent basis the variable x[j] becomes
+ non-basic, knowing its value in the current basis we can
+ determine its change delta x[j] = new x[j] - old x[j] */
+ delta_j = (kase < 0 ? floor(x) : ceil(x)) - x;
+ /* and knowing the coefficient alfa we can determine the
+ corresponding change delta x[k] = new x[k] - old x[k],
+ where old x[k] is a value of x[k] in the current basis,
+ and new x[k] is a value of x[k] in the adjacent basis */
+ delta_k = delta_j / alfa;
+ /* Tomlin noticed that if the variable x[k] is of integer
+ kind, its change cannot be less (eventually) than one in
+ the magnitude */
+ if (k > m && glp_get_col_kind(mip, k-m) != GLP_CV)
+ { /* x[k] is structural integer variable */
+ if (fabs(delta_k - floor(delta_k + 0.5)) > 1e-3)
+ { if (delta_k > 0.0)
+ delta_k = ceil(delta_k); /* +3.14 -> +4 */
+ else
+ delta_k = floor(delta_k); /* -3.14 -> -4 */
+ }
+ }
+ /* now determine the status and reduced cost of x[k] in the
+ current basis */
+ if (k <= m)
+ { stat = glp_get_row_stat(mip, k);
+ dk = glp_get_row_dual(mip, k);
+ }
+ else
+ { stat = glp_get_col_stat(mip, k-m);
+ dk = glp_get_col_dual(mip, k-m);
+ }
+ /* if the current basis is dual degenerate, some reduced
+ costs which are close to zero may have wrong sign due to
+ round-off errors, so correct the sign of d[k] */
+ switch (T->mip->dir)
+ { case GLP_MIN:
+ if (stat == GLP_NL && dk < 0.0 ||
+ stat == GLP_NU && dk > 0.0 ||
+ stat == GLP_NF) dk = 0.0;
+ break;
+ case GLP_MAX:
+ if (stat == GLP_NL && dk > 0.0 ||
+ stat == GLP_NU && dk < 0.0 ||
+ stat == GLP_NF) dk = 0.0;
+ break;
+ default:
+ xassert(T != T);
+ }
+ /* now knowing the change of x[k] and its reduced cost d[k]
+ we can compute the corresponding change in the objective
+ function delta Z = new Z - old Z = d[k] * delta x[k];
+ note that due to Tomlin's modification new Z can be even
+ worse than in the adjacent basis */
+ delta_z = dk * delta_k;
+skip: /* new Z is never better than old Z, therefore the change
+ delta Z is always non-negative (in case of minimization)
+ or non-positive (in case of maximization) */
+ switch (T->mip->dir)
+ { case GLP_MIN: xassert(delta_z >= 0.0); break;
+ case GLP_MAX: xassert(delta_z <= 0.0); break;
+ default: xassert(T != T);
+ }
+ /* save the change in the objective fnction for down- and
+ up-branches, respectively */
+ if (kase < 0) dz_dn = delta_z; else dz_up = delta_z;
+ }
+ /* thus, in down-branch no integer feasible solution can be
+ better than Z + dz_dn, and in up-branch no integer feasible
+ solution can be better than Z + dz_up, where Z is value of
+ the objective function in the current basis */
+ /* following the heuristic by Driebeck and Tomlin we choose a
+ column (i.e. structural variable) which provides largest
+ degradation of the objective function in some of branches;
+ besides, we select the branch with smaller degradation to
+ be solved next and keep other branch with larger degradation
+ in the active list hoping to minimize the number of further
+ backtrackings */
+ if (degrad < fabs(dz_dn) || degrad < fabs(dz_up))
+ { jj = j;
+ if (fabs(dz_dn) < fabs(dz_up))
+ { /* select down branch to be solved next */
+ next = GLP_DN_BRNCH;
+ degrad = fabs(dz_up);
+ }
+ else
+ { /* select up branch to be solved next */
+ next = GLP_UP_BRNCH;
+ degrad = fabs(dz_dn);
+ }
+ /* save the objective changes for printing */
+ dd_dn = dz_dn, dd_up = dz_up;
+ /* if down- or up-branch has no feasible solution, we does
+ not need to consider other candidates (in principle, the
+ corresponding branch could be pruned right now) */
+ if (degrad == DBL_MAX) break;
+ }
+ }
+ /* free working arrays */
+ xfree(ind);
+ xfree(val);
+ /* something must be chosen */
+ xassert(1 <= jj && jj <= n);
+#if 1 /* 02/XI-2009 */
+ if (degrad < 1e-6 * (1.0 + 0.001 * fabs(mip->obj_val)))
+ { jj = branch_mostf(T, &next);
+ goto done;
+ }
+#endif
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ { xprintf("branch_drtom: column %d chosen to branch on\n", jj);
+ if (fabs(dd_dn) == DBL_MAX)
+ xprintf("branch_drtom: down-branch is infeasible\n");
+ else
+ xprintf("branch_drtom: down-branch bound is %.9e\n",
+ glp_get_obj_val(mip) + dd_dn);
+ if (fabs(dd_up) == DBL_MAX)
+ xprintf("branch_drtom: up-branch is infeasible\n");
+ else
+ xprintf("branch_drtom: up-branch bound is %.9e\n",
+ glp_get_obj_val(mip) + dd_up);
+ }
+done: *_next = next;
+ return jj;
+}
+
+/**********************************************************************/
+
+struct csa
+{ /* common storage area */
+ int *dn_cnt; /* int dn_cnt[1+n]; */
+ /* dn_cnt[j] is the number of subproblems, whose LP relaxations
+ have been solved and which are down-branches for variable x[j];
+ dn_cnt[j] = 0 means the down pseudocost is uninitialized */
+ double *dn_sum; /* double dn_sum[1+n]; */
+ /* dn_sum[j] is the sum of per unit degradations of the objective
+ over all dn_cnt[j] subproblems */
+ int *up_cnt; /* int up_cnt[1+n]; */
+ /* up_cnt[j] is the number of subproblems, whose LP relaxations
+ have been solved and which are up-branches for variable x[j];
+ up_cnt[j] = 0 means the up pseudocost is uninitialized */
+ double *up_sum; /* double up_sum[1+n]; */
+ /* up_sum[j] is the sum of per unit degradations of the objective
+ over all up_cnt[j] subproblems */
+};
+
+void *ios_pcost_init(glp_tree *tree)
+{ /* initialize working data used on pseudocost branching */
+ struct csa *csa;
+ int n = tree->n, j;
+ csa = xmalloc(sizeof(struct csa));
+ csa->dn_cnt = xcalloc(1+n, sizeof(int));
+ csa->dn_sum = xcalloc(1+n, sizeof(double));
+ csa->up_cnt = xcalloc(1+n, sizeof(int));
+ csa->up_sum = xcalloc(1+n, sizeof(double));
+ for (j = 1; j <= n; j++)
+ { csa->dn_cnt[j] = csa->up_cnt[j] = 0;
+ csa->dn_sum[j] = csa->up_sum[j] = 0.0;
+ }
+ return csa;
+}
+
+static double eval_degrad(glp_prob *P, int j, double bnd)
+{ /* compute degradation of the objective on fixing x[j] at given
+ value with a limited number of dual simplex iterations */
+ /* this routine fixes column x[j] at specified value bnd,
+ solves resulting LP, and returns a lower bound to degradation
+ of the objective, degrad >= 0 */
+ glp_prob *lp;
+ glp_smcp parm;
+ int ret;
+ double degrad;
+ /* the current basis must be optimal */
+ xassert(glp_get_status(P) == GLP_OPT);
+ /* create a copy of P */
+ lp = glp_create_prob();
+ glp_copy_prob(lp, P, 0);
+ /* fix column x[j] at specified value */
+ glp_set_col_bnds(lp, j, GLP_FX, bnd, bnd);
+ /* try to solve resulting LP */
+ glp_init_smcp(&parm);
+ parm.msg_lev = GLP_MSG_OFF;
+ parm.meth = GLP_DUAL;
+ parm.it_lim = 30;
+ parm.out_dly = 1000;
+ parm.meth = GLP_DUAL;
+ ret = glp_simplex(lp, &parm);
+ if (ret == 0 || ret == GLP_EITLIM)
+ { if (glp_get_prim_stat(lp) == GLP_NOFEAS)
+ { /* resulting LP has no primal feasible solution */
+ degrad = DBL_MAX;
+ }
+ else if (glp_get_dual_stat(lp) == GLP_FEAS)
+ { /* resulting basis is optimal or at least dual feasible,
+ so we have the correct lower bound to degradation */
+ if (P->dir == GLP_MIN)
+ degrad = lp->obj_val - P->obj_val;
+ else if (P->dir == GLP_MAX)
+ degrad = P->obj_val - lp->obj_val;
+ else
+ xassert(P != P);
+ /* degradation cannot be negative by definition */
+ /* note that the lower bound to degradation may be close
+ to zero even if its exact value is zero due to round-off
+ errors on computing the objective value */
+ if (degrad < 1e-6 * (1.0 + 0.001 * fabs(P->obj_val)))
+ degrad = 0.0;
+ }
+ else
+ { /* the final basis reported by the simplex solver is dual
+ infeasible, so we cannot determine a non-trivial lower
+ bound to degradation */
+ degrad = 0.0;
+ }
+ }
+ else
+ { /* the simplex solver failed */
+ degrad = 0.0;
+ }
+ /* delete the copy of P */
+ glp_delete_prob(lp);
+ return degrad;
+}
+
+void ios_pcost_update(glp_tree *tree)
+{ /* update history information for pseudocost branching */
+ /* this routine is called every time when LP relaxation of the
+ current subproblem has been solved to optimality with all lazy
+ and cutting plane constraints included */
+ int j;
+ double dx, dz, psi;
+ struct csa *csa = tree->pcost;
+ xassert(csa != NULL);
+ xassert(tree->curr != NULL);
+ /* if the current subproblem is the root, skip updating */
+ if (tree->curr->up == NULL) goto skip;
+ /* determine branching variable x[j], which was used in the
+ parent subproblem to create the current subproblem */
+ j = tree->curr->up->br_var;
+ xassert(1 <= j && j <= tree->n);
+ /* determine the change dx[j] = new x[j] - old x[j],
+ where new x[j] is a value of x[j] in optimal solution to LP
+ relaxation of the current subproblem, old x[j] is a value of
+ x[j] in optimal solution to LP relaxation of the parent
+ subproblem */
+ dx = tree->mip->col[j]->prim - tree->curr->up->br_val;
+ xassert(dx != 0.0);
+ /* determine corresponding change dz = new dz - old dz in the
+ objective function value */
+ dz = tree->mip->obj_val - tree->curr->up->lp_obj;
+ /* determine per unit degradation of the objective function */
+ psi = fabs(dz / dx);
+ /* update history information */
+ if (dx < 0.0)
+ { /* the current subproblem is down-branch */
+ csa->dn_cnt[j]++;
+ csa->dn_sum[j] += psi;
+ }
+ else /* dx > 0.0 */
+ { /* the current subproblem is up-branch */
+ csa->up_cnt[j]++;
+ csa->up_sum[j] += psi;
+ }
+skip: return;
+}
+
+void ios_pcost_free(glp_tree *tree)
+{ /* free working area used on pseudocost branching */
+ struct csa *csa = tree->pcost;
+ xassert(csa != NULL);
+ xfree(csa->dn_cnt);
+ xfree(csa->dn_sum);
+ xfree(csa->up_cnt);
+ xfree(csa->up_sum);
+ xfree(csa);
+ tree->pcost = NULL;
+ return;
+}
+
+static double eval_psi(glp_tree *T, int j, int brnch)
+{ /* compute estimation of pseudocost of variable x[j] for down-
+ or up-branch */
+ struct csa *csa = T->pcost;
+ double beta, degrad, psi;
+ xassert(csa != NULL);
+ xassert(1 <= j && j <= T->n);
+ if (brnch == GLP_DN_BRNCH)
+ { /* down-branch */
+ if (csa->dn_cnt[j] == 0)
+ { /* initialize down pseudocost */
+ beta = T->mip->col[j]->prim;
+ degrad = eval_degrad(T->mip, j, floor(beta));
+ if (degrad == DBL_MAX)
+ { psi = DBL_MAX;
+ goto done;
+ }
+ csa->dn_cnt[j] = 1;
+ csa->dn_sum[j] = degrad / (beta - floor(beta));
+ }
+ psi = csa->dn_sum[j] / (double)csa->dn_cnt[j];
+ }
+ else if (brnch == GLP_UP_BRNCH)
+ { /* up-branch */
+ if (csa->up_cnt[j] == 0)
+ { /* initialize up pseudocost */
+ beta = T->mip->col[j]->prim;
+ degrad = eval_degrad(T->mip, j, ceil(beta));
+ if (degrad == DBL_MAX)
+ { psi = DBL_MAX;
+ goto done;
+ }
+ csa->up_cnt[j] = 1;
+ csa->up_sum[j] = degrad / (ceil(beta) - beta);
+ }
+ psi = csa->up_sum[j] / (double)csa->up_cnt[j];
+ }
+ else
+ xassert(brnch != brnch);
+done: return psi;
+}
+
+static void progress(glp_tree *T)
+{ /* display progress of pseudocost initialization */
+ struct csa *csa = T->pcost;
+ int j, nv = 0, ni = 0;
+ for (j = 1; j <= T->n; j++)
+ { if (glp_ios_can_branch(T, j))
+ { nv++;
+ if (csa->dn_cnt[j] > 0 && csa->up_cnt[j] > 0) ni++;
+ }
+ }
+ xprintf("Pseudocosts initialized for %d of %d variables\n",
+ ni, nv);
+ return;
+}
+
+int ios_pcost_branch(glp_tree *T, int *_next)
+{ /* choose branching variable with pseudocost branching */
+#if 0 /* 10/VI-2013 */
+ glp_long t = xtime();
+#else
+ double t = xtime();
+#endif
+ int j, jjj, sel;
+ double beta, psi, d1, d2, d, dmax;
+ /* initialize the working arrays */
+ if (T->pcost == NULL)
+ T->pcost = ios_pcost_init(T);
+ /* nothing has been chosen so far */
+ jjj = 0, dmax = -1.0;
+ /* go through the list of branching candidates */
+ for (j = 1; j <= T->n; j++)
+ { if (!glp_ios_can_branch(T, j)) continue;
+ /* determine primal value of x[j] in optimal solution to LP
+ relaxation of the current subproblem */
+ beta = T->mip->col[j]->prim;
+ /* estimate pseudocost of x[j] for down-branch */
+ psi = eval_psi(T, j, GLP_DN_BRNCH);
+ if (psi == DBL_MAX)
+ { /* down-branch has no primal feasible solution */
+ jjj = j, sel = GLP_DN_BRNCH;
+ goto done;
+ }
+ /* estimate degradation of the objective for down-branch */
+ d1 = psi * (beta - floor(beta));
+ /* estimate pseudocost of x[j] for up-branch */
+ psi = eval_psi(T, j, GLP_UP_BRNCH);
+ if (psi == DBL_MAX)
+ { /* up-branch has no primal feasible solution */
+ jjj = j, sel = GLP_UP_BRNCH;
+ goto done;
+ }
+ /* estimate degradation of the objective for up-branch */
+ d2 = psi * (ceil(beta) - beta);
+ /* determine d = max(d1, d2) */
+ d = (d1 > d2 ? d1 : d2);
+ /* choose x[j] which provides maximal estimated degradation of
+ the objective either in down- or up-branch */
+ if (dmax < d)
+ { dmax = d;
+ jjj = j;
+ /* continue the search from a subproblem, where degradation
+ is less than in other one */
+ sel = (d1 <= d2 ? GLP_DN_BRNCH : GLP_UP_BRNCH);
+ }
+ /* display progress of pseudocost initialization */
+ if (T->parm->msg_lev >= GLP_ON)
+ { if (xdifftime(xtime(), t) >= 10.0)
+ { progress(T);
+ t = xtime();
+ }
+ }
+ }
+ if (dmax == 0.0)
+ { /* no degradation is indicated; choose a variable having most
+ fractional value */
+ jjj = branch_mostf(T, &sel);
+ }
+done: *_next = sel;
+ return jjj;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpios11.c b/test/monniaux/glpk-4.65/src/draft/glpios11.c
new file mode 100644
index 00000000..09fccef6
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpios11.c
@@ -0,0 +1,435 @@
+/* glpios11.c (process cuts stored in the local cut pool) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2017, 2018 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/>.
+***********************************************************************/
+
+#include "draft.h"
+#include "env.h"
+#include "ios.h"
+
+/***********************************************************************
+* NAME
+*
+* ios_process_cuts - process cuts stored in the local cut pool
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void ios_process_cuts(glp_tree *T);
+*
+* DESCRIPTION
+*
+* The routine ios_process_cuts analyzes each cut currently stored in
+* the local cut pool, which must be non-empty, and either adds the cut
+* to the current subproblem or just discards it. All cuts are assumed
+* to be locally valid. On exit the local cut pool remains unchanged.
+*
+* REFERENCES
+*
+* 1. E.Balas, S.Ceria, G.Cornuejols, "Mixed 0-1 Programming by
+* Lift-and-Project in a Branch-and-Cut Framework", Management Sc.,
+* 42 (1996) 1229-1246.
+*
+* 2. G.Andreello, A.Caprara, and M.Fischetti, "Embedding Cuts in
+* a Branch&Cut Framework: a Computational Study with {0,1/2}-Cuts",
+* Preliminary Draft, October 28, 2003, pp.6-8. */
+
+struct info
+{ /* estimated cut efficiency */
+ IOSCUT *cut;
+ /* pointer to cut in the cut pool */
+ char flag;
+ /* if this flag is set, the cut is included into the current
+ subproblem */
+ double eff;
+ /* cut efficacy (normalized residual) */
+ double deg;
+ /* lower bound to objective degradation */
+};
+
+static int CDECL fcmp(const void *arg1, const void *arg2)
+{ const struct info *info1 = arg1, *info2 = arg2;
+ if (info1->deg == 0.0 && info2->deg == 0.0)
+ { if (info1->eff > info2->eff) return -1;
+ if (info1->eff < info2->eff) return +1;
+ }
+ else
+ { if (info1->deg > info2->deg) return -1;
+ if (info1->deg < info2->deg) return +1;
+ }
+ return 0;
+}
+
+static double parallel(IOSCUT *a, IOSCUT *b, double work[]);
+
+#ifdef NEW_LOCAL /* 02/II-2018 */
+void ios_process_cuts(glp_tree *T)
+{ IOSPOOL *pool;
+ IOSCUT *cut;
+ GLPAIJ *aij;
+ struct info *info;
+ int k, kk, max_cuts, len, ret, *ind;
+ double *val, *work, rhs;
+ /* the current subproblem must exist */
+ xassert(T->curr != NULL);
+ /* the pool must exist and be non-empty */
+ pool = T->local;
+ xassert(pool != NULL);
+ xassert(pool->m > 0);
+ /* allocate working arrays */
+ info = xcalloc(1+pool->m, sizeof(struct info));
+ ind = xcalloc(1+T->n, sizeof(int));
+ val = xcalloc(1+T->n, sizeof(double));
+ work = xcalloc(1+T->n, sizeof(double));
+ for (k = 1; k <= T->n; k++) work[k] = 0.0;
+ /* build the list of cuts stored in the cut pool */
+ for (k = 1; k <= pool->m; k++)
+ info[k].cut = pool->row[k], info[k].flag = 0;
+ /* estimate efficiency of all cuts in the cut pool */
+ for (k = 1; k <= pool->m; k++)
+ { double temp, dy, dz;
+ cut = info[k].cut;
+ /* build the vector of cut coefficients and compute its
+ Euclidean norm */
+ len = 0; temp = 0.0;
+ for (aij = cut->ptr; aij != NULL; aij = aij->r_next)
+ { xassert(1 <= aij->col->j && aij->col->j <= T->n);
+ len++, ind[len] = aij->col->j, val[len] = aij->val;
+ temp += aij->val * aij->val;
+ }
+ if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
+ /* transform the cut to express it only through non-basic
+ (auxiliary and structural) variables */
+ len = glp_transform_row(T->mip, len, ind, val);
+ /* determine change in the cut value and in the objective
+ value for the adjacent basis by simulating one step of the
+ dual simplex */
+ switch (cut->type)
+ { case GLP_LO: rhs = cut->lb; break;
+ case GLP_UP: rhs = cut->ub; break;
+ default: xassert(cut != cut);
+ }
+ ret = _glp_analyze_row(T->mip, len, ind, val, cut->type,
+ rhs, 1e-9, NULL, NULL, NULL, NULL, &dy, &dz);
+ /* determine normalized residual and lower bound to objective
+ degradation */
+ if (ret == 0)
+ { info[k].eff = fabs(dy) / sqrt(temp);
+ /* if some reduced costs violates (slightly) their zero
+ bounds (i.e. have wrong signs) due to round-off errors,
+ dz also may have wrong sign being close to zero */
+ if (T->mip->dir == GLP_MIN)
+ { if (dz < 0.0) dz = 0.0;
+ info[k].deg = + dz;
+ }
+ else /* GLP_MAX */
+ { if (dz > 0.0) dz = 0.0;
+ info[k].deg = - dz;
+ }
+ }
+ else if (ret == 1)
+ { /* the constraint is not violated at the current point */
+ info[k].eff = info[k].deg = 0.0;
+ }
+ else if (ret == 2)
+ { /* no dual feasible adjacent basis exists */
+ info[k].eff = 1.0;
+ info[k].deg = DBL_MAX;
+ }
+ else
+ xassert(ret != ret);
+ /* if the degradation is too small, just ignore it */
+ if (info[k].deg < 0.01) info[k].deg = 0.0;
+ }
+ /* sort the list of cuts by decreasing objective degradation and
+ then by decreasing efficacy */
+ qsort(&info[1], pool->m, sizeof(struct info), fcmp);
+ /* only first (most efficient) max_cuts in the list are qualified
+ as candidates to be added to the current subproblem */
+ max_cuts = (T->curr->level == 0 ? 90 : 10);
+ if (max_cuts > pool->m) max_cuts = pool->m;
+ /* add cuts to the current subproblem */
+#if 0
+ xprintf("*** adding cuts ***\n");
+#endif
+ for (k = 1; k <= max_cuts; k++)
+ { int i, len;
+ /* if this cut seems to be inefficient, skip it */
+ if (info[k].deg < 0.01 && info[k].eff < 0.01) continue;
+ /* if the angle between this cut and every other cut included
+ in the current subproblem is small, skip this cut */
+ for (kk = 1; kk < k; kk++)
+ { if (info[kk].flag)
+ { if (parallel(info[k].cut, info[kk].cut, work) > 0.90)
+ break;
+ }
+ }
+ if (kk < k) continue;
+ /* add this cut to the current subproblem */
+#if 0
+ xprintf("eff = %g; deg = %g\n", info[k].eff, info[k].deg);
+#endif
+ cut = info[k].cut, info[k].flag = 1;
+ i = glp_add_rows(T->mip, 1);
+ if (cut->name != NULL)
+ glp_set_row_name(T->mip, i, cut->name);
+ xassert(T->mip->row[i]->origin == GLP_RF_CUT);
+ T->mip->row[i]->klass = cut->klass;
+ len = 0;
+ for (aij = cut->ptr; aij != NULL; aij = aij->r_next)
+ len++, ind[len] = aij->col->j, val[len] = aij->val;
+ glp_set_mat_row(T->mip, i, len, ind, val);
+ switch (cut->type)
+ { case GLP_LO: rhs = cut->lb; break;
+ case GLP_UP: rhs = cut->ub; break;
+ default: xassert(cut != cut);
+ }
+ glp_set_row_bnds(T->mip, i, cut->type, rhs, rhs);
+ }
+ /* free working arrays */
+ xfree(info);
+ xfree(ind);
+ xfree(val);
+ xfree(work);
+ return;
+}
+#else
+void ios_process_cuts(glp_tree *T)
+{ IOSPOOL *pool;
+ IOSCUT *cut;
+ IOSAIJ *aij;
+ struct info *info;
+ int k, kk, max_cuts, len, ret, *ind;
+ double *val, *work;
+ /* the current subproblem must exist */
+ xassert(T->curr != NULL);
+ /* the pool must exist and be non-empty */
+ pool = T->local;
+ xassert(pool != NULL);
+ xassert(pool->size > 0);
+ /* allocate working arrays */
+ info = xcalloc(1+pool->size, sizeof(struct info));
+ ind = xcalloc(1+T->n, sizeof(int));
+ val = xcalloc(1+T->n, sizeof(double));
+ work = xcalloc(1+T->n, sizeof(double));
+ for (k = 1; k <= T->n; k++) work[k] = 0.0;
+ /* build the list of cuts stored in the cut pool */
+ for (k = 0, cut = pool->head; cut != NULL; cut = cut->next)
+ k++, info[k].cut = cut, info[k].flag = 0;
+ xassert(k == pool->size);
+ /* estimate efficiency of all cuts in the cut pool */
+ for (k = 1; k <= pool->size; k++)
+ { double temp, dy, dz;
+ cut = info[k].cut;
+ /* build the vector of cut coefficients and compute its
+ Euclidean norm */
+ len = 0; temp = 0.0;
+ for (aij = cut->ptr; aij != NULL; aij = aij->next)
+ { xassert(1 <= aij->j && aij->j <= T->n);
+ len++, ind[len] = aij->j, val[len] = aij->val;
+ temp += aij->val * aij->val;
+ }
+ if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
+ /* transform the cut to express it only through non-basic
+ (auxiliary and structural) variables */
+ len = glp_transform_row(T->mip, len, ind, val);
+ /* determine change in the cut value and in the objective
+ value for the adjacent basis by simulating one step of the
+ dual simplex */
+ ret = _glp_analyze_row(T->mip, len, ind, val, cut->type,
+ cut->rhs, 1e-9, NULL, NULL, NULL, NULL, &dy, &dz);
+ /* determine normalized residual and lower bound to objective
+ degradation */
+ if (ret == 0)
+ { info[k].eff = fabs(dy) / sqrt(temp);
+ /* if some reduced costs violates (slightly) their zero
+ bounds (i.e. have wrong signs) due to round-off errors,
+ dz also may have wrong sign being close to zero */
+ if (T->mip->dir == GLP_MIN)
+ { if (dz < 0.0) dz = 0.0;
+ info[k].deg = + dz;
+ }
+ else /* GLP_MAX */
+ { if (dz > 0.0) dz = 0.0;
+ info[k].deg = - dz;
+ }
+ }
+ else if (ret == 1)
+ { /* the constraint is not violated at the current point */
+ info[k].eff = info[k].deg = 0.0;
+ }
+ else if (ret == 2)
+ { /* no dual feasible adjacent basis exists */
+ info[k].eff = 1.0;
+ info[k].deg = DBL_MAX;
+ }
+ else
+ xassert(ret != ret);
+ /* if the degradation is too small, just ignore it */
+ if (info[k].deg < 0.01) info[k].deg = 0.0;
+ }
+ /* sort the list of cuts by decreasing objective degradation and
+ then by decreasing efficacy */
+ qsort(&info[1], pool->size, sizeof(struct info), fcmp);
+ /* only first (most efficient) max_cuts in the list are qualified
+ as candidates to be added to the current subproblem */
+ max_cuts = (T->curr->level == 0 ? 90 : 10);
+ if (max_cuts > pool->size) max_cuts = pool->size;
+ /* add cuts to the current subproblem */
+#if 0
+ xprintf("*** adding cuts ***\n");
+#endif
+ for (k = 1; k <= max_cuts; k++)
+ { int i, len;
+ /* if this cut seems to be inefficient, skip it */
+ if (info[k].deg < 0.01 && info[k].eff < 0.01) continue;
+ /* if the angle between this cut and every other cut included
+ in the current subproblem is small, skip this cut */
+ for (kk = 1; kk < k; kk++)
+ { if (info[kk].flag)
+ { if (parallel(info[k].cut, info[kk].cut, work) > 0.90)
+ break;
+ }
+ }
+ if (kk < k) continue;
+ /* add this cut to the current subproblem */
+#if 0
+ xprintf("eff = %g; deg = %g\n", info[k].eff, info[k].deg);
+#endif
+ cut = info[k].cut, info[k].flag = 1;
+ i = glp_add_rows(T->mip, 1);
+ if (cut->name != NULL)
+ glp_set_row_name(T->mip, i, cut->name);
+ xassert(T->mip->row[i]->origin == GLP_RF_CUT);
+ T->mip->row[i]->klass = cut->klass;
+ len = 0;
+ for (aij = cut->ptr; aij != NULL; aij = aij->next)
+ len++, ind[len] = aij->j, val[len] = aij->val;
+ glp_set_mat_row(T->mip, i, len, ind, val);
+ xassert(cut->type == GLP_LO || cut->type == GLP_UP);
+ glp_set_row_bnds(T->mip, i, cut->type, cut->rhs, cut->rhs);
+ }
+ /* free working arrays */
+ xfree(info);
+ xfree(ind);
+ xfree(val);
+ xfree(work);
+ return;
+}
+#endif
+
+#if 0
+/***********************************************************************
+* Given a cut a * x >= b (<= b) the routine efficacy computes the cut
+* efficacy as follows:
+*
+* eff = d * (a * x~ - b) / ||a||,
+*
+* where d is -1 (in case of '>= b') or +1 (in case of '<= b'), x~ is
+* the vector of values of structural variables in optimal solution to
+* LP relaxation of the current subproblem, ||a|| is the Euclidean norm
+* of the vector of cut coefficients.
+*
+* If the cut is violated at point x~, the efficacy eff is positive,
+* and its value is the Euclidean distance between x~ and the cut plane
+* a * x = b in the space of structural variables.
+*
+* Following geometrical intuition, it is quite natural to consider
+* this distance as a first-order measure of the expected efficacy of
+* the cut: the larger the distance the better the cut [1]. */
+
+static double efficacy(glp_tree *T, IOSCUT *cut)
+{ glp_prob *mip = T->mip;
+ IOSAIJ *aij;
+ double s = 0.0, t = 0.0, temp;
+ for (aij = cut->ptr; aij != NULL; aij = aij->next)
+ { xassert(1 <= aij->j && aij->j <= mip->n);
+ s += aij->val * mip->col[aij->j]->prim;
+ t += aij->val * aij->val;
+ }
+ temp = sqrt(t);
+ if (temp < DBL_EPSILON) temp = DBL_EPSILON;
+ if (cut->type == GLP_LO)
+ temp = (s >= cut->rhs ? 0.0 : (cut->rhs - s) / temp);
+ else if (cut->type == GLP_UP)
+ temp = (s <= cut->rhs ? 0.0 : (s - cut->rhs) / temp);
+ else
+ xassert(cut != cut);
+ return temp;
+}
+#endif
+
+/***********************************************************************
+* Given two cuts a1 * x >= b1 (<= b1) and a2 * x >= b2 (<= b2) the
+* routine parallel computes the cosine of angle between the cut planes
+* a1 * x = b1 and a2 * x = b2 (which is the acute angle between two
+* normals to these planes) in the space of structural variables as
+* follows:
+*
+* cos phi = (a1' * a2) / (||a1|| * ||a2||),
+*
+* where (a1' * a2) is a dot product of vectors of cut coefficients,
+* ||a1|| and ||a2|| are Euclidean norms of vectors a1 and a2.
+*
+* Note that requirement cos phi = 0 forces the cuts to be orthogonal,
+* i.e. with disjoint support, while requirement cos phi <= 0.999 means
+* only avoiding duplicate (parallel) cuts [1]. */
+
+#ifdef NEW_LOCAL /* 02/II-2018 */
+static double parallel(IOSCUT *a, IOSCUT *b, double work[])
+{ GLPAIJ *aij;
+ double s = 0.0, sa = 0.0, sb = 0.0, temp;
+ for (aij = a->ptr; aij != NULL; aij = aij->r_next)
+ { work[aij->col->j] = aij->val;
+ sa += aij->val * aij->val;
+ }
+ for (aij = b->ptr; aij != NULL; aij = aij->r_next)
+ { s += work[aij->col->j] * aij->val;
+ sb += aij->val * aij->val;
+ }
+ for (aij = a->ptr; aij != NULL; aij = aij->r_next)
+ work[aij->col->j] = 0.0;
+ temp = sqrt(sa) * sqrt(sb);
+ if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
+ return s / temp;
+}
+#else
+static double parallel(IOSCUT *a, IOSCUT *b, double work[])
+{ IOSAIJ *aij;
+ double s = 0.0, sa = 0.0, sb = 0.0, temp;
+ for (aij = a->ptr; aij != NULL; aij = aij->next)
+ { work[aij->j] = aij->val;
+ sa += aij->val * aij->val;
+ }
+ for (aij = b->ptr; aij != NULL; aij = aij->next)
+ { s += work[aij->j] * aij->val;
+ sb += aij->val * aij->val;
+ }
+ for (aij = a->ptr; aij != NULL; aij = aij->next)
+ work[aij->j] = 0.0;
+ temp = sqrt(sa) * sqrt(sb);
+ if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
+ return s / temp;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpios12.c b/test/monniaux/glpk-4.65/src/draft/glpios12.c
new file mode 100644
index 00000000..bec6fa2c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpios12.c
@@ -0,0 +1,177 @@
+/* glpios12.c (node selection heuristics) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+
+/***********************************************************************
+* NAME
+*
+* ios_choose_node - select subproblem to continue the search
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* int ios_choose_node(glp_tree *T);
+*
+* DESCRIPTION
+*
+* The routine ios_choose_node selects a subproblem from the active
+* list to continue the search. The choice depends on the backtracking
+* technique option.
+*
+* RETURNS
+*
+* The routine ios_choose_node return the reference number of the
+* subproblem selected. */
+
+static int most_feas(glp_tree *T);
+static int best_proj(glp_tree *T);
+static int best_node(glp_tree *T);
+
+int ios_choose_node(glp_tree *T)
+{ int p;
+ if (T->parm->bt_tech == GLP_BT_DFS)
+ { /* depth first search */
+ xassert(T->tail != NULL);
+ p = T->tail->p;
+ }
+ else if (T->parm->bt_tech == GLP_BT_BFS)
+ { /* breadth first search */
+ xassert(T->head != NULL);
+ p = T->head->p;
+ }
+ else if (T->parm->bt_tech == GLP_BT_BLB)
+ { /* select node with best local bound */
+ p = best_node(T);
+ }
+ else if (T->parm->bt_tech == GLP_BT_BPH)
+ { if (T->mip->mip_stat == GLP_UNDEF)
+ { /* "most integer feasible" subproblem */
+ p = most_feas(T);
+ }
+ else
+ { /* best projection heuristic */
+ p = best_proj(T);
+ }
+ }
+ else
+ xassert(T != T);
+ return p;
+}
+
+static int most_feas(glp_tree *T)
+{ /* select subproblem whose parent has minimal sum of integer
+ infeasibilities */
+ IOSNPD *node;
+ int p;
+ double best;
+ p = 0, best = DBL_MAX;
+ for (node = T->head; node != NULL; node = node->next)
+ { xassert(node->up != NULL);
+ if (best > node->up->ii_sum)
+ p = node->p, best = node->up->ii_sum;
+ }
+ return p;
+}
+
+static int best_proj(glp_tree *T)
+{ /* select subproblem using the best projection heuristic */
+ IOSNPD *root, *node;
+ int p;
+ double best, deg, obj;
+ /* the global bound must exist */
+ xassert(T->mip->mip_stat == GLP_FEAS);
+ /* obtain pointer to the root node, which must exist */
+ root = T->slot[1].node;
+ xassert(root != NULL);
+ /* deg estimates degradation of the objective function per unit
+ of the sum of integer infeasibilities */
+ xassert(root->ii_sum > 0.0);
+ deg = (T->mip->mip_obj - root->bound) / root->ii_sum;
+ /* nothing has been selected so far */
+ p = 0, best = DBL_MAX;
+ /* walk through the list of active subproblems */
+ for (node = T->head; node != NULL; node = node->next)
+ { xassert(node->up != NULL);
+ /* obj estimates optimal objective value if the sum of integer
+ infeasibilities were zero */
+ obj = node->up->bound + deg * node->up->ii_sum;
+ if (T->mip->dir == GLP_MAX) obj = - obj;
+ /* select the subproblem which has the best estimated optimal
+ objective value */
+ if (best > obj) p = node->p, best = obj;
+ }
+ return p;
+}
+
+static int best_node(glp_tree *T)
+{ /* select subproblem with best local bound */
+ IOSNPD *node, *best = NULL;
+ double bound, eps;
+ switch (T->mip->dir)
+ { case GLP_MIN:
+ bound = +DBL_MAX;
+ for (node = T->head; node != NULL; node = node->next)
+ if (bound > node->bound) bound = node->bound;
+ xassert(bound != +DBL_MAX);
+ eps = 1e-10 * (1.0 + fabs(bound));
+ for (node = T->head; node != NULL; node = node->next)
+ { if (node->bound <= bound + eps)
+ { xassert(node->up != NULL);
+ if (best == NULL ||
+#if 1
+ best->up->ii_sum > node->up->ii_sum) best = node;
+#else
+ best->lp_obj > node->lp_obj) best = node;
+#endif
+ }
+ }
+ break;
+ case GLP_MAX:
+ bound = -DBL_MAX;
+ for (node = T->head; node != NULL; node = node->next)
+ if (bound < node->bound) bound = node->bound;
+ xassert(bound != -DBL_MAX);
+ eps = 1e-10 * (1.0 + fabs(bound));
+ for (node = T->head; node != NULL; node = node->next)
+ { if (node->bound >= bound - eps)
+ { xassert(node->up != NULL);
+ if (best == NULL ||
+#if 1
+ best->up->ii_sum > node->up->ii_sum) best = node;
+#else
+ best->lp_obj < node->lp_obj) best = node;
+#endif
+ }
+ }
+ break;
+ default:
+ xassert(T != T);
+ }
+ xassert(best != NULL);
+ return best->p;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpipm.c b/test/monniaux/glpk-4.65/src/draft/glpipm.c
new file mode 100644
index 00000000..2b3a8176
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpipm.c
@@ -0,0 +1,1144 @@
+/* glpipm.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpipm.h"
+#include "glpmat.h"
+
+#define ITER_MAX 100
+/* maximal number of iterations */
+
+struct csa
+{ /* common storage area */
+ /*--------------------------------------------------------------*/
+ /* LP data */
+ int m;
+ /* number of rows (equality constraints) */
+ int n;
+ /* number of columns (structural variables) */
+ int *A_ptr; /* int A_ptr[1+m+1]; */
+ int *A_ind; /* int A_ind[A_ptr[m+1]]; */
+ double *A_val; /* double A_val[A_ptr[m+1]]; */
+ /* mxn-matrix A in storage-by-rows format */
+ double *b; /* double b[1+m]; */
+ /* m-vector b of right-hand sides */
+ double *c; /* double c[1+n]; */
+ /* n-vector c of objective coefficients; c[0] is constant term of
+ the objective function */
+ /*--------------------------------------------------------------*/
+ /* LP solution */
+ double *x; /* double x[1+n]; */
+ double *y; /* double y[1+m]; */
+ double *z; /* double z[1+n]; */
+ /* current point in primal-dual space; the best point on exit */
+ /*--------------------------------------------------------------*/
+ /* control parameters */
+ const glp_iptcp *parm;
+ /*--------------------------------------------------------------*/
+ /* working arrays and variables */
+ double *D; /* double D[1+n]; */
+ /* diagonal nxn-matrix D = X*inv(Z), where X = diag(x[j]) and
+ Z = diag(z[j]) */
+ int *P; /* int P[1+m+m]; */
+ /* permutation mxm-matrix P used to minimize fill-in in Cholesky
+ factorization */
+ int *S_ptr; /* int S_ptr[1+m+1]; */
+ int *S_ind; /* int S_ind[S_ptr[m+1]]; */
+ double *S_val; /* double S_val[S_ptr[m+1]]; */
+ double *S_diag; /* double S_diag[1+m]; */
+ /* symmetric mxm-matrix S = P*A*D*A'*P' whose upper triangular
+ part without diagonal elements is stored in S_ptr, S_ind, and
+ S_val in storage-by-rows format, diagonal elements are stored
+ in S_diag */
+ int *U_ptr; /* int U_ptr[1+m+1]; */
+ int *U_ind; /* int U_ind[U_ptr[m+1]]; */
+ double *U_val; /* double U_val[U_ptr[m+1]]; */
+ double *U_diag; /* double U_diag[1+m]; */
+ /* upper triangular mxm-matrix U defining Cholesky factorization
+ S = U'*U; its non-diagonal elements are stored in U_ptr, U_ind,
+ U_val in storage-by-rows format, diagonal elements are stored
+ in U_diag */
+ int iter;
+ /* iteration number (0, 1, 2, ...); iter = 0 corresponds to the
+ initial point */
+ double obj;
+ /* current value of the objective function */
+ double rpi;
+ /* relative primal infeasibility rpi = ||A*x-b||/(1+||b||) */
+ double rdi;
+ /* relative dual infeasibility rdi = ||A'*y+z-c||/(1+||c||) */
+ double gap;
+ /* primal-dual gap = |c'*x-b'*y|/(1+|c'*x|) which is a relative
+ difference between primal and dual objective functions */
+ double phi;
+ /* merit function phi = ||A*x-b||/max(1,||b||) +
+ + ||A'*y+z-c||/max(1,||c||) +
+ + |c'*x-b'*y|/max(1,||b||,||c||) */
+ double mu;
+ /* duality measure mu = x'*z/n (used as barrier parameter) */
+ double rmu;
+ /* rmu = max(||A*x-b||,||A'*y+z-c||)/mu */
+ double rmu0;
+ /* the initial value of rmu on iteration 0 */
+ double *phi_min; /* double phi_min[1+ITER_MAX]; */
+ /* phi_min[k] = min(phi[k]), where phi[k] is the value of phi on
+ k-th iteration, 0 <= k <= iter */
+ int best_iter;
+ /* iteration number, on which the value of phi reached its best
+ (minimal) value */
+ double *best_x; /* double best_x[1+n]; */
+ double *best_y; /* double best_y[1+m]; */
+ double *best_z; /* double best_z[1+n]; */
+ /* best point (in the sense of the merit function phi) which has
+ been reached on iteration iter_best */
+ double best_obj;
+ /* objective value at the best point */
+ double *dx_aff; /* double dx_aff[1+n]; */
+ double *dy_aff; /* double dy_aff[1+m]; */
+ double *dz_aff; /* double dz_aff[1+n]; */
+ /* affine scaling direction */
+ double alfa_aff_p, alfa_aff_d;
+ /* maximal primal and dual stepsizes in affine scaling direction,
+ on which x and z are still non-negative */
+ double mu_aff;
+ /* duality measure mu_aff = x_aff'*z_aff/n in the boundary point
+ x_aff' = x+alfa_aff_p*dx_aff, z_aff' = z+alfa_aff_d*dz_aff */
+ double sigma;
+ /* Mehrotra's heuristic parameter (0 <= sigma <= 1) */
+ double *dx_cc; /* double dx_cc[1+n]; */
+ double *dy_cc; /* double dy_cc[1+m]; */
+ double *dz_cc; /* double dz_cc[1+n]; */
+ /* centering corrector direction */
+ double *dx; /* double dx[1+n]; */
+ double *dy; /* double dy[1+m]; */
+ double *dz; /* double dz[1+n]; */
+ /* final combined direction dx = dx_aff+dx_cc, dy = dy_aff+dy_cc,
+ dz = dz_aff+dz_cc */
+ double alfa_max_p;
+ double alfa_max_d;
+ /* maximal primal and dual stepsizes in combined direction, on
+ which x and z are still non-negative */
+};
+
+/***********************************************************************
+* initialize - allocate and initialize common storage area
+*
+* This routine allocates and initializes the common storage area (CSA)
+* used by interior-point method routines. */
+
+static void initialize(struct csa *csa)
+{ int m = csa->m;
+ int n = csa->n;
+ int i;
+ if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Matrix A has %d non-zeros\n", csa->A_ptr[m+1]-1);
+ csa->D = xcalloc(1+n, sizeof(double));
+ /* P := I */
+ csa->P = xcalloc(1+m+m, sizeof(int));
+ for (i = 1; i <= m; i++) csa->P[i] = csa->P[m+i] = i;
+ /* S := A*A', symbolically */
+ csa->S_ptr = xcalloc(1+m+1, sizeof(int));
+ csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
+ csa->S_ptr);
+ if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Matrix S = A*A' has %d non-zeros (upper triangle)\n",
+ csa->S_ptr[m+1]-1 + m);
+ /* determine P using specified ordering algorithm */
+ if (csa->parm->ord_alg == GLP_ORD_NONE)
+ { if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Original ordering is being used\n");
+ for (i = 1; i <= m; i++)
+ csa->P[i] = csa->P[m+i] = i;
+ }
+ else if (csa->parm->ord_alg == GLP_ORD_QMD)
+ { if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Minimum degree ordering (QMD)...\n");
+ min_degree(m, csa->S_ptr, csa->S_ind, csa->P);
+ }
+ else if (csa->parm->ord_alg == GLP_ORD_AMD)
+ { if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Approximate minimum degree ordering (AMD)...\n");
+ amd_order1(m, csa->S_ptr, csa->S_ind, csa->P);
+ }
+ else if (csa->parm->ord_alg == GLP_ORD_SYMAMD)
+ { if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Approximate minimum degree ordering (SYMAMD)...\n")
+ ;
+ symamd_ord(m, csa->S_ptr, csa->S_ind, csa->P);
+ }
+ else
+ xassert(csa != csa);
+ /* S := P*A*A'*P', symbolically */
+ xfree(csa->S_ind);
+ csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
+ csa->S_ptr);
+ csa->S_val = xcalloc(csa->S_ptr[m+1], sizeof(double));
+ csa->S_diag = xcalloc(1+m, sizeof(double));
+ /* compute Cholesky factorization S = U'*U, symbolically */
+ if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Computing Cholesky factorization S = L*L'...\n");
+ csa->U_ptr = xcalloc(1+m+1, sizeof(int));
+ csa->U_ind = chol_symbolic(m, csa->S_ptr, csa->S_ind, csa->U_ptr);
+ if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Matrix L has %d non-zeros\n", csa->U_ptr[m+1]-1 + m);
+ csa->U_val = xcalloc(csa->U_ptr[m+1], sizeof(double));
+ csa->U_diag = xcalloc(1+m, sizeof(double));
+ csa->iter = 0;
+ csa->obj = 0.0;
+ csa->rpi = 0.0;
+ csa->rdi = 0.0;
+ csa->gap = 0.0;
+ csa->phi = 0.0;
+ csa->mu = 0.0;
+ csa->rmu = 0.0;
+ csa->rmu0 = 0.0;
+ csa->phi_min = xcalloc(1+ITER_MAX, sizeof(double));
+ csa->best_iter = 0;
+ csa->best_x = xcalloc(1+n, sizeof(double));
+ csa->best_y = xcalloc(1+m, sizeof(double));
+ csa->best_z = xcalloc(1+n, sizeof(double));
+ csa->best_obj = 0.0;
+ csa->dx_aff = xcalloc(1+n, sizeof(double));
+ csa->dy_aff = xcalloc(1+m, sizeof(double));
+ csa->dz_aff = xcalloc(1+n, sizeof(double));
+ csa->alfa_aff_p = 0.0;
+ csa->alfa_aff_d = 0.0;
+ csa->mu_aff = 0.0;
+ csa->sigma = 0.0;
+ csa->dx_cc = xcalloc(1+n, sizeof(double));
+ csa->dy_cc = xcalloc(1+m, sizeof(double));
+ csa->dz_cc = xcalloc(1+n, sizeof(double));
+ csa->dx = csa->dx_aff;
+ csa->dy = csa->dy_aff;
+ csa->dz = csa->dz_aff;
+ csa->alfa_max_p = 0.0;
+ csa->alfa_max_d = 0.0;
+ return;
+}
+
+/***********************************************************************
+* A_by_vec - compute y = A*x
+*
+* This routine computes matrix-vector product y = A*x, where A is the
+* constraint matrix. */
+
+static void A_by_vec(struct csa *csa, double x[], double y[])
+{ /* compute y = A*x */
+ int m = csa->m;
+ int *A_ptr = csa->A_ptr;
+ int *A_ind = csa->A_ind;
+ double *A_val = csa->A_val;
+ int i, t, beg, end;
+ double temp;
+ for (i = 1; i <= m; i++)
+ { temp = 0.0;
+ beg = A_ptr[i], end = A_ptr[i+1];
+ for (t = beg; t < end; t++) temp += A_val[t] * x[A_ind[t]];
+ y[i] = temp;
+ }
+ return;
+}
+
+/***********************************************************************
+* AT_by_vec - compute y = A'*x
+*
+* This routine computes matrix-vector product y = A'*x, where A' is a
+* matrix transposed to the constraint matrix A. */
+
+static void AT_by_vec(struct csa *csa, double x[], double y[])
+{ /* compute y = A'*x, where A' is transposed to A */
+ int m = csa->m;
+ int n = csa->n;
+ int *A_ptr = csa->A_ptr;
+ int *A_ind = csa->A_ind;
+ double *A_val = csa->A_val;
+ int i, j, t, beg, end;
+ double temp;
+ for (j = 1; j <= n; j++) y[j] = 0.0;
+ for (i = 1; i <= m; i++)
+ { temp = x[i];
+ if (temp == 0.0) continue;
+ beg = A_ptr[i], end = A_ptr[i+1];
+ for (t = beg; t < end; t++) y[A_ind[t]] += A_val[t] * temp;
+ }
+ return;
+}
+
+/***********************************************************************
+* decomp_NE - numeric factorization of matrix S = P*A*D*A'*P'
+*
+* This routine implements numeric phase of Cholesky factorization of
+* the matrix S = P*A*D*A'*P', which is a permuted matrix of the normal
+* equation system. Matrix D is assumed to be already computed. */
+
+static void decomp_NE(struct csa *csa)
+{ adat_numeric(csa->m, csa->n, csa->P, csa->A_ptr, csa->A_ind,
+ csa->A_val, csa->D, csa->S_ptr, csa->S_ind, csa->S_val,
+ csa->S_diag);
+ chol_numeric(csa->m, csa->S_ptr, csa->S_ind, csa->S_val,
+ csa->S_diag, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag);
+ return;
+}
+
+/***********************************************************************
+* solve_NE - solve normal equation system
+*
+* This routine solves the normal equation system:
+*
+* A*D*A'*y = h.
+*
+* It is assumed that the matrix A*D*A' has been previously factorized
+* by the routine decomp_NE.
+*
+* On entry the array y contains the vector of right-hand sides h. On
+* exit this array contains the computed vector of unknowns y.
+*
+* Once the vector y has been computed the routine checks for numeric
+* stability. If the residual vector:
+*
+* r = A*D*A'*y - h
+*
+* is relatively small, the routine returns zero, otherwise non-zero is
+* returned. */
+
+static int solve_NE(struct csa *csa, double y[])
+{ int m = csa->m;
+ int n = csa->n;
+ int *P = csa->P;
+ int i, j, ret = 0;
+ double *h, *r, *w;
+ /* save vector of right-hand sides h */
+ h = xcalloc(1+m, sizeof(double));
+ for (i = 1; i <= m; i++) h[i] = y[i];
+ /* solve normal equation system (A*D*A')*y = h */
+ /* since S = P*A*D*A'*P' = U'*U, then A*D*A' = P'*U'*U*P, so we
+ have inv(A*D*A') = P'*inv(U)*inv(U')*P */
+ /* w := P*h */
+ w = xcalloc(1+m, sizeof(double));
+ for (i = 1; i <= m; i++) w[i] = y[P[i]];
+ /* w := inv(U')*w */
+ ut_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
+ /* w := inv(U)*w */
+ u_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
+ /* y := P'*w */
+ for (i = 1; i <= m; i++) y[i] = w[P[m+i]];
+ xfree(w);
+ /* compute residual vector r = A*D*A'*y - h */
+ r = xcalloc(1+m, sizeof(double));
+ /* w := A'*y */
+ w = xcalloc(1+n, sizeof(double));
+ AT_by_vec(csa, y, w);
+ /* w := D*w */
+ for (j = 1; j <= n; j++) w[j] *= csa->D[j];
+ /* r := A*w */
+ A_by_vec(csa, w, r);
+ xfree(w);
+ /* r := r - h */
+ for (i = 1; i <= m; i++) r[i] -= h[i];
+ /* check for numeric stability */
+ for (i = 1; i <= m; i++)
+ { if (fabs(r[i]) / (1.0 + fabs(h[i])) > 1e-4)
+ { ret = 1;
+ break;
+ }
+ }
+ xfree(h);
+ xfree(r);
+ return ret;
+}
+
+/***********************************************************************
+* solve_NS - solve Newtonian system
+*
+* This routine solves the Newtonian system:
+*
+* A*dx = p
+*
+* A'*dy + dz = q
+*
+* Z*dx + X*dz = r
+*
+* where X = diag(x[j]), Z = diag(z[j]), by reducing it to the normal
+* equation system:
+*
+* (A*inv(Z)*X*A')*dy = A*inv(Z)*(X*q-r)+p
+*
+* (it is assumed that the matrix A*inv(Z)*X*A' has been factorized by
+* the routine decomp_NE).
+*
+* Once vector dy has been computed the routine computes vectors dx and
+* dz as follows:
+*
+* dx = inv(Z)*(X*(A'*dy-q)+r)
+*
+* dz = inv(X)*(r-Z*dx)
+*
+* The routine solve_NS returns the same code which was reported by the
+* routine solve_NE (see above). */
+
+static int solve_NS(struct csa *csa, double p[], double q[], double r[],
+ double dx[], double dy[], double dz[])
+{ int m = csa->m;
+ int n = csa->n;
+ double *x = csa->x;
+ double *z = csa->z;
+ int i, j, ret;
+ double *w = dx;
+ /* compute the vector of right-hand sides A*inv(Z)*(X*q-r)+p for
+ the normal equation system */
+ for (j = 1; j <= n; j++)
+ w[j] = (x[j] * q[j] - r[j]) / z[j];
+ A_by_vec(csa, w, dy);
+ for (i = 1; i <= m; i++) dy[i] += p[i];
+ /* solve the normal equation system to compute vector dy */
+ ret = solve_NE(csa, dy);
+ /* compute vectors dx and dz */
+ AT_by_vec(csa, dy, dx);
+ for (j = 1; j <= n; j++)
+ { dx[j] = (x[j] * (dx[j] - q[j]) + r[j]) / z[j];
+ dz[j] = (r[j] - z[j] * dx[j]) / x[j];
+ }
+ return ret;
+}
+
+/***********************************************************************
+* initial_point - choose initial point using Mehrotra's heuristic
+*
+* This routine chooses a starting point using a heuristic proposed in
+* the paper:
+*
+* S. Mehrotra. On the implementation of a primal-dual interior point
+* method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
+*
+* The starting point x in the primal space is chosen as a solution of
+* the following least squares problem:
+*
+* minimize ||x||
+*
+* subject to A*x = b
+*
+* which can be computed explicitly as follows:
+*
+* x = A'*inv(A*A')*b
+*
+* Similarly, the starting point (y, z) in the dual space is chosen as
+* a solution of the following least squares problem:
+*
+* minimize ||z||
+*
+* subject to A'*y + z = c
+*
+* which can be computed explicitly as follows:
+*
+* y = inv(A*A')*A*c
+*
+* z = c - A'*y
+*
+* However, some components of the vectors x and z may be non-positive
+* or close to zero, so the routine uses a Mehrotra's heuristic to find
+* a more appropriate starting point. */
+
+static void initial_point(struct csa *csa)
+{ int m = csa->m;
+ int n = csa->n;
+ double *b = csa->b;
+ double *c = csa->c;
+ double *x = csa->x;
+ double *y = csa->y;
+ double *z = csa->z;
+ double *D = csa->D;
+ int i, j;
+ double dp, dd, ex, ez, xz;
+ /* factorize A*A' */
+ for (j = 1; j <= n; j++) D[j] = 1.0;
+ decomp_NE(csa);
+ /* x~ = A'*inv(A*A')*b */
+ for (i = 1; i <= m; i++) y[i] = b[i];
+ solve_NE(csa, y);
+ AT_by_vec(csa, y, x);
+ /* y~ = inv(A*A')*A*c */
+ A_by_vec(csa, c, y);
+ solve_NE(csa, y);
+ /* z~ = c - A'*y~ */
+ AT_by_vec(csa, y,z);
+ for (j = 1; j <= n; j++) z[j] = c[j] - z[j];
+ /* use Mehrotra's heuristic in order to choose more appropriate
+ starting point with positive components of vectors x and z */
+ dp = dd = 0.0;
+ for (j = 1; j <= n; j++)
+ { if (dp < -1.5 * x[j]) dp = -1.5 * x[j];
+ if (dd < -1.5 * z[j]) dd = -1.5 * z[j];
+ }
+ /* note that b = 0 involves x = 0, and c = 0 involves y = 0 and
+ z = 0, so we need to be careful */
+ if (dp == 0.0) dp = 1.5;
+ if (dd == 0.0) dd = 1.5;
+ ex = ez = xz = 0.0;
+ for (j = 1; j <= n; j++)
+ { ex += (x[j] + dp);
+ ez += (z[j] + dd);
+ xz += (x[j] + dp) * (z[j] + dd);
+ }
+ dp += 0.5 * (xz / ez);
+ dd += 0.5 * (xz / ex);
+ for (j = 1; j <= n; j++)
+ { x[j] += dp;
+ z[j] += dd;
+ xassert(x[j] > 0.0 && z[j] > 0.0);
+ }
+ return;
+}
+
+/***********************************************************************
+* basic_info - perform basic computations at the current point
+*
+* This routine computes the following quantities at the current point:
+*
+* 1) value of the objective function:
+*
+* F = c'*x + c[0]
+*
+* 2) relative primal infeasibility:
+*
+* rpi = ||A*x-b|| / (1+||b||)
+*
+* 3) relative dual infeasibility:
+*
+* rdi = ||A'*y+z-c|| / (1+||c||)
+*
+* 4) primal-dual gap (relative difference between the primal and the
+* dual objective function values):
+*
+* gap = |c'*x-b'*y| / (1+|c'*x|)
+*
+* 5) merit function:
+*
+* phi = ||A*x-b|| / max(1,||b||) + ||A'*y+z-c|| / max(1,||c||) +
+*
+* + |c'*x-b'*y| / max(1,||b||,||c||)
+*
+* 6) duality measure:
+*
+* mu = x'*z / n
+*
+* 7) the ratio of infeasibility to mu:
+*
+* rmu = max(||A*x-b||,||A'*y+z-c||) / mu
+*
+* where ||*|| denotes euclidian norm, *' denotes transposition. */
+
+static void basic_info(struct csa *csa)
+{ int m = csa->m;
+ int n = csa->n;
+ double *b = csa->b;
+ double *c = csa->c;
+ double *x = csa->x;
+ double *y = csa->y;
+ double *z = csa->z;
+ int i, j;
+ double norm1, bnorm, norm2, cnorm, cx, by, *work, temp;
+ /* compute value of the objective function */
+ temp = c[0];
+ for (j = 1; j <= n; j++) temp += c[j] * x[j];
+ csa->obj = temp;
+ /* norm1 = ||A*x-b|| */
+ work = xcalloc(1+m, sizeof(double));
+ A_by_vec(csa, x, work);
+ norm1 = 0.0;
+ for (i = 1; i <= m; i++)
+ norm1 += (work[i] - b[i]) * (work[i] - b[i]);
+ norm1 = sqrt(norm1);
+ xfree(work);
+ /* bnorm = ||b|| */
+ bnorm = 0.0;
+ for (i = 1; i <= m; i++) bnorm += b[i] * b[i];
+ bnorm = sqrt(bnorm);
+ /* compute relative primal infeasibility */
+ csa->rpi = norm1 / (1.0 + bnorm);
+ /* norm2 = ||A'*y+z-c|| */
+ work = xcalloc(1+n, sizeof(double));
+ AT_by_vec(csa, y, work);
+ norm2 = 0.0;
+ for (j = 1; j <= n; j++)
+ norm2 += (work[j] + z[j] - c[j]) * (work[j] + z[j] - c[j]);
+ norm2 = sqrt(norm2);
+ xfree(work);
+ /* cnorm = ||c|| */
+ cnorm = 0.0;
+ for (j = 1; j <= n; j++) cnorm += c[j] * c[j];
+ cnorm = sqrt(cnorm);
+ /* compute relative dual infeasibility */
+ csa->rdi = norm2 / (1.0 + cnorm);
+ /* by = b'*y */
+ by = 0.0;
+ for (i = 1; i <= m; i++) by += b[i] * y[i];
+ /* cx = c'*x */
+ cx = 0.0;
+ for (j = 1; j <= n; j++) cx += c[j] * x[j];
+ /* compute primal-dual gap */
+ csa->gap = fabs(cx - by) / (1.0 + fabs(cx));
+ /* compute merit function */
+ csa->phi = 0.0;
+ csa->phi += norm1 / (bnorm > 1.0 ? bnorm : 1.0);
+ csa->phi += norm2 / (cnorm > 1.0 ? cnorm : 1.0);
+ temp = 1.0;
+ if (temp < bnorm) temp = bnorm;
+ if (temp < cnorm) temp = cnorm;
+ csa->phi += fabs(cx - by) / temp;
+ /* compute duality measure */
+ temp = 0.0;
+ for (j = 1; j <= n; j++) temp += x[j] * z[j];
+ csa->mu = temp / (double)n;
+ /* compute the ratio of infeasibility to mu */
+ csa->rmu = (norm1 > norm2 ? norm1 : norm2) / csa->mu;
+ return;
+}
+
+/***********************************************************************
+* make_step - compute next point using Mehrotra's technique
+*
+* This routine computes the next point using the predictor-corrector
+* technique proposed in the paper:
+*
+* S. Mehrotra. On the implementation of a primal-dual interior point
+* method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
+*
+* At first, the routine computes so called affine scaling (predictor)
+* direction (dx_aff,dy_aff,dz_aff) which is a solution of the system:
+*
+* A*dx_aff = b - A*x
+*
+* A'*dy_aff + dz_aff = c - A'*y - z
+*
+* Z*dx_aff + X*dz_aff = - X*Z*e
+*
+* where (x,y,z) is the current point, X = diag(x[j]), Z = diag(z[j]),
+* e = (1,...,1)'.
+*
+* Then, the routine computes the centering parameter sigma, using the
+* following Mehrotra's heuristic:
+*
+* alfa_aff_p = inf{0 <= alfa <= 1 | x+alfa*dx_aff >= 0}
+*
+* alfa_aff_d = inf{0 <= alfa <= 1 | z+alfa*dz_aff >= 0}
+*
+* mu_aff = (x+alfa_aff_p*dx_aff)'*(z+alfa_aff_d*dz_aff)/n
+*
+* sigma = (mu_aff/mu)^3
+*
+* where alfa_aff_p is the maximal stepsize along the affine scaling
+* direction in the primal space, alfa_aff_d is the maximal stepsize
+* along the same direction in the dual space.
+*
+* After determining sigma the routine computes so called centering
+* (corrector) direction (dx_cc,dy_cc,dz_cc) which is the solution of
+* the system:
+*
+* A*dx_cc = 0
+*
+* A'*dy_cc + dz_cc = 0
+*
+* Z*dx_cc + X*dz_cc = sigma*mu*e - X*Z*e
+*
+* Finally, the routine computes the combined direction
+*
+* (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc)
+*
+* and determines maximal primal and dual stepsizes along the combined
+* direction:
+*
+* alfa_max_p = inf{0 <= alfa <= 1 | x+alfa*dx >= 0}
+*
+* alfa_max_d = inf{0 <= alfa <= 1 | z+alfa*dz >= 0}
+*
+* In order to prevent the next point to be too close to the boundary
+* of the positive ortant, the routine decreases maximal stepsizes:
+*
+* alfa_p = gamma_p * alfa_max_p
+*
+* alfa_d = gamma_d * alfa_max_d
+*
+* where gamma_p and gamma_d are scaling factors, and computes the next
+* point:
+*
+* x_new = x + alfa_p * dx
+*
+* y_new = y + alfa_d * dy
+*
+* z_new = z + alfa_d * dz
+*
+* which becomes the current point on the next iteration. */
+
+static int make_step(struct csa *csa)
+{ int m = csa->m;
+ int n = csa->n;
+ double *b = csa->b;
+ double *c = csa->c;
+ double *x = csa->x;
+ double *y = csa->y;
+ double *z = csa->z;
+ double *dx_aff = csa->dx_aff;
+ double *dy_aff = csa->dy_aff;
+ double *dz_aff = csa->dz_aff;
+ double *dx_cc = csa->dx_cc;
+ double *dy_cc = csa->dy_cc;
+ double *dz_cc = csa->dz_cc;
+ double *dx = csa->dx;
+ double *dy = csa->dy;
+ double *dz = csa->dz;
+ int i, j, ret = 0;
+ double temp, gamma_p, gamma_d, *p, *q, *r;
+ /* allocate working arrays */
+ p = xcalloc(1+m, sizeof(double));
+ q = xcalloc(1+n, sizeof(double));
+ r = xcalloc(1+n, sizeof(double));
+ /* p = b - A*x */
+ A_by_vec(csa, x, p);
+ for (i = 1; i <= m; i++) p[i] = b[i] - p[i];
+ /* q = c - A'*y - z */
+ AT_by_vec(csa, y,q);
+ for (j = 1; j <= n; j++) q[j] = c[j] - q[j] - z[j];
+ /* r = - X * Z * e */
+ for (j = 1; j <= n; j++) r[j] = - x[j] * z[j];
+ /* solve the first Newtonian system */
+ if (solve_NS(csa, p, q, r, dx_aff, dy_aff, dz_aff))
+ { ret = 1;
+ goto done;
+ }
+ /* alfa_aff_p = inf{0 <= alfa <= 1 | x + alfa*dx_aff >= 0} */
+ /* alfa_aff_d = inf{0 <= alfa <= 1 | z + alfa*dz_aff >= 0} */
+ csa->alfa_aff_p = csa->alfa_aff_d = 1.0;
+ for (j = 1; j <= n; j++)
+ { if (dx_aff[j] < 0.0)
+ { temp = - x[j] / dx_aff[j];
+ if (csa->alfa_aff_p > temp) csa->alfa_aff_p = temp;
+ }
+ if (dz_aff[j] < 0.0)
+ { temp = - z[j] / dz_aff[j];
+ if (csa->alfa_aff_d > temp) csa->alfa_aff_d = temp;
+ }
+ }
+ /* mu_aff = (x+alfa_aff_p*dx_aff)' * (z+alfa_aff_d*dz_aff) / n */
+ temp = 0.0;
+ for (j = 1; j <= n; j++)
+ temp += (x[j] + csa->alfa_aff_p * dx_aff[j]) *
+ (z[j] + csa->alfa_aff_d * dz_aff[j]);
+ csa->mu_aff = temp / (double)n;
+ /* sigma = (mu_aff/mu)^3 */
+ temp = csa->mu_aff / csa->mu;
+ csa->sigma = temp * temp * temp;
+ /* p = 0 */
+ for (i = 1; i <= m; i++) p[i] = 0.0;
+ /* q = 0 */
+ for (j = 1; j <= n; j++) q[j] = 0.0;
+ /* r = sigma * mu * e - X * Z * e */
+ for (j = 1; j <= n; j++)
+ r[j] = csa->sigma * csa->mu - dx_aff[j] * dz_aff[j];
+ /* solve the second Newtonian system with the same coefficients
+ but with altered right-hand sides */
+ if (solve_NS(csa, p, q, r, dx_cc, dy_cc, dz_cc))
+ { ret = 1;
+ goto done;
+ }
+ /* (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc) */
+ for (j = 1; j <= n; j++) dx[j] = dx_aff[j] + dx_cc[j];
+ for (i = 1; i <= m; i++) dy[i] = dy_aff[i] + dy_cc[i];
+ for (j = 1; j <= n; j++) dz[j] = dz_aff[j] + dz_cc[j];
+ /* alfa_max_p = inf{0 <= alfa <= 1 | x + alfa*dx >= 0} */
+ /* alfa_max_d = inf{0 <= alfa <= 1 | z + alfa*dz >= 0} */
+ csa->alfa_max_p = csa->alfa_max_d = 1.0;
+ for (j = 1; j <= n; j++)
+ { if (dx[j] < 0.0)
+ { temp = - x[j] / dx[j];
+ if (csa->alfa_max_p > temp) csa->alfa_max_p = temp;
+ }
+ if (dz[j] < 0.0)
+ { temp = - z[j] / dz[j];
+ if (csa->alfa_max_d > temp) csa->alfa_max_d = temp;
+ }
+ }
+ /* determine scale factors (not implemented yet) */
+ gamma_p = 0.90;
+ gamma_d = 0.90;
+ /* compute the next point */
+ for (j = 1; j <= n; j++)
+ { x[j] += gamma_p * csa->alfa_max_p * dx[j];
+ xassert(x[j] > 0.0);
+ }
+ for (i = 1; i <= m; i++)
+ y[i] += gamma_d * csa->alfa_max_d * dy[i];
+ for (j = 1; j <= n; j++)
+ { z[j] += gamma_d * csa->alfa_max_d * dz[j];
+ xassert(z[j] > 0.0);
+ }
+done: /* free working arrays */
+ xfree(p);
+ xfree(q);
+ xfree(r);
+ return ret;
+}
+
+/***********************************************************************
+* terminate - deallocate common storage area
+*
+* This routine frees all memory allocated to the common storage area
+* used by interior-point method routines. */
+
+static void terminate(struct csa *csa)
+{ xfree(csa->D);
+ xfree(csa->P);
+ xfree(csa->S_ptr);
+ xfree(csa->S_ind);
+ xfree(csa->S_val);
+ xfree(csa->S_diag);
+ xfree(csa->U_ptr);
+ xfree(csa->U_ind);
+ xfree(csa->U_val);
+ xfree(csa->U_diag);
+ xfree(csa->phi_min);
+ xfree(csa->best_x);
+ xfree(csa->best_y);
+ xfree(csa->best_z);
+ xfree(csa->dx_aff);
+ xfree(csa->dy_aff);
+ xfree(csa->dz_aff);
+ xfree(csa->dx_cc);
+ xfree(csa->dy_cc);
+ xfree(csa->dz_cc);
+ return;
+}
+
+/***********************************************************************
+* ipm_main - main interior-point method routine
+*
+* This is a main routine of the primal-dual interior-point method.
+*
+* The routine ipm_main returns one of the following codes:
+*
+* 0 - optimal solution found;
+* 1 - problem has no feasible (primal or dual) solution;
+* 2 - no convergence;
+* 3 - iteration limit exceeded;
+* 4 - numeric instability on solving Newtonian system.
+*
+* In case of non-zero return code the routine returns the best point,
+* which has been reached during optimization. */
+
+static int ipm_main(struct csa *csa)
+{ int m = csa->m;
+ int n = csa->n;
+ int i, j, status;
+ double temp;
+ /* choose initial point using Mehrotra's heuristic */
+ if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Guessing initial point...\n");
+ initial_point(csa);
+ /* main loop starts here */
+ if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Optimization begins...\n");
+ for (;;)
+ { /* perform basic computations at the current point */
+ basic_info(csa);
+ /* save initial value of rmu */
+ if (csa->iter == 0) csa->rmu0 = csa->rmu;
+ /* accumulate values of min(phi[k]) and save the best point */
+ xassert(csa->iter <= ITER_MAX);
+ if (csa->iter == 0 || csa->phi_min[csa->iter-1] > csa->phi)
+ { csa->phi_min[csa->iter] = csa->phi;
+ csa->best_iter = csa->iter;
+ for (j = 1; j <= n; j++) csa->best_x[j] = csa->x[j];
+ for (i = 1; i <= m; i++) csa->best_y[i] = csa->y[i];
+ for (j = 1; j <= n; j++) csa->best_z[j] = csa->z[j];
+ csa->best_obj = csa->obj;
+ }
+ else
+ csa->phi_min[csa->iter] = csa->phi_min[csa->iter-1];
+ /* display information at the current point */
+ if (csa->parm->msg_lev >= GLP_MSG_ON)
+ xprintf("%3d: obj = %17.9e; rpi = %8.1e; rdi = %8.1e; gap ="
+ " %8.1e\n", csa->iter, csa->obj, csa->rpi, csa->rdi,
+ csa->gap);
+ /* check if the current point is optimal */
+ if (csa->rpi < 1e-8 && csa->rdi < 1e-8 && csa->gap < 1e-8)
+ { if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("OPTIMAL SOLUTION FOUND\n");
+ status = 0;
+ break;
+ }
+ /* check if the problem has no feasible solution */
+ temp = 1e5 * csa->phi_min[csa->iter];
+ if (temp < 1e-8) temp = 1e-8;
+ if (csa->phi >= temp)
+ { if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("PROBLEM HAS NO FEASIBLE PRIMAL/DUAL SOLUTION\n")
+ ;
+ status = 1;
+ break;
+ }
+ /* check for very slow convergence or divergence */
+ if (((csa->rpi >= 1e-8 || csa->rdi >= 1e-8) && csa->rmu /
+ csa->rmu0 >= 1e6) ||
+ (csa->iter >= 30 && csa->phi_min[csa->iter] >= 0.5 *
+ csa->phi_min[csa->iter - 30]))
+ { if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("NO CONVERGENCE; SEARCH TERMINATED\n");
+ status = 2;
+ break;
+ }
+ /* check for maximal number of iterations */
+ if (csa->iter == ITER_MAX)
+ { if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
+ status = 3;
+ break;
+ }
+ /* start the next iteration */
+ csa->iter++;
+ /* factorize normal equation system */
+ for (j = 1; j <= n; j++) csa->D[j] = csa->x[j] / csa->z[j];
+ decomp_NE(csa);
+ /* compute the next point using Mehrotra's predictor-corrector
+ technique */
+ if (make_step(csa))
+ { if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("NUMERIC INSTABILITY; SEARCH TERMINATED\n");
+ status = 4;
+ break;
+ }
+ }
+ /* restore the best point */
+ if (status != 0)
+ { for (j = 1; j <= n; j++) csa->x[j] = csa->best_x[j];
+ for (i = 1; i <= m; i++) csa->y[i] = csa->best_y[i];
+ for (j = 1; j <= n; j++) csa->z[j] = csa->best_z[j];
+ if (csa->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Best point %17.9e was reached on iteration %d\n",
+ csa->best_obj, csa->best_iter);
+ }
+ /* return to the calling program */
+ return status;
+}
+
+/***********************************************************************
+* NAME
+*
+* ipm_solve - core LP solver based on the interior-point method
+*
+* SYNOPSIS
+*
+* #include "glpipm.h"
+* int ipm_solve(glp_prob *P, const glp_iptcp *parm);
+*
+* DESCRIPTION
+*
+* The routine ipm_solve is a core LP solver based on the primal-dual
+* interior-point method.
+*
+* The routine assumes the following standard formulation of LP problem
+* to be solved:
+*
+* minimize
+*
+* F = c[0] + c[1]*x[1] + c[2]*x[2] + ... + c[n]*x[n]
+*
+* subject to linear constraints
+*
+* a[1,1]*x[1] + a[1,2]*x[2] + ... + a[1,n]*x[n] = b[1]
+*
+* a[2,1]*x[1] + a[2,2]*x[2] + ... + a[2,n]*x[n] = b[2]
+*
+* . . . . . .
+*
+* a[m,1]*x[1] + a[m,2]*x[2] + ... + a[m,n]*x[n] = b[m]
+*
+* and non-negative variables
+*
+* x[1] >= 0, x[2] >= 0, ..., x[n] >= 0
+*
+* where:
+* F is the objective function;
+* x[1], ..., x[n] are (structural) variables;
+* c[0] is a constant term of the objective function;
+* c[1], ..., c[n] are objective coefficients;
+* a[1,1], ..., a[m,n] are constraint coefficients;
+* b[1], ..., b[n] are right-hand sides.
+*
+* The solution is three vectors x, y, and z, which are stored by the
+* routine in the arrays x, y, and z, respectively. These vectors
+* correspond to the best primal-dual point found during optimization.
+* They are approximate solution of the following system (which is the
+* Karush-Kuhn-Tucker optimality conditions):
+*
+* A*x = b (primal feasibility condition)
+*
+* A'*y + z = c (dual feasibility condition)
+*
+* x'*z = 0 (primal-dual complementarity condition)
+*
+* x >= 0, z >= 0 (non-negativity condition)
+*
+* where:
+* x[1], ..., x[n] are primal (structural) variables;
+* y[1], ..., y[m] are dual variables (Lagrange multipliers) for
+* equality constraints;
+* z[1], ..., z[n] are dual variables (Lagrange multipliers) for
+* non-negativity constraints.
+*
+* RETURNS
+*
+* 0 LP has been successfully solved.
+*
+* GLP_ENOCVG
+* No convergence.
+*
+* GLP_EITLIM
+* Iteration limit exceeded.
+*
+* GLP_EINSTAB
+* Numeric instability on solving Newtonian system.
+*
+* In case of non-zero return code the routine returns the best point,
+* which has been reached during optimization. */
+
+int ipm_solve(glp_prob *P, const glp_iptcp *parm)
+{ struct csa _dsa, *csa = &_dsa;
+ int m = P->m;
+ int n = P->n;
+ int nnz = P->nnz;
+ GLPROW *row;
+ GLPCOL *col;
+ GLPAIJ *aij;
+ int i, j, loc, ret, *A_ind, *A_ptr;
+ double dir, *A_val, *b, *c, *x, *y, *z;
+ xassert(m > 0);
+ xassert(n > 0);
+ /* allocate working arrays */
+ A_ptr = xcalloc(1+m+1, sizeof(int));
+ A_ind = xcalloc(1+nnz, sizeof(int));
+ A_val = xcalloc(1+nnz, sizeof(double));
+ b = xcalloc(1+m, sizeof(double));
+ c = xcalloc(1+n, sizeof(double));
+ x = xcalloc(1+n, sizeof(double));
+ y = xcalloc(1+m, sizeof(double));
+ z = xcalloc(1+n, sizeof(double));
+ /* prepare rows and constraint coefficients */
+ loc = 1;
+ for (i = 1; i <= m; i++)
+ { row = P->row[i];
+ xassert(row->type == GLP_FX);
+ b[i] = row->lb * row->rii;
+ A_ptr[i] = loc;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { A_ind[loc] = aij->col->j;
+ A_val[loc] = row->rii * aij->val * aij->col->sjj;
+ loc++;
+ }
+ }
+ A_ptr[m+1] = loc;
+ xassert(loc-1 == nnz);
+ /* prepare columns and objective coefficients */
+ if (P->dir == GLP_MIN)
+ dir = +1.0;
+ else if (P->dir == GLP_MAX)
+ dir = -1.0;
+ else
+ xassert(P != P);
+ c[0] = dir * P->c0;
+ for (j = 1; j <= n; j++)
+ { col = P->col[j];
+ xassert(col->type == GLP_LO && col->lb == 0.0);
+ c[j] = dir * col->coef * col->sjj;
+ }
+ /* allocate and initialize the common storage area */
+ csa->m = m;
+ csa->n = n;
+ csa->A_ptr = A_ptr;
+ csa->A_ind = A_ind;
+ csa->A_val = A_val;
+ csa->b = b;
+ csa->c = c;
+ csa->x = x;
+ csa->y = y;
+ csa->z = z;
+ csa->parm = parm;
+ initialize(csa);
+ /* solve LP with the interior-point method */
+ ret = ipm_main(csa);
+ /* deallocate the common storage area */
+ terminate(csa);
+ /* determine solution status */
+ if (ret == 0)
+ { /* optimal solution found */
+ P->ipt_stat = GLP_OPT;
+ ret = 0;
+ }
+ else if (ret == 1)
+ { /* problem has no feasible (primal or dual) solution */
+ P->ipt_stat = GLP_NOFEAS;
+ ret = 0;
+ }
+ else if (ret == 2)
+ { /* no convergence */
+ P->ipt_stat = GLP_INFEAS;
+ ret = GLP_ENOCVG;
+ }
+ else if (ret == 3)
+ { /* iteration limit exceeded */
+ P->ipt_stat = GLP_INFEAS;
+ ret = GLP_EITLIM;
+ }
+ else if (ret == 4)
+ { /* numeric instability on solving Newtonian system */
+ P->ipt_stat = GLP_INFEAS;
+ ret = GLP_EINSTAB;
+ }
+ else
+ xassert(ret != ret);
+ /* store row solution components */
+ for (i = 1; i <= m; i++)
+ { row = P->row[i];
+ row->pval = row->lb;
+ row->dval = dir * y[i] * row->rii;
+ }
+ /* store column solution components */
+ P->ipt_obj = P->c0;
+ for (j = 1; j <= n; j++)
+ { col = P->col[j];
+ col->pval = x[j] * col->sjj;
+ col->dval = dir * z[j] / col->sjj;
+ P->ipt_obj += col->coef * col->pval;
+ }
+ /* free working arrays */
+ xfree(A_ptr);
+ xfree(A_ind);
+ xfree(A_val);
+ xfree(b);
+ xfree(c);
+ xfree(x);
+ xfree(y);
+ xfree(z);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpipm.h b/test/monniaux/glpk-4.65/src/draft/glpipm.h
new file mode 100644
index 00000000..a5f94fec
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpipm.h
@@ -0,0 +1,36 @@
+/* glpipm.h (primal-dual interior-point method) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#ifndef GLPIPM_H
+#define GLPIPM_H
+
+#include "prob.h"
+
+#define ipm_solve _glp_ipm_solve
+int ipm_solve(glp_prob *P, const glp_iptcp *parm);
+/* core LP solver based on the interior-point method */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpmat.c b/test/monniaux/glpk-4.65/src/draft/glpmat.c
new file mode 100644
index 00000000..97d1c651
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpmat.c
@@ -0,0 +1,924 @@
+/* glpmat.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpmat.h"
+#include "qmd.h"
+#include "amd.h"
+#include "colamd.h"
+
+/*----------------------------------------------------------------------
+-- check_fvs - check sparse vector in full-vector storage format.
+--
+-- SYNOPSIS
+--
+-- #include "glpmat.h"
+-- int check_fvs(int n, int nnz, int ind[], double vec[]);
+--
+-- DESCRIPTION
+--
+-- The routine check_fvs checks if a given vector of dimension n in
+-- full-vector storage format has correct representation.
+--
+-- RETURNS
+--
+-- The routine returns one of the following codes:
+--
+-- 0 - the vector is correct;
+-- 1 - the number of elements (n) is negative;
+-- 2 - the number of non-zero elements (nnz) is negative;
+-- 3 - some element index is out of range;
+-- 4 - some element index is duplicate;
+-- 5 - some non-zero element is out of pattern. */
+
+int check_fvs(int n, int nnz, int ind[], double vec[])
+{ int i, t, ret, *flag = NULL;
+ /* check the number of elements */
+ if (n < 0)
+ { ret = 1;
+ goto done;
+ }
+ /* check the number of non-zero elements */
+ if (nnz < 0)
+ { ret = 2;
+ goto done;
+ }
+ /* check vector indices */
+ flag = xcalloc(1+n, sizeof(int));
+ for (i = 1; i <= n; i++) flag[i] = 0;
+ for (t = 1; t <= nnz; t++)
+ { i = ind[t];
+ if (!(1 <= i && i <= n))
+ { ret = 3;
+ goto done;
+ }
+ if (flag[i])
+ { ret = 4;
+ goto done;
+ }
+ flag[i] = 1;
+ }
+ /* check vector elements */
+ for (i = 1; i <= n; i++)
+ { if (!flag[i] && vec[i] != 0.0)
+ { ret = 5;
+ goto done;
+ }
+ }
+ /* the vector is ok */
+ ret = 0;
+done: if (flag != NULL) xfree(flag);
+ return ret;
+}
+
+/*----------------------------------------------------------------------
+-- check_pattern - check pattern of sparse matrix.
+--
+-- SYNOPSIS
+--
+-- #include "glpmat.h"
+-- int check_pattern(int m, int n, int A_ptr[], int A_ind[]);
+--
+-- DESCRIPTION
+--
+-- The routine check_pattern checks the pattern of a given mxn matrix
+-- in storage-by-rows format.
+--
+-- RETURNS
+--
+-- The routine returns one of the following codes:
+--
+-- 0 - the pattern is correct;
+-- 1 - the number of rows (m) is negative;
+-- 2 - the number of columns (n) is negative;
+-- 3 - A_ptr[1] is not 1;
+-- 4 - some column index is out of range;
+-- 5 - some column indices are duplicate. */
+
+int check_pattern(int m, int n, int A_ptr[], int A_ind[])
+{ int i, j, ptr, ret, *flag = NULL;
+ /* check the number of rows */
+ if (m < 0)
+ { ret = 1;
+ goto done;
+ }
+ /* check the number of columns */
+ if (n < 0)
+ { ret = 2;
+ goto done;
+ }
+ /* check location A_ptr[1] */
+ if (A_ptr[1] != 1)
+ { ret = 3;
+ goto done;
+ }
+ /* check row patterns */
+ flag = xcalloc(1+n, sizeof(int));
+ for (j = 1; j <= n; j++) flag[j] = 0;
+ for (i = 1; i <= m; i++)
+ { /* check pattern of row i */
+ for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++)
+ { j = A_ind[ptr];
+ /* check column index */
+ if (!(1 <= j && j <= n))
+ { ret = 4;
+ goto done;
+ }
+ /* check for duplication */
+ if (flag[j])
+ { ret = 5;
+ goto done;
+ }
+ flag[j] = 1;
+ }
+ /* clear flags */
+ for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++)
+ { j = A_ind[ptr];
+ flag[j] = 0;
+ }
+ }
+ /* the pattern is ok */
+ ret = 0;
+done: if (flag != NULL) xfree(flag);
+ return ret;
+}
+
+/*----------------------------------------------------------------------
+-- transpose - transpose sparse matrix.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void transpose(int m, int n, int A_ptr[], int A_ind[],
+-- double A_val[], int AT_ptr[], int AT_ind[], double AT_val[]);
+--
+-- *Description*
+--
+-- For a given mxn sparse matrix A the routine transpose builds a nxm
+-- sparse matrix A' which is a matrix transposed to A.
+--
+-- The arrays A_ptr, A_ind, and A_val specify a given mxn matrix A to
+-- be transposed in storage-by-rows format. The parameter A_val can be
+-- NULL, in which case numeric values are not copied. The arrays A_ptr,
+-- A_ind, and A_val are not changed on exit.
+--
+-- On entry the arrays AT_ptr, AT_ind, and AT_val must be allocated,
+-- but their content is ignored. On exit the routine stores a resultant
+-- nxm matrix A' in these arrays in storage-by-rows format. Note that
+-- if the parameter A_val is NULL, the array AT_val is not used.
+--
+-- The routine transpose has a side effect that elements in rows of the
+-- resultant matrix A' follow in ascending their column indices. */
+
+void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[],
+ int AT_ptr[], int AT_ind[], double AT_val[])
+{ int i, j, t, beg, end, pos, len;
+ /* determine row lengths of resultant matrix */
+ for (j = 1; j <= n; j++) AT_ptr[j] = 0;
+ for (i = 1; i <= m; i++)
+ { beg = A_ptr[i], end = A_ptr[i+1];
+ for (t = beg; t < end; t++) AT_ptr[A_ind[t]]++;
+ }
+ /* set up row pointers of resultant matrix */
+ pos = 1;
+ for (j = 1; j <= n; j++)
+ len = AT_ptr[j], pos += len, AT_ptr[j] = pos;
+ AT_ptr[n+1] = pos;
+ /* build resultant matrix */
+ for (i = m; i >= 1; i--)
+ { beg = A_ptr[i], end = A_ptr[i+1];
+ for (t = beg; t < end; t++)
+ { pos = --AT_ptr[A_ind[t]];
+ AT_ind[pos] = i;
+ if (A_val != NULL) AT_val[pos] = A_val[t];
+ }
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- adat_symbolic - compute S = P*A*D*A'*P' (symbolic phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- int *adat_symbolic(int m, int n, int P_per[], int A_ptr[],
+-- int A_ind[], int S_ptr[]);
+--
+-- *Description*
+--
+-- The routine adat_symbolic implements the symbolic phase to compute
+-- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix,
+-- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix
+-- transposed to A, P' is an inverse of P.
+--
+-- The parameter m is the number of rows in A and the order of P.
+--
+-- The parameter n is the number of columns in A and the order of D.
+--
+-- The array P_per specifies permutation matrix P. It is not changed on
+-- exit.
+--
+-- The arrays A_ptr and A_ind specify the pattern of matrix A. They are
+-- not changed on exit.
+--
+-- On exit the routine stores the pattern of upper triangular part of
+-- matrix S without diagonal elements in the arrays S_ptr and S_ind in
+-- storage-by-rows format. The array S_ptr should be allocated on entry,
+-- however, its content is ignored. The array S_ind is allocated by the
+-- routine itself which returns a pointer to it.
+--
+-- *Returns*
+--
+-- The routine returns a pointer to the array S_ind. */
+
+int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[],
+ int S_ptr[])
+{ int i, j, t, ii, jj, tt, k, size, len;
+ int *S_ind, *AT_ptr, *AT_ind, *ind, *map, *temp;
+ /* build the pattern of A', which is a matrix transposed to A, to
+ efficiently access A in column-wise manner */
+ AT_ptr = xcalloc(1+n+1, sizeof(int));
+ AT_ind = xcalloc(A_ptr[m+1], sizeof(int));
+ transpose(m, n, A_ptr, A_ind, NULL, AT_ptr, AT_ind, NULL);
+ /* allocate the array S_ind */
+ size = A_ptr[m+1] - 1;
+ if (size < m) size = m;
+ S_ind = xcalloc(1+size, sizeof(int));
+ /* allocate and initialize working arrays */
+ ind = xcalloc(1+m, sizeof(int));
+ map = xcalloc(1+m, sizeof(int));
+ for (jj = 1; jj <= m; jj++) map[jj] = 0;
+ /* compute pattern of S; note that symbolically S = B*B', where
+ B = P*A, B' is matrix transposed to B */
+ S_ptr[1] = 1;
+ for (ii = 1; ii <= m; ii++)
+ { /* compute pattern of ii-th row of S */
+ len = 0;
+ i = P_per[ii]; /* i-th row of A = ii-th row of B */
+ for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
+ { k = A_ind[t];
+ /* walk through k-th column of A */
+ for (tt = AT_ptr[k]; tt < AT_ptr[k+1]; tt++)
+ { j = AT_ind[tt];
+ jj = P_per[m+j]; /* j-th row of A = jj-th row of B */
+ /* a[i,k] != 0 and a[j,k] != 0 ergo s[ii,jj] != 0 */
+ if (ii < jj && !map[jj]) ind[++len] = jj, map[jj] = 1;
+ }
+ }
+ /* now (ind) is pattern of ii-th row of S */
+ S_ptr[ii+1] = S_ptr[ii] + len;
+ /* at least (S_ptr[ii+1] - 1) locations should be available in
+ the array S_ind */
+ if (S_ptr[ii+1] - 1 > size)
+ { temp = S_ind;
+ size += size;
+ S_ind = xcalloc(1+size, sizeof(int));
+ memcpy(&S_ind[1], &temp[1], (S_ptr[ii] - 1) * sizeof(int));
+ xfree(temp);
+ }
+ xassert(S_ptr[ii+1] - 1 <= size);
+ /* (ii-th row of S) := (ind) */
+ memcpy(&S_ind[S_ptr[ii]], &ind[1], len * sizeof(int));
+ /* clear the row pattern map */
+ for (t = 1; t <= len; t++) map[ind[t]] = 0;
+ }
+ /* free working arrays */
+ xfree(AT_ptr);
+ xfree(AT_ind);
+ xfree(ind);
+ xfree(map);
+ /* reallocate the array S_ind to free unused locations */
+ temp = S_ind;
+ size = S_ptr[m+1] - 1;
+ S_ind = xcalloc(1+size, sizeof(int));
+ memcpy(&S_ind[1], &temp[1], size * sizeof(int));
+ xfree(temp);
+ return S_ind;
+}
+
+/*----------------------------------------------------------------------
+-- adat_numeric - compute S = P*A*D*A'*P' (numeric phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void adat_numeric(int m, int n, int P_per[],
+-- int A_ptr[], int A_ind[], double A_val[], double D_diag[],
+-- int S_ptr[], int S_ind[], double S_val[], double S_diag[]);
+--
+-- *Description*
+--
+-- The routine adat_numeric implements the numeric phase to compute
+-- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix,
+-- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix
+-- transposed to A, P' is an inverse of P.
+--
+-- The parameter m is the number of rows in A and the order of P.
+--
+-- The parameter n is the number of columns in A and the order of D.
+--
+-- The matrix P is specified in the array P_per, which is not changed
+-- on exit.
+--
+-- The matrix A is specified in the arrays A_ptr, A_ind, and A_val in
+-- storage-by-rows format. These arrays are not changed on exit.
+--
+-- Diagonal elements of the matrix D are specified in the array D_diag,
+-- where D_diag[0] is not used, D_diag[i] = d[i,i] for i = 1, ..., n.
+-- The array D_diag is not changed on exit.
+--
+-- The pattern of the upper triangular part of the matrix S without
+-- diagonal elements (previously computed by the routine adat_symbolic)
+-- is specified in the arrays S_ptr and S_ind, which are not changed on
+-- exit. Numeric values of non-diagonal elements of S are stored in
+-- corresponding locations of the array S_val, and values of diagonal
+-- elements of S are stored in locations S_diag[1], ..., S_diag[n]. */
+
+void adat_numeric(int m, int n, int P_per[],
+ int A_ptr[], int A_ind[], double A_val[], double D_diag[],
+ int S_ptr[], int S_ind[], double S_val[], double S_diag[])
+{ int i, j, t, ii, jj, tt, beg, end, beg1, end1, k;
+ double sum, *work;
+ work = xcalloc(1+n, sizeof(double));
+ for (j = 1; j <= n; j++) work[j] = 0.0;
+ /* compute S = B*D*B', where B = P*A, B' is a matrix transposed
+ to B */
+ for (ii = 1; ii <= m; ii++)
+ { i = P_per[ii]; /* i-th row of A = ii-th row of B */
+ /* (work) := (i-th row of A) */
+ beg = A_ptr[i], end = A_ptr[i+1];
+ for (t = beg; t < end; t++)
+ work[A_ind[t]] = A_val[t];
+ /* compute ii-th row of S */
+ beg = S_ptr[ii], end = S_ptr[ii+1];
+ for (t = beg; t < end; t++)
+ { jj = S_ind[t];
+ j = P_per[jj]; /* j-th row of A = jj-th row of B */
+ /* s[ii,jj] := sum a[i,k] * d[k,k] * a[j,k] */
+ sum = 0.0;
+ beg1 = A_ptr[j], end1 = A_ptr[j+1];
+ for (tt = beg1; tt < end1; tt++)
+ { k = A_ind[tt];
+ sum += work[k] * D_diag[k] * A_val[tt];
+ }
+ S_val[t] = sum;
+ }
+ /* s[ii,ii] := sum a[i,k] * d[k,k] * a[i,k] */
+ sum = 0.0;
+ beg = A_ptr[i], end = A_ptr[i+1];
+ for (t = beg; t < end; t++)
+ { k = A_ind[t];
+ sum += A_val[t] * D_diag[k] * A_val[t];
+ work[k] = 0.0;
+ }
+ S_diag[ii] = sum;
+ }
+ xfree(work);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- min_degree - minimum degree ordering.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]);
+--
+-- *Description*
+--
+-- The routine min_degree uses the minimum degree ordering algorithm
+-- to find a permutation matrix P for a given sparse symmetric positive
+-- matrix A which minimizes the number of non-zeros in upper triangular
+-- factor U for Cholesky factorization P*A*P' = U'*U.
+--
+-- The parameter n is the order of matrices A and P.
+--
+-- The pattern of the given matrix A is specified on entry in the arrays
+-- A_ptr and A_ind in storage-by-rows format. Only the upper triangular
+-- part without diagonal elements (which all are assumed to be non-zero)
+-- should be specified as if A were upper triangular. The arrays A_ptr
+-- and A_ind are not changed on exit.
+--
+-- The permutation matrix P is stored by the routine in the array P_per
+-- on exit.
+--
+-- *Algorithm*
+--
+-- The routine min_degree is based on some subroutines from the package
+-- SPARSPAK (see comments in the module glpqmd). */
+
+void min_degree(int n, int A_ptr[], int A_ind[], int P_per[])
+{ int i, j, ne, t, pos, len;
+ int *xadj, *adjncy, *deg, *marker, *rchset, *nbrhd, *qsize,
+ *qlink, nofsub;
+ /* determine number of non-zeros in complete pattern */
+ ne = A_ptr[n+1] - 1;
+ ne += ne;
+ /* allocate working arrays */
+ xadj = xcalloc(1+n+1, sizeof(int));
+ adjncy = xcalloc(1+ne, sizeof(int));
+ deg = xcalloc(1+n, sizeof(int));
+ marker = xcalloc(1+n, sizeof(int));
+ rchset = xcalloc(1+n, sizeof(int));
+ nbrhd = xcalloc(1+n, sizeof(int));
+ qsize = xcalloc(1+n, sizeof(int));
+ qlink = xcalloc(1+n, sizeof(int));
+ /* determine row lengths in complete pattern */
+ for (i = 1; i <= n; i++) xadj[i] = 0;
+ for (i = 1; i <= n; i++)
+ { for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
+ { j = A_ind[t];
+ xassert(i < j && j <= n);
+ xadj[i]++, xadj[j]++;
+ }
+ }
+ /* set up row pointers for complete pattern */
+ pos = 1;
+ for (i = 1; i <= n; i++)
+ len = xadj[i], pos += len, xadj[i] = pos;
+ xadj[n+1] = pos;
+ xassert(pos - 1 == ne);
+ /* construct complete pattern */
+ for (i = 1; i <= n; i++)
+ { for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
+ { j = A_ind[t];
+ adjncy[--xadj[i]] = j, adjncy[--xadj[j]] = i;
+ }
+ }
+ /* call the main minimimum degree ordering routine */
+ genqmd(&n, xadj, adjncy, P_per, P_per + n, deg, marker, rchset,
+ nbrhd, qsize, qlink, &nofsub);
+ /* make sure that permutation matrix P is correct */
+ for (i = 1; i <= n; i++)
+ { j = P_per[i];
+ xassert(1 <= j && j <= n);
+ xassert(P_per[n+j] == i);
+ }
+ /* free working arrays */
+ xfree(xadj);
+ xfree(adjncy);
+ xfree(deg);
+ xfree(marker);
+ xfree(rchset);
+ xfree(nbrhd);
+ xfree(qsize);
+ xfree(qlink);
+ return;
+}
+
+/**********************************************************************/
+
+void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[])
+{ /* approximate minimum degree ordering (AMD) */
+ int k, ret;
+ double Control[AMD_CONTROL], Info[AMD_INFO];
+ /* get the default parameters */
+ amd_defaults(Control);
+#if 0
+ /* and print them */
+ amd_control(Control);
+#endif
+ /* make all indices 0-based */
+ for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--;
+ for (k = 1; k <= n+1; k++) A_ptr[k]--;
+ /* call the ordering routine */
+ ret = amd_order(n, &A_ptr[1], &A_ind[1], &P_per[1], Control, Info)
+ ;
+#if 0
+ amd_info(Info);
+#endif
+ xassert(ret == AMD_OK || ret == AMD_OK_BUT_JUMBLED);
+ /* retsore 1-based indices */
+ for (k = 1; k <= n+1; k++) A_ptr[k]++;
+ for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++;
+ /* patch up permutation matrix */
+ memset(&P_per[n+1], 0, n * sizeof(int));
+ for (k = 1; k <= n; k++)
+ { P_per[k]++;
+ xassert(1 <= P_per[k] && P_per[k] <= n);
+ xassert(P_per[n+P_per[k]] == 0);
+ P_per[n+P_per[k]] = k;
+ }
+ return;
+}
+
+/**********************************************************************/
+
+static void *allocate(size_t n, size_t size)
+{ void *ptr;
+ ptr = xcalloc(n, size);
+ memset(ptr, 0, n * size);
+ return ptr;
+}
+
+static void release(void *ptr)
+{ xfree(ptr);
+ return;
+}
+
+void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[])
+{ /* approximate minimum degree ordering (SYMAMD) */
+ int k, ok;
+ int stats[COLAMD_STATS];
+ /* make all indices 0-based */
+ for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--;
+ for (k = 1; k <= n+1; k++) A_ptr[k]--;
+ /* call the ordering routine */
+ ok = symamd(n, &A_ind[1], &A_ptr[1], &P_per[1], NULL, stats,
+ allocate, release);
+#if 0
+ symamd_report(stats);
+#endif
+ xassert(ok);
+ /* restore 1-based indices */
+ for (k = 1; k <= n+1; k++) A_ptr[k]++;
+ for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++;
+ /* patch up permutation matrix */
+ memset(&P_per[n+1], 0, n * sizeof(int));
+ for (k = 1; k <= n; k++)
+ { P_per[k]++;
+ xassert(1 <= P_per[k] && P_per[k] <= n);
+ xassert(P_per[n+P_per[k]] == 0);
+ P_per[n+P_per[k]] = k;
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- chol_symbolic - compute Cholesky factorization (symbolic phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]);
+--
+-- *Description*
+--
+-- The routine chol_symbolic implements the symbolic phase of Cholesky
+-- factorization A = U'*U, where A is a given sparse symmetric positive
+-- definite matrix, U is a resultant upper triangular factor, U' is a
+-- matrix transposed to U.
+--
+-- The parameter n is the order of matrices A and U.
+--
+-- The pattern of the given matrix A is specified on entry in the arrays
+-- A_ptr and A_ind in storage-by-rows format. Only the upper triangular
+-- part without diagonal elements (which all are assumed to be non-zero)
+-- should be specified as if A were upper triangular. The arrays A_ptr
+-- and A_ind are not changed on exit.
+--
+-- The pattern of the matrix U without diagonal elements (which all are
+-- assumed to be non-zero) is stored on exit from the routine in the
+-- arrays U_ptr and U_ind in storage-by-rows format. The array U_ptr
+-- should be allocated on entry, however, its content is ignored. The
+-- array U_ind is allocated by the routine which returns a pointer to it
+-- on exit.
+--
+-- *Returns*
+--
+-- The routine returns a pointer to the array U_ind.
+--
+-- *Method*
+--
+-- The routine chol_symbolic computes the pattern of the matrix U in a
+-- row-wise manner. No pivoting is used.
+--
+-- It is known that to compute the pattern of row k of the matrix U we
+-- need to merge the pattern of row k of the matrix A and the patterns
+-- of each row i of U, where u[i,k] is non-zero (these rows are already
+-- computed and placed above row k).
+--
+-- However, to reduce the number of rows to be merged the routine uses
+-- an advanced algorithm proposed in:
+--
+-- D.J.Rose, R.E.Tarjan, and G.S.Lueker. Algorithmic aspects of vertex
+-- elimination on graphs. SIAM J. Comput. 5, 1976, 266-83.
+--
+-- The authors of the cited paper show that we have the same result if
+-- we merge row k of the matrix A and such rows of the matrix U (among
+-- rows 1, ..., k-1) whose leftmost non-diagonal non-zero element is
+-- placed in k-th column. This feature signficantly reduces the number
+-- of rows to be merged, especially on the final steps, where rows of
+-- the matrix U become quite dense.
+--
+-- To determine rows, which should be merged on k-th step, for a fixed
+-- time the routine uses linked lists of row numbers of the matrix U.
+-- Location head[k] contains the number of a first row, whose leftmost
+-- non-diagonal non-zero element is placed in column k, and location
+-- next[i] contains the number of a next row with the same property as
+-- row i. */
+
+int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[])
+{ int i, j, k, t, len, size, beg, end, min_j, *U_ind, *head, *next,
+ *ind, *map, *temp;
+ /* initially we assume that on computing the pattern of U fill-in
+ will double the number of non-zeros in A */
+ size = A_ptr[n+1] - 1;
+ if (size < n) size = n;
+ size += size;
+ U_ind = xcalloc(1+size, sizeof(int));
+ /* allocate and initialize working arrays */
+ head = xcalloc(1+n, sizeof(int));
+ for (i = 1; i <= n; i++) head[i] = 0;
+ next = xcalloc(1+n, sizeof(int));
+ ind = xcalloc(1+n, sizeof(int));
+ map = xcalloc(1+n, sizeof(int));
+ for (j = 1; j <= n; j++) map[j] = 0;
+ /* compute the pattern of matrix U */
+ U_ptr[1] = 1;
+ for (k = 1; k <= n; k++)
+ { /* compute the pattern of k-th row of U, which is the union of
+ k-th row of A and those rows of U (among 1, ..., k-1) whose
+ leftmost non-diagonal non-zero is placed in k-th column */
+ /* (ind) := (k-th row of A) */
+ len = A_ptr[k+1] - A_ptr[k];
+ memcpy(&ind[1], &A_ind[A_ptr[k]], len * sizeof(int));
+ for (t = 1; t <= len; t++)
+ { j = ind[t];
+ xassert(k < j && j <= n);
+ map[j] = 1;
+ }
+ /* walk through rows of U whose leftmost non-diagonal non-zero
+ is placed in k-th column */
+ for (i = head[k]; i != 0; i = next[i])
+ { /* (ind) := (ind) union (i-th row of U) */
+ beg = U_ptr[i], end = U_ptr[i+1];
+ for (t = beg; t < end; t++)
+ { j = U_ind[t];
+ if (j > k && !map[j]) ind[++len] = j, map[j] = 1;
+ }
+ }
+ /* now (ind) is the pattern of k-th row of U */
+ U_ptr[k+1] = U_ptr[k] + len;
+ /* at least (U_ptr[k+1] - 1) locations should be available in
+ the array U_ind */
+ if (U_ptr[k+1] - 1 > size)
+ { temp = U_ind;
+ size += size;
+ U_ind = xcalloc(1+size, sizeof(int));
+ memcpy(&U_ind[1], &temp[1], (U_ptr[k] - 1) * sizeof(int));
+ xfree(temp);
+ }
+ xassert(U_ptr[k+1] - 1 <= size);
+ /* (k-th row of U) := (ind) */
+ memcpy(&U_ind[U_ptr[k]], &ind[1], len * sizeof(int));
+ /* determine column index of leftmost non-diagonal non-zero in
+ k-th row of U and clear the row pattern map */
+ min_j = n + 1;
+ for (t = 1; t <= len; t++)
+ { j = ind[t], map[j] = 0;
+ if (min_j > j) min_j = j;
+ }
+ /* include k-th row into corresponding linked list */
+ if (min_j <= n) next[k] = head[min_j], head[min_j] = k;
+ }
+ /* free working arrays */
+ xfree(head);
+ xfree(next);
+ xfree(ind);
+ xfree(map);
+ /* reallocate the array U_ind to free unused locations */
+ temp = U_ind;
+ size = U_ptr[n+1] - 1;
+ U_ind = xcalloc(1+size, sizeof(int));
+ memcpy(&U_ind[1], &temp[1], size * sizeof(int));
+ xfree(temp);
+ return U_ind;
+}
+
+/*----------------------------------------------------------------------
+-- chol_numeric - compute Cholesky factorization (numeric phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- int chol_numeric(int n,
+-- int A_ptr[], int A_ind[], double A_val[], double A_diag[],
+-- int U_ptr[], int U_ind[], double U_val[], double U_diag[]);
+--
+-- *Description*
+--
+-- The routine chol_symbolic implements the numeric phase of Cholesky
+-- factorization A = U'*U, where A is a given sparse symmetric positive
+-- definite matrix, U is a resultant upper triangular factor, U' is a
+-- matrix transposed to U.
+--
+-- The parameter n is the order of matrices A and U.
+--
+-- Upper triangular part of the matrix A without diagonal elements is
+-- specified in the arrays A_ptr, A_ind, and A_val in storage-by-rows
+-- format. Diagonal elements of A are specified in the array A_diag,
+-- where A_diag[0] is not used, A_diag[i] = a[i,i] for i = 1, ..., n.
+-- The arrays A_ptr, A_ind, A_val, and A_diag are not changed on exit.
+--
+-- The pattern of the matrix U without diagonal elements (previously
+-- computed with the routine chol_symbolic) is specified in the arrays
+-- U_ptr and U_ind, which are not changed on exit. Numeric values of
+-- non-diagonal elements of U are stored in corresponding locations of
+-- the array U_val, and values of diagonal elements of U are stored in
+-- locations U_diag[1], ..., U_diag[n].
+--
+-- *Returns*
+--
+-- The routine returns the number of non-positive diagonal elements of
+-- the matrix U which have been replaced by a huge positive number (see
+-- the method description below). Zero return code means the matrix A
+-- has been successfully factorized.
+--
+-- *Method*
+--
+-- The routine chol_numeric computes the matrix U in a row-wise manner
+-- using standard gaussian elimination technique. No pivoting is used.
+--
+-- Initially the routine sets U = A, and before k-th elimination step
+-- the matrix U is the following:
+--
+-- 1 k n
+-- 1 x x x x x x x x x x
+-- . x x x x x x x x x
+-- . . x x x x x x x x
+-- . . . x x x x x x x
+-- k . . . . * * * * * *
+-- . . . . * * * * * *
+-- . . . . * * * * * *
+-- . . . . * * * * * *
+-- . . . . * * * * * *
+-- n . . . . * * * * * *
+--
+-- where 'x' are elements of already computed rows, '*' are elements of
+-- the active submatrix. (Note that the lower triangular part of the
+-- active submatrix being symmetric is not stored and diagonal elements
+-- are stored separately in the array U_diag.)
+--
+-- The matrix A is assumed to be positive definite. However, if it is
+-- close to semi-definite, on some elimination step a pivot u[k,k] may
+-- happen to be non-positive due to round-off errors. In this case the
+-- routine uses a technique proposed in:
+--
+-- S.J.Wright. The Cholesky factorization in interior-point and barrier
+-- methods. Preprint MCS-P600-0596, Mathematics and Computer Science
+-- Division, Argonne National Laboratory, Argonne, Ill., May 1996.
+--
+-- The routine just replaces non-positive u[k,k] by a huge positive
+-- number. This involves non-diagonal elements in k-th row of U to be
+-- close to zero that, in turn, involves k-th component of a solution
+-- vector to be close to zero. Note, however, that this technique works
+-- only if the system A*x = b is consistent. */
+
+int chol_numeric(int n,
+ int A_ptr[], int A_ind[], double A_val[], double A_diag[],
+ int U_ptr[], int U_ind[], double U_val[], double U_diag[])
+{ int i, j, k, t, t1, beg, end, beg1, end1, count = 0;
+ double ukk, uki, *work;
+ work = xcalloc(1+n, sizeof(double));
+ for (j = 1; j <= n; j++) work[j] = 0.0;
+ /* U := (upper triangle of A) */
+ /* note that the upper traingle of A is a subset of U */
+ for (i = 1; i <= n; i++)
+ { beg = A_ptr[i], end = A_ptr[i+1];
+ for (t = beg; t < end; t++)
+ j = A_ind[t], work[j] = A_val[t];
+ beg = U_ptr[i], end = U_ptr[i+1];
+ for (t = beg; t < end; t++)
+ j = U_ind[t], U_val[t] = work[j], work[j] = 0.0;
+ U_diag[i] = A_diag[i];
+ }
+ /* main elimination loop */
+ for (k = 1; k <= n; k++)
+ { /* transform k-th row of U */
+ ukk = U_diag[k];
+ if (ukk > 0.0)
+ U_diag[k] = ukk = sqrt(ukk);
+ else
+ U_diag[k] = ukk = DBL_MAX, count++;
+ /* (work) := (transformed k-th row) */
+ beg = U_ptr[k], end = U_ptr[k+1];
+ for (t = beg; t < end; t++)
+ work[U_ind[t]] = (U_val[t] /= ukk);
+ /* transform other rows of U */
+ for (t = beg; t < end; t++)
+ { i = U_ind[t];
+ xassert(i > k);
+ /* (i-th row) := (i-th row) - u[k,i] * (k-th row) */
+ uki = work[i];
+ beg1 = U_ptr[i], end1 = U_ptr[i+1];
+ for (t1 = beg1; t1 < end1; t1++)
+ U_val[t1] -= uki * work[U_ind[t1]];
+ U_diag[i] -= uki * uki;
+ }
+ /* (work) := 0 */
+ for (t = beg; t < end; t++)
+ work[U_ind[t]] = 0.0;
+ }
+ xfree(work);
+ return count;
+}
+
+/*----------------------------------------------------------------------
+-- u_solve - solve upper triangular system U*x = b.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+-- double U_diag[], double x[]);
+--
+-- *Description*
+--
+-- The routine u_solve solves an linear system U*x = b, where U is an
+-- upper triangular matrix.
+--
+-- The parameter n is the order of matrix U.
+--
+-- The matrix U without diagonal elements is specified in the arrays
+-- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements
+-- of U are specified in the array U_diag, where U_diag[0] is not used,
+-- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not
+-- changed on exit.
+--
+-- The right-hand side vector b is specified on entry in the array x,
+-- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit
+-- the routine stores computed components of the vector of unknowns x
+-- in the array x in the same manner. */
+
+void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+ double U_diag[], double x[])
+{ int i, t, beg, end;
+ double temp;
+ for (i = n; i >= 1; i--)
+ { temp = x[i];
+ beg = U_ptr[i], end = U_ptr[i+1];
+ for (t = beg; t < end; t++)
+ temp -= U_val[t] * x[U_ind[t]];
+ xassert(U_diag[i] != 0.0);
+ x[i] = temp / U_diag[i];
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- ut_solve - solve lower triangular system U'*x = b.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+-- double U_diag[], double x[]);
+--
+-- *Description*
+--
+-- The routine ut_solve solves an linear system U'*x = b, where U is a
+-- matrix transposed to an upper triangular matrix.
+--
+-- The parameter n is the order of matrix U.
+--
+-- The matrix U without diagonal elements is specified in the arrays
+-- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements
+-- of U are specified in the array U_diag, where U_diag[0] is not used,
+-- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not
+-- changed on exit.
+--
+-- The right-hand side vector b is specified on entry in the array x,
+-- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit
+-- the routine stores computed components of the vector of unknowns x
+-- in the array x in the same manner. */
+
+void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+ double U_diag[], double x[])
+{ int i, t, beg, end;
+ double temp;
+ for (i = 1; i <= n; i++)
+ { xassert(U_diag[i] != 0.0);
+ temp = (x[i] /= U_diag[i]);
+ if (temp == 0.0) continue;
+ beg = U_ptr[i], end = U_ptr[i+1];
+ for (t = beg; t < end; t++)
+ x[U_ind[t]] -= U_val[t] * temp;
+ }
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpmat.h b/test/monniaux/glpk-4.65/src/draft/glpmat.h
new file mode 100644
index 00000000..5b058437
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpmat.h
@@ -0,0 +1,198 @@
+/* glpmat.h (linear algebra routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#ifndef GLPMAT_H
+#define GLPMAT_H
+
+/***********************************************************************
+* FULL-VECTOR STORAGE
+*
+* For a sparse vector x having n elements, ne of which are non-zero,
+* the full-vector storage format uses two arrays x_ind and x_vec, which
+* are set up as follows:
+*
+* x_ind is an integer array of length [1+ne]. Location x_ind[0] is
+* not used, and locations x_ind[1], ..., x_ind[ne] contain indices of
+* non-zero elements in vector x.
+*
+* x_vec is a floating-point array of length [1+n]. Location x_vec[0]
+* is not used, and locations x_vec[1], ..., x_vec[n] contain numeric
+* values of ALL elements in vector x, including its zero elements.
+*
+* Let, for example, the following sparse vector x be given:
+*
+* (0, 1, 0, 0, 2, 3, 0, 4)
+*
+* Then the arrays are:
+*
+* x_ind = { X; 2, 5, 6, 8 }
+*
+* x_vec = { X; 0, 1, 0, 0, 2, 3, 0, 4 }
+*
+* COMPRESSED-VECTOR STORAGE
+*
+* For a sparse vector x having n elements, ne of which are non-zero,
+* the compressed-vector storage format uses two arrays x_ind and x_vec,
+* which are set up as follows:
+*
+* x_ind is an integer array of length [1+ne]. Location x_ind[0] is
+* not used, and locations x_ind[1], ..., x_ind[ne] contain indices of
+* non-zero elements in vector x.
+*
+* x_vec is a floating-point array of length [1+ne]. Location x_vec[0]
+* is not used, and locations x_vec[1], ..., x_vec[ne] contain numeric
+* values of corresponding non-zero elements in vector x.
+*
+* Let, for example, the following sparse vector x be given:
+*
+* (0, 1, 0, 0, 2, 3, 0, 4)
+*
+* Then the arrays are:
+*
+* x_ind = { X; 2, 5, 6, 8 }
+*
+* x_vec = { X; 1, 2, 3, 4 }
+*
+* STORAGE-BY-ROWS
+*
+* For a sparse matrix A, which has m rows, n columns, and ne non-zero
+* elements the storage-by-rows format uses three arrays A_ptr, A_ind,
+* and A_val, which are set up as follows:
+*
+* A_ptr is an integer array of length [1+m+1] also called "row pointer
+* array". It contains the relative starting positions of each row of A
+* in the arrays A_ind and A_val, i.e. element A_ptr[i], 1 <= i <= m,
+* indicates where row i begins in the arrays A_ind and A_val. If all
+* elements in row i are zero, then A_ptr[i] = A_ptr[i+1]. Location
+* A_ptr[0] is not used, location A_ptr[1] must contain 1, and location
+* A_ptr[m+1] must contain ne+1 that indicates the position after the
+* last element in the arrays A_ind and A_val.
+*
+* A_ind is an integer array of length [1+ne]. Location A_ind[0] is not
+* used, and locations A_ind[1], ..., A_ind[ne] contain column indices
+* of (non-zero) elements in matrix A.
+*
+* A_val is a floating-point array of length [1+ne]. Location A_val[0]
+* is not used, and locations A_val[1], ..., A_val[ne] contain numeric
+* values of non-zero elements in matrix A.
+*
+* Non-zero elements of matrix A are stored contiguously, and the rows
+* of matrix A are stored consecutively from 1 to m in the arrays A_ind
+* and A_val. The elements in each row of A may be stored in any order
+* in A_ind and A_val. Note that elements with duplicate column indices
+* are not allowed.
+*
+* Let, for example, the following sparse matrix A be given:
+*
+* | 11 . 13 . . . |
+* | 21 22 . 24 . . |
+* | . 32 33 . . . |
+* | . . 43 44 . 46 |
+* | . . . . . . |
+* | 61 62 . . . 66 |
+*
+* Then the arrays are:
+*
+* A_ptr = { X; 1, 3, 6, 8, 11, 11; 14 }
+*
+* A_ind = { X; 1, 3; 4, 2, 1; 2, 3; 4, 3, 6; 1, 2, 6 }
+*
+* A_val = { X; 11, 13; 24, 22, 21; 32, 33; 44, 43, 46; 61, 62, 66 }
+*
+* PERMUTATION MATRICES
+*
+* Let P be a permutation matrix of the order n. It is represented as
+* an integer array P_per of length [1+n+n] as follows: if p[i,j] = 1,
+* then P_per[i] = j and P_per[n+j] = i. Location P_per[0] is not used.
+*
+* Let A' = P*A. If i-th row of A corresponds to i'-th row of A', then
+* P_per[i'] = i and P_per[n+i] = i'.
+*
+* References:
+*
+* 1. Gustavson F.G. Some basic techniques for solving sparse systems of
+* linear equations. In Rose and Willoughby (1972), pp. 41-52.
+*
+* 2. Basic Linear Algebra Subprograms Technical (BLAST) Forum Standard.
+* University of Tennessee (2001). */
+
+#define check_fvs _glp_mat_check_fvs
+int check_fvs(int n, int nnz, int ind[], double vec[]);
+/* check sparse vector in full-vector storage format */
+
+#define check_pattern _glp_mat_check_pattern
+int check_pattern(int m, int n, int A_ptr[], int A_ind[]);
+/* check pattern of sparse matrix */
+
+#define transpose _glp_mat_transpose
+void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[],
+ int AT_ptr[], int AT_ind[], double AT_val[]);
+/* transpose sparse matrix */
+
+#define adat_symbolic _glp_mat_adat_symbolic
+int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[],
+ int S_ptr[]);
+/* compute S = P*A*D*A'*P' (symbolic phase) */
+
+#define adat_numeric _glp_mat_adat_numeric
+void adat_numeric(int m, int n, int P_per[],
+ int A_ptr[], int A_ind[], double A_val[], double D_diag[],
+ int S_ptr[], int S_ind[], double S_val[], double S_diag[]);
+/* compute S = P*A*D*A'*P' (numeric phase) */
+
+#define min_degree _glp_mat_min_degree
+void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]);
+/* minimum degree ordering */
+
+#define amd_order1 _glp_mat_amd_order1
+void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[]);
+/* approximate minimum degree ordering (AMD) */
+
+#define symamd_ord _glp_mat_symamd_ord
+void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[]);
+/* approximate minimum degree ordering (SYMAMD) */
+
+#define chol_symbolic _glp_mat_chol_symbolic
+int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]);
+/* compute Cholesky factorization (symbolic phase) */
+
+#define chol_numeric _glp_mat_chol_numeric
+int chol_numeric(int n,
+ int A_ptr[], int A_ind[], double A_val[], double A_diag[],
+ int U_ptr[], int U_ind[], double U_val[], double U_diag[]);
+/* compute Cholesky factorization (numeric phase) */
+
+#define u_solve _glp_mat_u_solve
+void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+ double U_diag[], double x[]);
+/* solve upper triangular system U*x = b */
+
+#define ut_solve _glp_mat_ut_solve
+void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+ double U_diag[], double x[]);
+/* solve lower triangular system U'*x = b */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glprgr.c b/test/monniaux/glpk-4.65/src/draft/glprgr.c
new file mode 100644
index 00000000..fbff6b8d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glprgr.c
@@ -0,0 +1,173 @@
+/* glprgr.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2017 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_ERRNO
+#define _GLPSTD_STDIO
+#include "env.h"
+#include "glprgr.h"
+#define xfault xerror
+
+/***********************************************************************
+* NAME
+*
+* rgr_write_bmp16 - write 16-color raster image in BMP file format
+*
+* SYNOPSIS
+*
+* #include "glprgr.h"
+* int rgr_write_bmp16(const char *fname, int m, int n, const char
+* map[]);
+*
+* DESCRIPTION
+*
+* The routine rgr_write_bmp16 writes 16-color raster image in
+* uncompressed BMP file format (Windows bitmap) to a binary file whose
+* name is specified by the character string fname.
+*
+* The parameters m and n specify, respectively, the number of rows and
+* the numbers of columns (i.e. height and width) of the raster image.
+*
+* The character array map has m*n elements. Elements map[0, ..., n-1]
+* correspond to the first (top) scanline, elements map[n, ..., 2*n-1]
+* correspond to the second scanline, etc.
+*
+* Each element of the array map specifies a color of the corresponding
+* pixel as 8-bit binary number XXXXIRGB, where four high-order bits (X)
+* are ignored, I is high intensity bit, R is red color bit, G is green
+* color bit, and B is blue color bit. Thus, all 16 possible colors are
+* coded as following hexadecimal numbers:
+*
+* 0x00 = black 0x08 = dark gray
+* 0x01 = blue 0x09 = bright blue
+* 0x02 = green 0x0A = bright green
+* 0x03 = cyan 0x0B = bright cyan
+* 0x04 = red 0x0C = bright red
+* 0x05 = magenta 0x0D = bright magenta
+* 0x06 = brown 0x0E = yellow
+* 0x07 = light gray 0x0F = white
+*
+* RETURNS
+*
+* If no error occured, the routine returns zero; otherwise, it prints
+* an appropriate error message and returns non-zero. */
+
+static void put_byte(FILE *fp, int c)
+{ fputc(c, fp);
+ return;
+}
+
+static void put_word(FILE *fp, int w)
+{ /* big endian */
+ put_byte(fp, w);
+ put_byte(fp, w >> 8);
+ return;
+}
+
+static void put_dword(FILE *fp, int d)
+{ /* big endian */
+ put_word(fp, d);
+ put_word(fp, d >> 16);
+ return;
+}
+
+int rgr_write_bmp16(const char *fname, int m, int n, const char map[])
+{ FILE *fp;
+ int offset, bmsize, i, j, b, ret = 0;
+ if (!(1 <= m && m <= 32767))
+ xfault("rgr_write_bmp16: m = %d; invalid height\n", m);
+ if (!(1 <= n && n <= 32767))
+ xfault("rgr_write_bmp16: n = %d; invalid width\n", n);
+ fp = fopen(fname, "wb");
+ if (fp == NULL)
+ { xprintf("rgr_write_bmp16: unable to create '%s' - %s\n",
+#if 0 /* 29/I-2017 */
+ fname, strerror(errno));
+#else
+ fname, xstrerr(errno));
+#endif
+ ret = 1;
+ goto fini;
+ }
+ offset = 14 + 40 + 16 * 4;
+ bmsize = (4 * n + 31) / 32;
+ /* struct BMPFILEHEADER (14 bytes) */
+ /* UINT bfType */ put_byte(fp, 'B'), put_byte(fp, 'M');
+ /* DWORD bfSize */ put_dword(fp, offset + bmsize * 4);
+ /* UINT bfReserved1 */ put_word(fp, 0);
+ /* UNIT bfReserved2 */ put_word(fp, 0);
+ /* DWORD bfOffBits */ put_dword(fp, offset);
+ /* struct BMPINFOHEADER (40 bytes) */
+ /* DWORD biSize */ put_dword(fp, 40);
+ /* LONG biWidth */ put_dword(fp, n);
+ /* LONG biHeight */ put_dword(fp, m);
+ /* WORD biPlanes */ put_word(fp, 1);
+ /* WORD biBitCount */ put_word(fp, 4);
+ /* DWORD biCompression */ put_dword(fp, 0 /* BI_RGB */);
+ /* DWORD biSizeImage */ put_dword(fp, 0);
+ /* LONG biXPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */);
+ /* LONG biYPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */);
+ /* DWORD biClrUsed */ put_dword(fp, 0);
+ /* DWORD biClrImportant */ put_dword(fp, 0);
+ /* struct RGBQUAD (16 * 4 = 64 bytes) */
+ /* CGA-compatible colors: */
+ /* 0x00 = black */ put_dword(fp, 0x000000);
+ /* 0x01 = blue */ put_dword(fp, 0x000080);
+ /* 0x02 = green */ put_dword(fp, 0x008000);
+ /* 0x03 = cyan */ put_dword(fp, 0x008080);
+ /* 0x04 = red */ put_dword(fp, 0x800000);
+ /* 0x05 = magenta */ put_dword(fp, 0x800080);
+ /* 0x06 = brown */ put_dword(fp, 0x808000);
+ /* 0x07 = light gray */ put_dword(fp, 0xC0C0C0);
+ /* 0x08 = dark gray */ put_dword(fp, 0x808080);
+ /* 0x09 = bright blue */ put_dword(fp, 0x0000FF);
+ /* 0x0A = bright green */ put_dword(fp, 0x00FF00);
+ /* 0x0B = bright cyan */ put_dword(fp, 0x00FFFF);
+ /* 0x0C = bright red */ put_dword(fp, 0xFF0000);
+ /* 0x0D = bright magenta */ put_dword(fp, 0xFF00FF);
+ /* 0x0E = yellow */ put_dword(fp, 0xFFFF00);
+ /* 0x0F = white */ put_dword(fp, 0xFFFFFF);
+ /* pixel data bits */
+ b = 0;
+ for (i = m - 1; i >= 0; i--)
+ { for (j = 0; j < ((n + 7) / 8) * 8; j++)
+ { b <<= 4;
+ b |= (j < n ? map[i * n + j] & 15 : 0);
+ if (j & 1) put_byte(fp, b);
+ }
+ }
+ fflush(fp);
+ if (ferror(fp))
+ { xprintf("rgr_write_bmp16: write error on '%s' - %s\n",
+#if 0 /* 29/I-2017 */
+ fname, strerror(errno));
+#else
+ fname, xstrerr(errno));
+#endif
+ ret = 1;
+ }
+fini: if (fp != NULL) fclose(fp);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glprgr.h b/test/monniaux/glpk-4.65/src/draft/glprgr.h
new file mode 100644
index 00000000..71e089e9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glprgr.h
@@ -0,0 +1,34 @@
+/* glprgr.h (raster graphics) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#ifndef GLPRGR_H
+#define GLPRGR_H
+
+#define rgr_write_bmp16 _glp_rgr_write_bmp16
+int rgr_write_bmp16(const char *fname, int m, int n, const char map[]);
+/* write 16-color raster image in BMP file format */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpscl.c b/test/monniaux/glpk-4.65/src/draft/glpscl.c
new file mode 100644
index 00000000..de769a8b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpscl.c
@@ -0,0 +1,478 @@
+/* glpscl.c (problem scaling routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "misc.h"
+#include "prob.h"
+
+/***********************************************************************
+* min_row_aij - determine minimal |a[i,j]| in i-th row
+*
+* This routine returns minimal magnitude of (non-zero) constraint
+* coefficients in i-th row of the constraint matrix.
+*
+* If the parameter scaled is zero, the original constraint matrix A is
+* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+* If i-th row of the matrix is empty, the routine returns 1. */
+
+static double min_row_aij(glp_prob *lp, int i, int scaled)
+{ GLPAIJ *aij;
+ double min_aij, temp;
+ xassert(1 <= i && i <= lp->m);
+ min_aij = 1.0;
+ for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ { temp = fabs(aij->val);
+ if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+ if (aij->r_prev == NULL || min_aij > temp)
+ min_aij = temp;
+ }
+ return min_aij;
+}
+
+/***********************************************************************
+* max_row_aij - determine maximal |a[i,j]| in i-th row
+*
+* This routine returns maximal magnitude of (non-zero) constraint
+* coefficients in i-th row of the constraint matrix.
+*
+* If the parameter scaled is zero, the original constraint matrix A is
+* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+* If i-th row of the matrix is empty, the routine returns 1. */
+
+static double max_row_aij(glp_prob *lp, int i, int scaled)
+{ GLPAIJ *aij;
+ double max_aij, temp;
+ xassert(1 <= i && i <= lp->m);
+ max_aij = 1.0;
+ for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ { temp = fabs(aij->val);
+ if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+ if (aij->r_prev == NULL || max_aij < temp)
+ max_aij = temp;
+ }
+ return max_aij;
+}
+
+/***********************************************************************
+* min_col_aij - determine minimal |a[i,j]| in j-th column
+*
+* This routine returns minimal magnitude of (non-zero) constraint
+* coefficients in j-th column of the constraint matrix.
+*
+* If the parameter scaled is zero, the original constraint matrix A is
+* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+* If j-th column of the matrix is empty, the routine returns 1. */
+
+static double min_col_aij(glp_prob *lp, int j, int scaled)
+{ GLPAIJ *aij;
+ double min_aij, temp;
+ xassert(1 <= j && j <= lp->n);
+ min_aij = 1.0;
+ for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+ { temp = fabs(aij->val);
+ if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+ if (aij->c_prev == NULL || min_aij > temp)
+ min_aij = temp;
+ }
+ return min_aij;
+}
+
+/***********************************************************************
+* max_col_aij - determine maximal |a[i,j]| in j-th column
+*
+* This routine returns maximal magnitude of (non-zero) constraint
+* coefficients in j-th column of the constraint matrix.
+*
+* If the parameter scaled is zero, the original constraint matrix A is
+* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+* If j-th column of the matrix is empty, the routine returns 1. */
+
+static double max_col_aij(glp_prob *lp, int j, int scaled)
+{ GLPAIJ *aij;
+ double max_aij, temp;
+ xassert(1 <= j && j <= lp->n);
+ max_aij = 1.0;
+ for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+ { temp = fabs(aij->val);
+ if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+ if (aij->c_prev == NULL || max_aij < temp)
+ max_aij = temp;
+ }
+ return max_aij;
+}
+
+/***********************************************************************
+* min_mat_aij - determine minimal |a[i,j]| in constraint matrix
+*
+* This routine returns minimal magnitude of (non-zero) constraint
+* coefficients in the constraint matrix.
+*
+* If the parameter scaled is zero, the original constraint matrix A is
+* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+* If the matrix is empty, the routine returns 1. */
+
+static double min_mat_aij(glp_prob *lp, int scaled)
+{ int i;
+ double min_aij, temp;
+ min_aij = 1.0;
+ for (i = 1; i <= lp->m; i++)
+ { temp = min_row_aij(lp, i, scaled);
+ if (i == 1 || min_aij > temp)
+ min_aij = temp;
+ }
+ return min_aij;
+}
+
+/***********************************************************************
+* max_mat_aij - determine maximal |a[i,j]| in constraint matrix
+*
+* This routine returns maximal magnitude of (non-zero) constraint
+* coefficients in the constraint matrix.
+*
+* If the parameter scaled is zero, the original constraint matrix A is
+* assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+* If the matrix is empty, the routine returns 1. */
+
+static double max_mat_aij(glp_prob *lp, int scaled)
+{ int i;
+ double max_aij, temp;
+ max_aij = 1.0;
+ for (i = 1; i <= lp->m; i++)
+ { temp = max_row_aij(lp, i, scaled);
+ if (i == 1 || max_aij < temp)
+ max_aij = temp;
+ }
+ return max_aij;
+}
+
+/***********************************************************************
+* eq_scaling - perform equilibration scaling
+*
+* This routine performs equilibration scaling of rows and columns of
+* the constraint matrix.
+*
+* If the parameter flag is zero, the routine scales rows at first and
+* then columns. Otherwise, the routine scales columns and then rows.
+*
+* Rows are scaled as follows:
+*
+* n
+* a'[i,j] = a[i,j] / max |a[i,j]|, i = 1,...,m.
+* j=1
+*
+* This makes the infinity (maximum) norm of each row of the matrix
+* equal to 1.
+*
+* Columns are scaled as follows:
+*
+* m
+* a'[i,j] = a[i,j] / max |a[i,j]|, j = 1,...,n.
+* i=1
+*
+* This makes the infinity (maximum) norm of each column of the matrix
+* equal to 1. */
+
+static void eq_scaling(glp_prob *lp, int flag)
+{ int i, j, pass;
+ double temp;
+ xassert(flag == 0 || flag == 1);
+ for (pass = 0; pass <= 1; pass++)
+ { if (pass == flag)
+ { /* scale rows */
+ for (i = 1; i <= lp->m; i++)
+ { temp = max_row_aij(lp, i, 1);
+ glp_set_rii(lp, i, glp_get_rii(lp, i) / temp);
+ }
+ }
+ else
+ { /* scale columns */
+ for (j = 1; j <= lp->n; j++)
+ { temp = max_col_aij(lp, j, 1);
+ glp_set_sjj(lp, j, glp_get_sjj(lp, j) / temp);
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* gm_scaling - perform geometric mean scaling
+*
+* This routine performs geometric mean scaling of rows and columns of
+* the constraint matrix.
+*
+* If the parameter flag is zero, the routine scales rows at first and
+* then columns. Otherwise, the routine scales columns and then rows.
+*
+* Rows are scaled as follows:
+*
+* a'[i,j] = a[i,j] / sqrt(alfa[i] * beta[i]), i = 1,...,m,
+*
+* where:
+* n n
+* alfa[i] = min |a[i,j]|, beta[i] = max |a[i,j]|.
+* j=1 j=1
+*
+* This allows decreasing the ratio beta[i] / alfa[i] for each row of
+* the matrix.
+*
+* Columns are scaled as follows:
+*
+* a'[i,j] = a[i,j] / sqrt(alfa[j] * beta[j]), j = 1,...,n,
+*
+* where:
+* m m
+* alfa[j] = min |a[i,j]|, beta[j] = max |a[i,j]|.
+* i=1 i=1
+*
+* This allows decreasing the ratio beta[j] / alfa[j] for each column
+* of the matrix. */
+
+static void gm_scaling(glp_prob *lp, int flag)
+{ int i, j, pass;
+ double temp;
+ xassert(flag == 0 || flag == 1);
+ for (pass = 0; pass <= 1; pass++)
+ { if (pass == flag)
+ { /* scale rows */
+ for (i = 1; i <= lp->m; i++)
+ { temp = min_row_aij(lp, i, 1) * max_row_aij(lp, i, 1);
+ glp_set_rii(lp, i, glp_get_rii(lp, i) / sqrt(temp));
+ }
+ }
+ else
+ { /* scale columns */
+ for (j = 1; j <= lp->n; j++)
+ { temp = min_col_aij(lp, j, 1) * max_col_aij(lp, j, 1);
+ glp_set_sjj(lp, j, glp_get_sjj(lp, j) / sqrt(temp));
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* max_row_ratio - determine worst scaling "quality" for rows
+*
+* This routine returns the worst scaling "quality" for rows of the
+* currently scaled constraint matrix:
+*
+* m
+* ratio = max ratio[i],
+* i=1
+* where:
+* n n
+* ratio[i] = max |a[i,j]| / min |a[i,j]|, 1 <= i <= m,
+* j=1 j=1
+*
+* is the scaling "quality" of i-th row. */
+
+static double max_row_ratio(glp_prob *lp)
+{ int i;
+ double ratio, temp;
+ ratio = 1.0;
+ for (i = 1; i <= lp->m; i++)
+ { temp = max_row_aij(lp, i, 1) / min_row_aij(lp, i, 1);
+ if (i == 1 || ratio < temp) ratio = temp;
+ }
+ return ratio;
+}
+
+/***********************************************************************
+* max_col_ratio - determine worst scaling "quality" for columns
+*
+* This routine returns the worst scaling "quality" for columns of the
+* currently scaled constraint matrix:
+*
+* n
+* ratio = max ratio[j],
+* j=1
+* where:
+* m m
+* ratio[j] = max |a[i,j]| / min |a[i,j]|, 1 <= j <= n,
+* i=1 i=1
+*
+* is the scaling "quality" of j-th column. */
+
+static double max_col_ratio(glp_prob *lp)
+{ int j;
+ double ratio, temp;
+ ratio = 1.0;
+ for (j = 1; j <= lp->n; j++)
+ { temp = max_col_aij(lp, j, 1) / min_col_aij(lp, j, 1);
+ if (j == 1 || ratio < temp) ratio = temp;
+ }
+ return ratio;
+}
+
+/***********************************************************************
+* gm_iterate - perform iterative geometric mean scaling
+*
+* This routine performs iterative geometric mean scaling of rows and
+* columns of the constraint matrix.
+*
+* The parameter it_max specifies the maximal number of iterations.
+* Recommended value of it_max is 15.
+*
+* The parameter tau specifies a minimal improvement of the scaling
+* "quality" on each iteration, 0 < tau < 1. It means than the scaling
+* process continues while the following condition is satisfied:
+*
+* ratio[k] <= tau * ratio[k-1],
+*
+* where ratio = max |a[i,j]| / min |a[i,j]| is the scaling "quality"
+* to be minimized, k is the iteration number. Recommended value of tau
+* is 0.90. */
+
+static void gm_iterate(glp_prob *lp, int it_max, double tau)
+{ int k, flag;
+ double ratio = 0.0, r_old;
+ /* if the scaling "quality" for rows is better than for columns,
+ the rows are scaled first; otherwise, the columns are scaled
+ first */
+ flag = (max_row_ratio(lp) > max_col_ratio(lp));
+ for (k = 1; k <= it_max; k++)
+ { /* save the scaling "quality" from previous iteration */
+ r_old = ratio;
+ /* determine the current scaling "quality" */
+ ratio = max_mat_aij(lp, 1) / min_mat_aij(lp, 1);
+#if 0
+ xprintf("k = %d; ratio = %g\n", k, ratio);
+#endif
+ /* if improvement is not enough, terminate scaling */
+ if (k > 1 && ratio > tau * r_old) break;
+ /* otherwise, perform another iteration */
+ gm_scaling(lp, flag);
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* scale_prob - scale problem data
+*
+* SYNOPSIS
+*
+* #include "glpscl.h"
+* void scale_prob(glp_prob *lp, int flags);
+*
+* DESCRIPTION
+*
+* The routine scale_prob performs automatic scaling of problem data
+* for the specified problem object. */
+
+static void scale_prob(glp_prob *lp, int flags)
+{ static const char *fmt =
+ "%s: min|aij| = %10.3e max|aij| = %10.3e ratio = %10.3e\n";
+ double min_aij, max_aij, ratio;
+ xprintf("Scaling...\n");
+ /* cancel the current scaling effect */
+ glp_unscale_prob(lp);
+ /* report original scaling "quality" */
+ min_aij = min_mat_aij(lp, 1);
+ max_aij = max_mat_aij(lp, 1);
+ ratio = max_aij / min_aij;
+ xprintf(fmt, " A", min_aij, max_aij, ratio);
+ /* check if the problem is well scaled */
+ if (min_aij >= 0.10 && max_aij <= 10.0)
+ { xprintf("Problem data seem to be well scaled\n");
+ /* skip scaling, if required */
+ if (flags & GLP_SF_SKIP) goto done;
+ }
+ /* perform iterative geometric mean scaling, if required */
+ if (flags & GLP_SF_GM)
+ { gm_iterate(lp, 15, 0.90);
+ min_aij = min_mat_aij(lp, 1);
+ max_aij = max_mat_aij(lp, 1);
+ ratio = max_aij / min_aij;
+ xprintf(fmt, "GM", min_aij, max_aij, ratio);
+ }
+ /* perform equilibration scaling, if required */
+ if (flags & GLP_SF_EQ)
+ { eq_scaling(lp, max_row_ratio(lp) > max_col_ratio(lp));
+ min_aij = min_mat_aij(lp, 1);
+ max_aij = max_mat_aij(lp, 1);
+ ratio = max_aij / min_aij;
+ xprintf(fmt, "EQ", min_aij, max_aij, ratio);
+ }
+ /* round scale factors to nearest power of two, if required */
+ if (flags & GLP_SF_2N)
+ { int i, j;
+ for (i = 1; i <= lp->m; i++)
+ glp_set_rii(lp, i, round2n(glp_get_rii(lp, i)));
+ for (j = 1; j <= lp->n; j++)
+ glp_set_sjj(lp, j, round2n(glp_get_sjj(lp, j)));
+ min_aij = min_mat_aij(lp, 1);
+ max_aij = max_mat_aij(lp, 1);
+ ratio = max_aij / min_aij;
+ xprintf(fmt, "2N", min_aij, max_aij, ratio);
+ }
+done: return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_scale_prob - scale problem data
+*
+* SYNOPSIS
+*
+* void glp_scale_prob(glp_prob *lp, int flags);
+*
+* DESCRIPTION
+*
+* The routine glp_scale_prob performs automatic scaling of problem
+* data for the specified problem object.
+*
+* The parameter flags specifies scaling options used by the routine.
+* Options can be combined with the bitwise OR operator and may be the
+* following:
+*
+* GLP_SF_GM perform geometric mean scaling;
+* GLP_SF_EQ perform equilibration scaling;
+* GLP_SF_2N round scale factors to nearest power of two;
+* GLP_SF_SKIP skip scaling, if the problem is well scaled.
+*
+* The parameter flags may be specified as GLP_SF_AUTO, in which case
+* the routine chooses scaling options automatically. */
+
+void glp_scale_prob(glp_prob *lp, int flags)
+{ if (flags & ~(GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP |
+ GLP_SF_AUTO))
+ xerror("glp_scale_prob: flags = 0x%02X; invalid scaling option"
+ "s\n", flags);
+ if (flags & GLP_SF_AUTO)
+ flags = (GLP_SF_GM | GLP_SF_EQ | GLP_SF_SKIP);
+ scale_prob(lp, flags);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpspm.c b/test/monniaux/glpk-4.65/src/draft/glpspm.c
new file mode 100644
index 00000000..c6cfd25d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpspm.c
@@ -0,0 +1,847 @@
+/* glpspm.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#include "glphbm.h"
+#include "glprgr.h"
+#include "glpspm.h"
+#include "env.h"
+
+/***********************************************************************
+* NAME
+*
+* spm_create_mat - create general sparse matrix
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* SPM *spm_create_mat(int m, int n);
+*
+* DESCRIPTION
+*
+* The routine spm_create_mat creates a general sparse matrix having
+* m rows and n columns. Being created the matrix is zero (empty), i.e.
+* has no elements.
+*
+* RETURNS
+*
+* The routine returns a pointer to the matrix created. */
+
+SPM *spm_create_mat(int m, int n)
+{ SPM *A;
+ xassert(0 <= m && m < INT_MAX);
+ xassert(0 <= n && n < INT_MAX);
+ A = xmalloc(sizeof(SPM));
+ A->m = m;
+ A->n = n;
+ if (m == 0 || n == 0)
+ { A->pool = NULL;
+ A->row = NULL;
+ A->col = NULL;
+ }
+ else
+ { int i, j;
+ A->pool = dmp_create_pool();
+ A->row = xcalloc(1+m, sizeof(SPME *));
+ for (i = 1; i <= m; i++) A->row[i] = NULL;
+ A->col = xcalloc(1+n, sizeof(SPME *));
+ for (j = 1; j <= n; j++) A->col[j] = NULL;
+ }
+ return A;
+}
+
+/***********************************************************************
+* NAME
+*
+* spm_new_elem - add new element to sparse matrix
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* SPME *spm_new_elem(SPM *A, int i, int j, double val);
+*
+* DESCRIPTION
+*
+* The routine spm_new_elem adds a new element to the specified sparse
+* matrix. Parameters i, j, and val specify the row number, the column
+* number, and a numerical value of the element, respectively.
+*
+* RETURNS
+*
+* The routine returns a pointer to the new element added. */
+
+SPME *spm_new_elem(SPM *A, int i, int j, double val)
+{ SPME *e;
+ xassert(1 <= i && i <= A->m);
+ xassert(1 <= j && j <= A->n);
+ e = dmp_get_atom(A->pool, sizeof(SPME));
+ e->i = i;
+ e->j = j;
+ e->val = val;
+ e->r_prev = NULL;
+ e->r_next = A->row[i];
+ if (e->r_next != NULL) e->r_next->r_prev = e;
+ e->c_prev = NULL;
+ e->c_next = A->col[j];
+ if (e->c_next != NULL) e->c_next->c_prev = e;
+ A->row[i] = A->col[j] = e;
+ return e;
+}
+
+/***********************************************************************
+* NAME
+*
+* spm_delete_mat - delete general sparse matrix
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* void spm_delete_mat(SPM *A);
+*
+* DESCRIPTION
+*
+* The routine deletes the specified general sparse matrix freeing all
+* the memory allocated to this object. */
+
+void spm_delete_mat(SPM *A)
+{ /* delete sparse matrix */
+ if (A->pool != NULL) dmp_delete_pool(A->pool);
+ if (A->row != NULL) xfree(A->row);
+ if (A->col != NULL) xfree(A->col);
+ xfree(A);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* spm_test_mat_e - create test sparse matrix of E(n,c) class
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* SPM *spm_test_mat_e(int n, int c);
+*
+* DESCRIPTION
+*
+* The routine spm_test_mat_e creates a test sparse matrix of E(n,c)
+* class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
+* Methods for Sparse Matrices. Springer-Verlag, 1983.
+*
+* Matrix of E(n,c) class is a symmetric positive definite matrix of
+* the order n. It has the number 4 on its main diagonal and the number
+* -1 on its four co-diagonals, two of which are neighbour to the main
+* diagonal and two others are shifted from the main diagonal on the
+* distance c.
+*
+* It is necessary that n >= 3 and 2 <= c <= n-1.
+*
+* RETURNS
+*
+* The routine returns a pointer to the matrix created. */
+
+SPM *spm_test_mat_e(int n, int c)
+{ SPM *A;
+ int i;
+ xassert(n >= 3 && 2 <= c && c <= n-1);
+ A = spm_create_mat(n, n);
+ for (i = 1; i <= n; i++)
+ spm_new_elem(A, i, i, 4.0);
+ for (i = 1; i <= n-1; i++)
+ { spm_new_elem(A, i, i+1, -1.0);
+ spm_new_elem(A, i+1, i, -1.0);
+ }
+ for (i = 1; i <= n-c; i++)
+ { spm_new_elem(A, i, i+c, -1.0);
+ spm_new_elem(A, i+c, i, -1.0);
+ }
+ return A;
+}
+
+/***********************************************************************
+* NAME
+*
+* spm_test_mat_d - create test sparse matrix of D(n,c) class
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* SPM *spm_test_mat_d(int n, int c);
+*
+* DESCRIPTION
+*
+* The routine spm_test_mat_d creates a test sparse matrix of D(n,c)
+* class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
+* Methods for Sparse Matrices. Springer-Verlag, 1983.
+*
+* Matrix of D(n,c) class is a non-singular matrix of the order n. It
+* has unity main diagonal, three co-diagonals above the main diagonal
+* on the distance c, which are cyclically continued below the main
+* diagonal, and a triangle block of the size 10x10 in the upper right
+* corner.
+*
+* It is necessary that n >= 14 and 1 <= c <= n-13.
+*
+* RETURNS
+*
+* The routine returns a pointer to the matrix created. */
+
+SPM *spm_test_mat_d(int n, int c)
+{ SPM *A;
+ int i, j;
+ xassert(n >= 14 && 1 <= c && c <= n-13);
+ A = spm_create_mat(n, n);
+ for (i = 1; i <= n; i++)
+ spm_new_elem(A, i, i, 1.0);
+ for (i = 1; i <= n-c; i++)
+ spm_new_elem(A, i, i+c, (double)(i+1));
+ for (i = n-c+1; i <= n; i++)
+ spm_new_elem(A, i, i-n+c, (double)(i+1));
+ for (i = 1; i <= n-c-1; i++)
+ spm_new_elem(A, i, i+c+1, (double)(-i));
+ for (i = n-c; i <= n; i++)
+ spm_new_elem(A, i, i-n+c+1, (double)(-i));
+ for (i = 1; i <= n-c-2; i++)
+ spm_new_elem(A, i, i+c+2, 16.0);
+ for (i = n-c-1; i <= n; i++)
+ spm_new_elem(A, i, i-n+c+2, 16.0);
+ for (j = 1; j <= 10; j++)
+ for (i = 1; i <= 11-j; i++)
+ spm_new_elem(A, i, n-11+i+j, 100.0 * (double)j);
+ return A;
+}
+
+/***********************************************************************
+* NAME
+*
+* spm_show_mat - write sparse matrix pattern in BMP file format
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* int spm_show_mat(const SPM *A, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine spm_show_mat writes pattern of the specified sparse
+* matrix in uncompressed BMP file format (Windows bitmap) to a binary
+* file whose name is specified by the character string fname.
+*
+* Each pixel corresponds to one matrix element. The pixel colors have
+* the following meaning:
+*
+* Black structurally zero element
+* White positive element
+* Cyan negative element
+* Green zero element
+* Red duplicate element
+*
+* RETURNS
+*
+* If no error occured, the routine returns zero. Otherwise, it prints
+* an appropriate error message and returns non-zero. */
+
+int spm_show_mat(const SPM *A, const char *fname)
+{ int m = A->m;
+ int n = A->n;
+ int i, j, k, ret;
+ char *map;
+ xprintf("spm_show_mat: writing matrix pattern to '%s'...\n",
+ fname);
+ xassert(1 <= m && m <= 32767);
+ xassert(1 <= n && n <= 32767);
+ map = xmalloc(m * n);
+ memset(map, 0x08, m * n);
+ for (i = 1; i <= m; i++)
+ { SPME *e;
+ for (e = A->row[i]; e != NULL; e = e->r_next)
+ { j = e->j;
+ xassert(1 <= j && j <= n);
+ k = n * (i - 1) + (j - 1);
+ if (map[k] != 0x08)
+ map[k] = 0x0C;
+ else if (e->val > 0.0)
+ map[k] = 0x0F;
+ else if (e->val < 0.0)
+ map[k] = 0x0B;
+ else
+ map[k] = 0x0A;
+ }
+ }
+ ret = rgr_write_bmp16(fname, m, n, map);
+ xfree(map);
+ return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* spm_read_hbm - read sparse matrix in Harwell-Boeing format
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* SPM *spm_read_hbm(const char *fname);
+*
+* DESCRIPTION
+*
+* The routine spm_read_hbm reads a sparse matrix in the Harwell-Boeing
+* format from a text file whose name is the character string fname.
+*
+* Detailed description of the Harwell-Boeing format recognised by this
+* routine can be found in the following report:
+*
+* I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
+* Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
+*
+* NOTE
+*
+* The routine spm_read_hbm reads the matrix "as is", due to which zero
+* and/or duplicate elements can appear in the matrix.
+*
+* RETURNS
+*
+* If no error occured, the routine returns a pointer to the matrix
+* created. Otherwise, the routine prints an appropriate error message
+* and returns NULL. */
+
+SPM *spm_read_hbm(const char *fname)
+{ SPM *A = NULL;
+ HBM *hbm;
+ int nrow, ncol, nnzero, i, j, beg, end, ptr, *colptr, *rowind;
+ double val, *values;
+ char *mxtype;
+ hbm = hbm_read_mat(fname);
+ if (hbm == NULL)
+ { xprintf("spm_read_hbm: unable to read matrix\n");
+ goto fini;
+ }
+ mxtype = hbm->mxtype;
+ nrow = hbm->nrow;
+ ncol = hbm->ncol;
+ nnzero = hbm->nnzero;
+ colptr = hbm->colptr;
+ rowind = hbm->rowind;
+ values = hbm->values;
+ if (!(strcmp(mxtype, "RSA") == 0 || strcmp(mxtype, "PSA") == 0 ||
+ strcmp(mxtype, "RUA") == 0 || strcmp(mxtype, "PUA") == 0 ||
+ strcmp(mxtype, "RRA") == 0 || strcmp(mxtype, "PRA") == 0))
+ { xprintf("spm_read_hbm: matrix type '%s' not supported\n",
+ mxtype);
+ goto fini;
+ }
+ A = spm_create_mat(nrow, ncol);
+ if (mxtype[1] == 'S' || mxtype[1] == 'U')
+ xassert(nrow == ncol);
+ for (j = 1; j <= ncol; j++)
+ { beg = colptr[j];
+ end = colptr[j+1];
+ xassert(1 <= beg && beg <= end && end <= nnzero + 1);
+ for (ptr = beg; ptr < end; ptr++)
+ { i = rowind[ptr];
+ xassert(1 <= i && i <= nrow);
+ if (mxtype[0] == 'R')
+ val = values[ptr];
+ else
+ val = 1.0;
+ spm_new_elem(A, i, j, val);
+ if (mxtype[1] == 'S' && i != j)
+ spm_new_elem(A, j, i, val);
+ }
+ }
+fini: if (hbm != NULL) hbm_free_mat(hbm);
+ return A;
+}
+
+/***********************************************************************
+* NAME
+*
+* spm_count_nnz - determine number of non-zeros in sparse matrix
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* int spm_count_nnz(const SPM *A);
+*
+* RETURNS
+*
+* The routine spm_count_nnz returns the number of structural non-zero
+* elements in the specified sparse matrix. */
+
+int spm_count_nnz(const SPM *A)
+{ SPME *e;
+ int i, nnz = 0;
+ for (i = 1; i <= A->m; i++)
+ for (e = A->row[i]; e != NULL; e = e->r_next) nnz++;
+ return nnz;
+}
+
+/***********************************************************************
+* NAME
+*
+* spm_drop_zeros - remove zero elements from sparse matrix
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* int spm_drop_zeros(SPM *A, double eps);
+*
+* DESCRIPTION
+*
+* The routine spm_drop_zeros removes all elements from the specified
+* sparse matrix, whose absolute value is less than eps.
+*
+* If the parameter eps is 0, only zero elements are removed from the
+* matrix.
+*
+* RETURNS
+*
+* The routine returns the number of elements removed. */
+
+int spm_drop_zeros(SPM *A, double eps)
+{ SPME *e, *next;
+ int i, count = 0;
+ for (i = 1; i <= A->m; i++)
+ { for (e = A->row[i]; e != NULL; e = next)
+ { next = e->r_next;
+ if (e->val == 0.0 || fabs(e->val) < eps)
+ { /* remove element from the row list */
+ if (e->r_prev == NULL)
+ A->row[e->i] = e->r_next;
+ else
+ e->r_prev->r_next = e->r_next;
+ if (e->r_next == NULL)
+ ;
+ else
+ e->r_next->r_prev = e->r_prev;
+ /* remove element from the column list */
+ if (e->c_prev == NULL)
+ A->col[e->j] = e->c_next;
+ else
+ e->c_prev->c_next = e->c_next;
+ if (e->c_next == NULL)
+ ;
+ else
+ e->c_next->c_prev = e->c_prev;
+ /* return element to the memory pool */
+ dmp_free_atom(A->pool, e, sizeof(SPME));
+ count++;
+ }
+ }
+ }
+ return count;
+}
+
+/***********************************************************************
+* NAME
+*
+* spm_read_mat - read sparse matrix from text file
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* SPM *spm_read_mat(const char *fname);
+*
+* DESCRIPTION
+*
+* The routine reads a sparse matrix from a text file whose name is
+* specified by the parameter fname.
+*
+* For the file format see description of the routine spm_write_mat.
+*
+* RETURNS
+*
+* On success the routine returns a pointer to the matrix created,
+* otherwise NULL. */
+
+#if 1
+SPM *spm_read_mat(const char *fname)
+{ xassert(fname != fname);
+ return NULL;
+}
+#else
+SPM *spm_read_mat(const char *fname)
+{ SPM *A = NULL;
+ PDS *pds;
+ jmp_buf jump;
+ int i, j, k, m, n, nnz, fail = 0;
+ double val;
+ xprintf("spm_read_mat: reading matrix from '%s'...\n", fname);
+ pds = pds_open_file(fname);
+ if (pds == NULL)
+ { xprintf("spm_read_mat: unable to open '%s' - %s\n", fname,
+ strerror(errno));
+ fail = 1;
+ goto done;
+ }
+ if (setjmp(jump))
+ { fail = 1;
+ goto done;
+ }
+ pds_set_jump(pds, jump);
+ /* number of rows, number of columns, number of non-zeros */
+ m = pds_scan_int(pds);
+ if (m < 0)
+ pds_error(pds, "invalid number of rows\n");
+ n = pds_scan_int(pds);
+ if (n < 0)
+ pds_error(pds, "invalid number of columns\n");
+ nnz = pds_scan_int(pds);
+ if (nnz < 0)
+ pds_error(pds, "invalid number of non-zeros\n");
+ /* create matrix */
+ xprintf("spm_read_mat: %d rows, %d columns, %d non-zeros\n",
+ m, n, nnz);
+ A = spm_create_mat(m, n);
+ /* read matrix elements */
+ for (k = 1; k <= nnz; k++)
+ { /* row index, column index, element value */
+ i = pds_scan_int(pds);
+ if (!(1 <= i && i <= m))
+ pds_error(pds, "row index out of range\n");
+ j = pds_scan_int(pds);
+ if (!(1 <= j && j <= n))
+ pds_error(pds, "column index out of range\n");
+ val = pds_scan_num(pds);
+ /* add new element to the matrix */
+ spm_new_elem(A, i, j, val);
+ }
+ xprintf("spm_read_mat: %d lines were read\n", pds->count);
+done: if (pds != NULL) pds_close_file(pds);
+ if (fail && A != NULL) spm_delete_mat(A), A = NULL;
+ return A;
+}
+#endif
+
+/***********************************************************************
+* NAME
+*
+* spm_write_mat - write sparse matrix to text file
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* int spm_write_mat(const SPM *A, const char *fname);
+*
+* DESCRIPTION
+*
+* The routine spm_write_mat writes the specified sparse matrix to a
+* text file whose name is specified by the parameter fname. This file
+* can be read back with the routine spm_read_mat.
+*
+* RETURNS
+*
+* On success the routine returns zero, otherwise non-zero.
+*
+* FILE FORMAT
+*
+* The file created by the routine spm_write_mat is a plain text file,
+* which contains the following information:
+*
+* m n nnz
+* row[1] col[1] val[1]
+* row[2] col[2] val[2]
+* . . .
+* row[nnz] col[nnz] val[nnz]
+*
+* where:
+* m is the number of rows;
+* n is the number of columns;
+* nnz is the number of non-zeros;
+* row[k], k = 1,...,nnz, are row indices;
+* col[k], k = 1,...,nnz, are column indices;
+* val[k], k = 1,...,nnz, are element values. */
+
+#if 1
+int spm_write_mat(const SPM *A, const char *fname)
+{ xassert(A != A);
+ xassert(fname != fname);
+ return 0;
+}
+#else
+int spm_write_mat(const SPM *A, const char *fname)
+{ FILE *fp;
+ int i, nnz, ret = 0;
+ xprintf("spm_write_mat: writing matrix to '%s'...\n", fname);
+ fp = fopen(fname, "w");
+ if (fp == NULL)
+ { xprintf("spm_write_mat: unable to create '%s' - %s\n", fname,
+ strerror(errno));
+ ret = 1;
+ goto done;
+ }
+ /* number of rows, number of columns, number of non-zeros */
+ nnz = spm_count_nnz(A);
+ fprintf(fp, "%d %d %d\n", A->m, A->n, nnz);
+ /* walk through rows of the matrix */
+ for (i = 1; i <= A->m; i++)
+ { SPME *e;
+ /* walk through elements of i-th row */
+ for (e = A->row[i]; e != NULL; e = e->r_next)
+ { /* row index, column index, element value */
+ fprintf(fp, "%d %d %.*g\n", e->i, e->j, DBL_DIG, e->val);
+ }
+ }
+ fflush(fp);
+ if (ferror(fp))
+ { xprintf("spm_write_mat: writing error on '%s' - %s\n", fname,
+ strerror(errno));
+ ret = 1;
+ goto done;
+ }
+ xprintf("spm_write_mat: %d lines were written\n", 1 + nnz);
+done: if (fp != NULL) fclose(fp);
+ return ret;
+}
+#endif
+
+/***********************************************************************
+* NAME
+*
+* spm_transpose - transpose sparse matrix
+*
+* SYNOPSIS
+*
+* #include "glpspm.h"
+* SPM *spm_transpose(const SPM *A);
+*
+* RETURNS
+*
+* The routine computes and returns sparse matrix B, which is a matrix
+* transposed to sparse matrix A. */
+
+SPM *spm_transpose(const SPM *A)
+{ SPM *B;
+ int i;
+ B = spm_create_mat(A->n, A->m);
+ for (i = 1; i <= A->m; i++)
+ { SPME *e;
+ for (e = A->row[i]; e != NULL; e = e->r_next)
+ spm_new_elem(B, e->j, i, e->val);
+ }
+ return B;
+}
+
+SPM *spm_add_sym(const SPM *A, const SPM *B)
+{ /* add two sparse matrices (symbolic phase) */
+ SPM *C;
+ int i, j, *flag;
+ xassert(A->m == B->m);
+ xassert(A->n == B->n);
+ /* create resultant matrix */
+ C = spm_create_mat(A->m, A->n);
+ /* allocate and clear the flag array */
+ flag = xcalloc(1+C->n, sizeof(int));
+ for (j = 1; j <= C->n; j++)
+ flag[j] = 0;
+ /* compute pattern of C = A + B */
+ for (i = 1; i <= C->m; i++)
+ { SPME *e;
+ /* at the beginning i-th row of C is empty */
+ /* (i-th row of C) := (i-th row of C) union (i-th row of A) */
+ for (e = A->row[i]; e != NULL; e = e->r_next)
+ { /* (note that i-th row of A may have duplicate elements) */
+ j = e->j;
+ if (!flag[j])
+ { spm_new_elem(C, i, j, 0.0);
+ flag[j] = 1;
+ }
+ }
+ /* (i-th row of C) := (i-th row of C) union (i-th row of B) */
+ for (e = B->row[i]; e != NULL; e = e->r_next)
+ { /* (note that i-th row of B may have duplicate elements) */
+ j = e->j;
+ if (!flag[j])
+ { spm_new_elem(C, i, j, 0.0);
+ flag[j] = 1;
+ }
+ }
+ /* reset the flag array */
+ for (e = C->row[i]; e != NULL; e = e->r_next)
+ flag[e->j] = 0;
+ }
+ /* check and deallocate the flag array */
+ for (j = 1; j <= C->n; j++)
+ xassert(!flag[j]);
+ xfree(flag);
+ return C;
+}
+
+void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
+ const SPM *B)
+{ /* add two sparse matrices (numeric phase) */
+ int i, j;
+ double *work;
+ /* allocate and clear the working array */
+ work = xcalloc(1+C->n, sizeof(double));
+ for (j = 1; j <= C->n; j++)
+ work[j] = 0.0;
+ /* compute matrix C = alfa * A + beta * B */
+ for (i = 1; i <= C->n; i++)
+ { SPME *e;
+ /* work := alfa * (i-th row of A) + beta * (i-th row of B) */
+ /* (note that A and/or B may have duplicate elements) */
+ for (e = A->row[i]; e != NULL; e = e->r_next)
+ work[e->j] += alfa * e->val;
+ for (e = B->row[i]; e != NULL; e = e->r_next)
+ work[e->j] += beta * e->val;
+ /* (i-th row of C) := work, work := 0 */
+ for (e = C->row[i]; e != NULL; e = e->r_next)
+ { j = e->j;
+ e->val = work[j];
+ work[j] = 0.0;
+ }
+ }
+ /* check and deallocate the working array */
+ for (j = 1; j <= C->n; j++)
+ xassert(work[j] == 0.0);
+ xfree(work);
+ return;
+}
+
+SPM *spm_add_mat(double alfa, const SPM *A, double beta, const SPM *B)
+{ /* add two sparse matrices (driver routine) */
+ SPM *C;
+ C = spm_add_sym(A, B);
+ spm_add_num(C, alfa, A, beta, B);
+ return C;
+}
+
+SPM *spm_mul_sym(const SPM *A, const SPM *B)
+{ /* multiply two sparse matrices (symbolic phase) */
+ int i, j, k, *flag;
+ SPM *C;
+ xassert(A->n == B->m);
+ /* create resultant matrix */
+ C = spm_create_mat(A->m, B->n);
+ /* allocate and clear the flag array */
+ flag = xcalloc(1+C->n, sizeof(int));
+ for (j = 1; j <= C->n; j++)
+ flag[j] = 0;
+ /* compute pattern of C = A * B */
+ for (i = 1; i <= C->m; i++)
+ { SPME *e, *ee;
+ /* compute pattern of i-th row of C */
+ for (e = A->row[i]; e != NULL; e = e->r_next)
+ { k = e->j;
+ for (ee = B->row[k]; ee != NULL; ee = ee->r_next)
+ { j = ee->j;
+ /* if a[i,k] != 0 and b[k,j] != 0 then c[i,j] != 0 */
+ if (!flag[j])
+ { /* c[i,j] does not exist, so create it */
+ spm_new_elem(C, i, j, 0.0);
+ flag[j] = 1;
+ }
+ }
+ }
+ /* reset the flag array */
+ for (e = C->row[i]; e != NULL; e = e->r_next)
+ flag[e->j] = 0;
+ }
+ /* check and deallocate the flag array */
+ for (j = 1; j <= C->n; j++)
+ xassert(!flag[j]);
+ xfree(flag);
+ return C;
+}
+
+void spm_mul_num(SPM *C, const SPM *A, const SPM *B)
+{ /* multiply two sparse matrices (numeric phase) */
+ int i, j;
+ double *work;
+ /* allocate and clear the working array */
+ work = xcalloc(1+A->n, sizeof(double));
+ for (j = 1; j <= A->n; j++)
+ work[j] = 0.0;
+ /* compute matrix C = A * B */
+ for (i = 1; i <= C->m; i++)
+ { SPME *e, *ee;
+ double temp;
+ /* work := (i-th row of A) */
+ /* (note that A may have duplicate elements) */
+ for (e = A->row[i]; e != NULL; e = e->r_next)
+ work[e->j] += e->val;
+ /* compute i-th row of C */
+ for (e = C->row[i]; e != NULL; e = e->r_next)
+ { j = e->j;
+ /* c[i,j] := work * (j-th column of B) */
+ temp = 0.0;
+ for (ee = B->col[j]; ee != NULL; ee = ee->c_next)
+ temp += work[ee->i] * ee->val;
+ e->val = temp;
+ }
+ /* reset the working array */
+ for (e = A->row[i]; e != NULL; e = e->r_next)
+ work[e->j] = 0.0;
+ }
+ /* check and deallocate the working array */
+ for (j = 1; j <= A->n; j++)
+ xassert(work[j] == 0.0);
+ xfree(work);
+ return;
+}
+
+SPM *spm_mul_mat(const SPM *A, const SPM *B)
+{ /* multiply two sparse matrices (driver routine) */
+ SPM *C;
+ C = spm_mul_sym(A, B);
+ spm_mul_num(C, A, B);
+ return C;
+}
+
+PER *spm_create_per(int n)
+{ /* create permutation matrix */
+ PER *P;
+ int k;
+ xassert(n >= 0);
+ P = xmalloc(sizeof(PER));
+ P->n = n;
+ P->row = xcalloc(1+n, sizeof(int));
+ P->col = xcalloc(1+n, sizeof(int));
+ /* initially it is identity matrix */
+ for (k = 1; k <= n; k++)
+ P->row[k] = P->col[k] = k;
+ return P;
+}
+
+void spm_check_per(PER *P)
+{ /* check permutation matrix for correctness */
+ int i, j;
+ xassert(P->n >= 0);
+ for (i = 1; i <= P->n; i++)
+ { j = P->row[i];
+ xassert(1 <= j && j <= P->n);
+ xassert(P->col[j] == i);
+ }
+ return;
+}
+
+void spm_delete_per(PER *P)
+{ /* delete permutation matrix */
+ xfree(P->row);
+ xfree(P->col);
+ xfree(P);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpspm.h b/test/monniaux/glpk-4.65/src/draft/glpspm.h
new file mode 100644
index 00000000..eda9f98f
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpspm.h
@@ -0,0 +1,165 @@
+/* glpspm.h (general sparse matrix) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#ifndef GLPSPM_H
+#define GLPSPM_H
+
+#include "dmp.h"
+
+typedef struct SPM SPM;
+typedef struct SPME SPME;
+
+struct SPM
+{ /* general sparse matrix */
+ int m;
+ /* number of rows, m >= 0 */
+ int n;
+ /* number of columns, n >= 0 */
+ DMP *pool;
+ /* memory pool to store matrix elements */
+ SPME **row; /* SPME *row[1+m]; */
+ /* row[i], 1 <= i <= m, is a pointer to i-th row list */
+ SPME **col; /* SPME *col[1+n]; */
+ /* col[j], 1 <= j <= n, is a pointer to j-th column list */
+};
+
+struct SPME
+{ /* sparse matrix element */
+ int i;
+ /* row number */
+ int j;
+ /* column number */
+ double val;
+ /* element value */
+ SPME *r_prev;
+ /* pointer to previous element in the same row */
+ SPME *r_next;
+ /* pointer to next element in the same row */
+ SPME *c_prev;
+ /* pointer to previous element in the same column */
+ SPME *c_next;
+ /* pointer to next element in the same column */
+};
+
+typedef struct PER PER;
+
+struct PER
+{ /* permutation matrix */
+ int n;
+ /* matrix order, n >= 0 */
+ int *row; /* int row[1+n]; */
+ /* row[i] = j means p[i,j] = 1 */
+ int *col; /* int col[1+n]; */
+ /* col[j] = i means p[i,j] = 1 */
+};
+
+#define spm_create_mat _glp_spm_create_mat
+SPM *spm_create_mat(int m, int n);
+/* create general sparse matrix */
+
+#define spm_new_elem _glp_spm_new_elem
+SPME *spm_new_elem(SPM *A, int i, int j, double val);
+/* add new element to sparse matrix */
+
+#define spm_delete_mat _glp_spm_delete_mat
+void spm_delete_mat(SPM *A);
+/* delete general sparse matrix */
+
+#define spm_test_mat_e _glp_spm_test_mat_e
+SPM *spm_test_mat_e(int n, int c);
+/* create test sparse matrix of E(n,c) class */
+
+#define spm_test_mat_d _glp_spm_test_mat_d
+SPM *spm_test_mat_d(int n, int c);
+/* create test sparse matrix of D(n,c) class */
+
+#define spm_show_mat _glp_spm_show_mat
+int spm_show_mat(const SPM *A, const char *fname);
+/* write sparse matrix pattern in BMP file format */
+
+#define spm_read_hbm _glp_spm_read_hbm
+SPM *spm_read_hbm(const char *fname);
+/* read sparse matrix in Harwell-Boeing format */
+
+#define spm_count_nnz _glp_spm_count_nnz
+int spm_count_nnz(const SPM *A);
+/* determine number of non-zeros in sparse matrix */
+
+#define spm_drop_zeros _glp_spm_drop_zeros
+int spm_drop_zeros(SPM *A, double eps);
+/* remove zero elements from sparse matrix */
+
+#define spm_read_mat _glp_spm_read_mat
+SPM *spm_read_mat(const char *fname);
+/* read sparse matrix from text file */
+
+#define spm_write_mat _glp_spm_write_mat
+int spm_write_mat(const SPM *A, const char *fname);
+/* write sparse matrix to text file */
+
+#define spm_transpose _glp_spm_transpose
+SPM *spm_transpose(const SPM *A);
+/* transpose sparse matrix */
+
+#define spm_add_sym _glp_spm_add_sym
+SPM *spm_add_sym(const SPM *A, const SPM *B);
+/* add two sparse matrices (symbolic phase) */
+
+#define spm_add_num _glp_spm_add_num
+void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
+ const SPM *B);
+/* add two sparse matrices (numeric phase) */
+
+#define spm_add_mat _glp_spm_add_mat
+SPM *spm_add_mat(double alfa, const SPM *A, double beta,
+ const SPM *B);
+/* add two sparse matrices (driver routine) */
+
+#define spm_mul_sym _glp_spm_mul_sym
+SPM *spm_mul_sym(const SPM *A, const SPM *B);
+/* multiply two sparse matrices (symbolic phase) */
+
+#define spm_mul_num _glp_spm_mul_num
+void spm_mul_num(SPM *C, const SPM *A, const SPM *B);
+/* multiply two sparse matrices (numeric phase) */
+
+#define spm_mul_mat _glp_spm_mul_mat
+SPM *spm_mul_mat(const SPM *A, const SPM *B);
+/* multiply two sparse matrices (driver routine) */
+
+#define spm_create_per _glp_spm_create_per
+PER *spm_create_per(int n);
+/* create permutation matrix */
+
+#define spm_check_per _glp_spm_check_per
+void spm_check_per(PER *P);
+/* check permutation matrix for correctness */
+
+#define spm_delete_per _glp_spm_delete_per
+void spm_delete_per(PER *P);
+/* delete permutation matrix */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpssx.h b/test/monniaux/glpk-4.65/src/draft/glpssx.h
new file mode 100644
index 00000000..3b52b3cc
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpssx.h
@@ -0,0 +1,437 @@
+/* glpssx.h (simplex method, rational arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2017 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/>.
+***********************************************************************/
+
+#ifndef GLPSSX_H
+#define GLPSSX_H
+
+#include "bfx.h"
+#include "env.h"
+#if 1 /* 25/XI-2017 */
+#include "glpk.h"
+#endif
+
+typedef struct SSX SSX;
+
+struct SSX
+{ /* simplex solver workspace */
+/*----------------------------------------------------------------------
+// LP PROBLEM DATA
+//
+// It is assumed that LP problem has the following statement:
+//
+// minimize (or maximize)
+//
+// z = c[1]*x[1] + ... + c[m+n]*x[m+n] + c[0] (1)
+//
+// subject to equality constraints
+//
+// x[1] - a[1,1]*x[m+1] - ... - a[1,n]*x[m+n] = 0
+//
+// . . . . . . . (2)
+//
+// x[m] - a[m,1]*x[m+1] + ... - a[m,n]*x[m+n] = 0
+//
+// and bounds of variables
+//
+// l[1] <= x[1] <= u[1]
+//
+// . . . . . . . (3)
+//
+// l[m+n] <= x[m+n] <= u[m+n]
+//
+// where:
+// x[1], ..., x[m] - auxiliary variables;
+// x[m+1], ..., x[m+n] - structural variables;
+// z - objective function;
+// c[1], ..., c[m+n] - coefficients of the objective function;
+// c[0] - constant term of the objective function;
+// a[1,1], ..., a[m,n] - constraint coefficients;
+// l[1], ..., l[m+n] - lower bounds of variables;
+// u[1], ..., u[m+n] - upper bounds of variables.
+//
+// Bounds of variables can be finite as well as inifinite. Besides,
+// lower and upper bounds can be equal to each other. So the following
+// five types of variables are possible:
+//
+// Bounds of variable Type of variable
+// -------------------------------------------------
+// -inf < x[k] < +inf Free (unbounded) variable
+// l[k] <= x[k] < +inf Variable with lower bound
+// -inf < x[k] <= u[k] Variable with upper bound
+// l[k] <= x[k] <= u[k] Double-bounded variable
+// l[k] = x[k] = u[k] Fixed variable
+//
+// Using vector-matrix notations the LP problem (1)-(3) can be written
+// as follows:
+//
+// minimize (or maximize)
+//
+// z = c * x + c[0] (4)
+//
+// subject to equality constraints
+//
+// xR - A * xS = 0 (5)
+//
+// and bounds of variables
+//
+// l <= x <= u (6)
+//
+// where:
+// xR - vector of auxiliary variables;
+// xS - vector of structural variables;
+// x = (xR, xS) - vector of all variables;
+// z - objective function;
+// c - vector of objective coefficients;
+// c[0] - constant term of the objective function;
+// A - matrix of constraint coefficients (has m rows
+// and n columns);
+// l - vector of lower bounds of variables;
+// u - vector of upper bounds of variables.
+//
+// The simplex method makes no difference between auxiliary and
+// structural variables, so it is convenient to think the system of
+// equality constraints (5) written in a homogeneous form:
+//
+// (I | -A) * x = 0, (7)
+//
+// where (I | -A) is an augmented (m+n)xm constraint matrix, I is mxm
+// unity matrix whose columns correspond to auxiliary variables, and A
+// is the original mxn constraint matrix whose columns correspond to
+// structural variables. Note that only the matrix A is stored.
+----------------------------------------------------------------------*/
+ int m;
+ /* number of rows (auxiliary variables), m > 0 */
+ int n;
+ /* number of columns (structural variables), n > 0 */
+ int *type; /* int type[1+m+n]; */
+ /* type[0] is not used;
+ type[k], 1 <= k <= m+n, is the type of variable x[k]: */
+#define SSX_FR 0 /* free (unbounded) variable */
+#define SSX_LO 1 /* variable with lower bound */
+#define SSX_UP 2 /* variable with upper bound */
+#define SSX_DB 3 /* double-bounded variable */
+#define SSX_FX 4 /* fixed variable */
+ mpq_t *lb; /* mpq_t lb[1+m+n]; alias: l */
+ /* lb[0] is not used;
+ lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
+ if x[k] has no lower bound, lb[k] is zero */
+ mpq_t *ub; /* mpq_t ub[1+m+n]; alias: u */
+ /* ub[0] is not used;
+ ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
+ if x[k] has no upper bound, ub[k] is zero;
+ if x[k] is of fixed type, ub[k] is equal to lb[k] */
+ int dir;
+ /* optimization direction (sense of the objective function): */
+#define SSX_MIN 0 /* minimization */
+#define SSX_MAX 1 /* maximization */
+ mpq_t *coef; /* mpq_t coef[1+m+n]; alias: c */
+ /* coef[0] is a constant term of the objective function;
+ coef[k], 1 <= k <= m+n, is a coefficient of the objective
+ function at variable x[k];
+ note that auxiliary variables also may have non-zero objective
+ coefficients */
+ int *A_ptr; /* int A_ptr[1+n+1]; */
+ int *A_ind; /* int A_ind[A_ptr[n+1]]; */
+ mpq_t *A_val; /* mpq_t A_val[A_ptr[n+1]]; */
+ /* constraint matrix A (see (5)) in storage-by-columns format */
+/*----------------------------------------------------------------------
+// LP BASIS AND CURRENT BASIC SOLUTION
+//
+// The LP basis is defined by the following partition of the augmented
+// constraint matrix (7):
+//
+// (B | N) = (I | -A) * Q, (8)
+//
+// where B is a mxm non-singular basis matrix whose columns correspond
+// to basic variables xB, N is a mxn matrix whose columns correspond to
+// non-basic variables xN, and Q is a permutation (m+n)x(m+n) matrix.
+//
+// From (7) and (8) it follows that
+//
+// (I | -A) * x = (I | -A) * Q * Q' * x = (B | N) * (xB, xN),
+//
+// therefore
+//
+// (xB, xN) = Q' * x, (9)
+//
+// where x is the vector of all variables in the original order, xB is
+// a vector of basic variables, xN is a vector of non-basic variables,
+// Q' = inv(Q) is a matrix transposed to Q.
+//
+// Current values of non-basic variables xN[j], j = 1, ..., n, are not
+// stored; they are defined implicitly by their statuses as follows:
+//
+// 0, if xN[j] is free variable
+// lN[j], if xN[j] is on its lower bound (10)
+// uN[j], if xN[j] is on its upper bound
+// lN[j] = uN[j], if xN[j] is fixed variable
+//
+// where lN[j] and uN[j] are lower and upper bounds of xN[j].
+//
+// Current values of basic variables xB[i], i = 1, ..., m, are computed
+// as follows:
+//
+// beta = - inv(B) * N * xN, (11)
+//
+// where current values of xN are defined by (10).
+//
+// Current values of simplex multipliers pi[i], i = 1, ..., m (which
+// are values of Lagrange multipliers for equality constraints (7) also
+// called shadow prices) are computed as follows:
+//
+// pi = inv(B') * cB, (12)
+//
+// where B' is a matrix transposed to B, cB is a vector of objective
+// coefficients at basic variables xB.
+//
+// Current values of reduced costs d[j], j = 1, ..., n, (which are
+// values of Langrange multipliers for active inequality constraints
+// corresponding to non-basic variables) are computed as follows:
+//
+// d = cN - N' * pi, (13)
+//
+// where N' is a matrix transposed to N, cN is a vector of objective
+// coefficients at non-basic variables xN.
+----------------------------------------------------------------------*/
+ int *stat; /* int stat[1+m+n]; */
+ /* stat[0] is not used;
+ stat[k], 1 <= k <= m+n, is the status of variable x[k]: */
+#define SSX_BS 0 /* basic variable */
+#define SSX_NL 1 /* non-basic variable on lower bound */
+#define SSX_NU 2 /* non-basic variable on upper bound */
+#define SSX_NF 3 /* non-basic free variable */
+#define SSX_NS 4 /* non-basic fixed variable */
+ int *Q_row; /* int Q_row[1+m+n]; */
+ /* matrix Q in row-like format;
+ Q_row[0] is not used;
+ Q_row[i] = j means that q[i,j] = 1 */
+ int *Q_col; /* int Q_col[1+m+n]; */
+ /* matrix Q in column-like format;
+ Q_col[0] is not used;
+ Q_col[j] = i means that q[i,j] = 1 */
+ /* if k-th column of the matrix (I | A) is k'-th column of the
+ matrix (B | N), then Q_row[k] = k' and Q_col[k'] = k;
+ if x[k] is xB[i], then Q_row[k] = i and Q_col[i] = k;
+ if x[k] is xN[j], then Q_row[k] = m+j and Q_col[m+j] = k */
+ BFX *binv;
+ /* invertable form of the basis matrix B */
+ mpq_t *bbar; /* mpq_t bbar[1+m]; alias: beta */
+ /* bbar[0] is a value of the objective function;
+ bbar[i], 1 <= i <= m, is a value of basic variable xB[i] */
+ mpq_t *pi; /* mpq_t pi[1+m]; */
+ /* pi[0] is not used;
+ pi[i], 1 <= i <= m, is a simplex multiplier corresponding to
+ i-th row (equality constraint) */
+ mpq_t *cbar; /* mpq_t cbar[1+n]; alias: d */
+ /* cbar[0] is not used;
+ cbar[j], 1 <= j <= n, is a reduced cost of non-basic variable
+ xN[j] */
+/*----------------------------------------------------------------------
+// SIMPLEX TABLE
+//
+// Due to (8) and (9) the system of equality constraints (7) for the
+// current basis can be written as follows:
+//
+// xB = A~ * xN, (14)
+//
+// where
+//
+// A~ = - inv(B) * N (15)
+//
+// is a mxn matrix called the simplex table.
+//
+// The revised simplex method uses only two components of A~, namely,
+// pivot column corresponding to non-basic variable xN[q] chosen to
+// enter the basis, and pivot row corresponding to basic variable xB[p]
+// chosen to leave the basis.
+//
+// Pivot column alfa_q is q-th column of A~, so
+//
+// alfa_q = A~ * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q], (16)
+//
+// where N[q] is q-th column of the matrix N.
+//
+// Pivot row alfa_p is p-th row of A~ or, equivalently, p-th column of
+// A~', a matrix transposed to A~, so
+//
+// alfa_p = A~' * e[p] = - N' * inv(B') * e[p] = - N' * rho_p, (17)
+//
+// where (*)' means transposition, and
+//
+// rho_p = inv(B') * e[p], (18)
+//
+// is p-th column of inv(B') or, that is the same, p-th row of inv(B).
+----------------------------------------------------------------------*/
+ int p;
+ /* number of basic variable xB[p], 1 <= p <= m, chosen to leave
+ the basis */
+ mpq_t *rho; /* mpq_t rho[1+m]; */
+ /* p-th row of the inverse inv(B); see (18) */
+ mpq_t *ap; /* mpq_t ap[1+n]; */
+ /* p-th row of the simplex table; see (17) */
+ int q;
+ /* number of non-basic variable xN[q], 1 <= q <= n, chosen to
+ enter the basis */
+ mpq_t *aq; /* mpq_t aq[1+m]; */
+ /* q-th column of the simplex table; see (16) */
+/*--------------------------------------------------------------------*/
+ int q_dir;
+ /* direction in which non-basic variable xN[q] should change on
+ moving to the adjacent vertex of the polyhedron:
+ +1 means that xN[q] increases
+ -1 means that xN[q] decreases */
+ int p_stat;
+ /* non-basic status which should be assigned to basic variable
+ xB[p] when it has left the basis and become xN[q] */
+ mpq_t delta;
+ /* actual change of xN[q] in the adjacent basis (it has the same
+ sign as q_dir) */
+/*--------------------------------------------------------------------*/
+#if 1 /* 25/XI-2017 */
+ int msg_lev;
+ /* verbosity level:
+ GLP_MSG_OFF no output
+ GLP_MSG_ERR report errors and warnings
+ GLP_MSG_ON normal output
+ GLP_MSG_ALL highest verbosity */
+#endif
+ int it_lim;
+ /* simplex iterations limit; if this value is positive, it is
+ decreased by one each time when one simplex iteration has been
+ performed, and reaching zero value signals the solver to stop
+ the search; negative value means no iterations limit */
+ int it_cnt;
+ /* simplex iterations count; this count is increased by one each
+ time when one simplex iteration has been performed */
+ double tm_lim;
+ /* searching time limit, in seconds; if this value is positive,
+ it is decreased each time when one simplex iteration has been
+ performed by the amount of time spent for the iteration, and
+ reaching zero value signals the solver to stop the search;
+ negative value means no time limit */
+ double out_frq;
+ /* output frequency, in seconds; this parameter specifies how
+ frequently the solver sends information about the progress of
+ the search to the standard output */
+#if 0 /* 10/VI-2013 */
+ glp_long tm_beg;
+#else
+ double tm_beg;
+#endif
+ /* starting time of the search, in seconds; the total time of the
+ search is the difference between xtime() and tm_beg */
+#if 0 /* 10/VI-2013 */
+ glp_long tm_lag;
+#else
+ double tm_lag;
+#endif
+ /* the most recent time, in seconds, at which the progress of the
+ the search was displayed */
+};
+
+#define ssx_create _glp_ssx_create
+#define ssx_factorize _glp_ssx_factorize
+#define ssx_get_xNj _glp_ssx_get_xNj
+#define ssx_eval_bbar _glp_ssx_eval_bbar
+#define ssx_eval_pi _glp_ssx_eval_pi
+#define ssx_eval_dj _glp_ssx_eval_dj
+#define ssx_eval_cbar _glp_ssx_eval_cbar
+#define ssx_eval_rho _glp_ssx_eval_rho
+#define ssx_eval_row _glp_ssx_eval_row
+#define ssx_eval_col _glp_ssx_eval_col
+#define ssx_chuzc _glp_ssx_chuzc
+#define ssx_chuzr _glp_ssx_chuzr
+#define ssx_update_bbar _glp_ssx_update_bbar
+#define ssx_update_pi _glp_ssx_update_pi
+#define ssx_update_cbar _glp_ssx_update_cbar
+#define ssx_change_basis _glp_ssx_change_basis
+#define ssx_delete _glp_ssx_delete
+
+#define ssx_phase_I _glp_ssx_phase_I
+#define ssx_phase_II _glp_ssx_phase_II
+#define ssx_driver _glp_ssx_driver
+
+SSX *ssx_create(int m, int n, int nnz);
+/* create simplex solver workspace */
+
+int ssx_factorize(SSX *ssx);
+/* factorize the current basis matrix */
+
+void ssx_get_xNj(SSX *ssx, int j, mpq_t x);
+/* determine value of non-basic variable */
+
+void ssx_eval_bbar(SSX *ssx);
+/* compute values of basic variables */
+
+void ssx_eval_pi(SSX *ssx);
+/* compute values of simplex multipliers */
+
+void ssx_eval_dj(SSX *ssx, int j, mpq_t dj);
+/* compute reduced cost of non-basic variable */
+
+void ssx_eval_cbar(SSX *ssx);
+/* compute reduced costs of all non-basic variables */
+
+void ssx_eval_rho(SSX *ssx);
+/* compute p-th row of the inverse */
+
+void ssx_eval_row(SSX *ssx);
+/* compute pivot row of the simplex table */
+
+void ssx_eval_col(SSX *ssx);
+/* compute pivot column of the simplex table */
+
+void ssx_chuzc(SSX *ssx);
+/* choose pivot column */
+
+void ssx_chuzr(SSX *ssx);
+/* choose pivot row */
+
+void ssx_update_bbar(SSX *ssx);
+/* update values of basic variables */
+
+void ssx_update_pi(SSX *ssx);
+/* update simplex multipliers */
+
+void ssx_update_cbar(SSX *ssx);
+/* update reduced costs of non-basic variables */
+
+void ssx_change_basis(SSX *ssx);
+/* change current basis to adjacent one */
+
+void ssx_delete(SSX *ssx);
+/* delete simplex solver workspace */
+
+int ssx_phase_I(SSX *ssx);
+/* find primal feasible solution */
+
+int ssx_phase_II(SSX *ssx);
+/* find optimal solution */
+
+int ssx_driver(SSX *ssx);
+/* base driver to exact simplex method */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpssx01.c b/test/monniaux/glpk-4.65/src/draft/glpssx01.c
new file mode 100644
index 00000000..9b70444e
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpssx01.c
@@ -0,0 +1,839 @@
+/* glpssx01.c (simplex method, rational arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpssx.h"
+#define xfault xerror
+
+/*----------------------------------------------------------------------
+// ssx_create - create simplex solver workspace.
+//
+// This routine creates the workspace used by simplex solver routines,
+// and returns a pointer to it.
+//
+// Parameters m, n, and nnz specify, respectively, the number of rows,
+// columns, and non-zero constraint coefficients.
+//
+// This routine only allocates the memory for the workspace components,
+// so the workspace needs to be saturated by data. */
+
+SSX *ssx_create(int m, int n, int nnz)
+{ SSX *ssx;
+ int i, j, k;
+ if (m < 1)
+ xfault("ssx_create: m = %d; invalid number of rows\n", m);
+ if (n < 1)
+ xfault("ssx_create: n = %d; invalid number of columns\n", n);
+ if (nnz < 0)
+ xfault("ssx_create: nnz = %d; invalid number of non-zero const"
+ "raint coefficients\n", nnz);
+ ssx = xmalloc(sizeof(SSX));
+ ssx->m = m;
+ ssx->n = n;
+ ssx->type = xcalloc(1+m+n, sizeof(int));
+ ssx->lb = xcalloc(1+m+n, sizeof(mpq_t));
+ for (k = 1; k <= m+n; k++) mpq_init(ssx->lb[k]);
+ ssx->ub = xcalloc(1+m+n, sizeof(mpq_t));
+ for (k = 1; k <= m+n; k++) mpq_init(ssx->ub[k]);
+ ssx->coef = xcalloc(1+m+n, sizeof(mpq_t));
+ for (k = 0; k <= m+n; k++) mpq_init(ssx->coef[k]);
+ ssx->A_ptr = xcalloc(1+n+1, sizeof(int));
+ ssx->A_ptr[n+1] = nnz+1;
+ ssx->A_ind = xcalloc(1+nnz, sizeof(int));
+ ssx->A_val = xcalloc(1+nnz, sizeof(mpq_t));
+ for (k = 1; k <= nnz; k++) mpq_init(ssx->A_val[k]);
+ ssx->stat = xcalloc(1+m+n, sizeof(int));
+ ssx->Q_row = xcalloc(1+m+n, sizeof(int));
+ ssx->Q_col = xcalloc(1+m+n, sizeof(int));
+ ssx->binv = bfx_create_binv();
+ ssx->bbar = xcalloc(1+m, sizeof(mpq_t));
+ for (i = 0; i <= m; i++) mpq_init(ssx->bbar[i]);
+ ssx->pi = xcalloc(1+m, sizeof(mpq_t));
+ for (i = 1; i <= m; i++) mpq_init(ssx->pi[i]);
+ ssx->cbar = xcalloc(1+n, sizeof(mpq_t));
+ for (j = 1; j <= n; j++) mpq_init(ssx->cbar[j]);
+ ssx->rho = xcalloc(1+m, sizeof(mpq_t));
+ for (i = 1; i <= m; i++) mpq_init(ssx->rho[i]);
+ ssx->ap = xcalloc(1+n, sizeof(mpq_t));
+ for (j = 1; j <= n; j++) mpq_init(ssx->ap[j]);
+ ssx->aq = xcalloc(1+m, sizeof(mpq_t));
+ for (i = 1; i <= m; i++) mpq_init(ssx->aq[i]);
+ mpq_init(ssx->delta);
+ return ssx;
+}
+
+/*----------------------------------------------------------------------
+// ssx_factorize - factorize the current basis matrix.
+//
+// This routine computes factorization of the current basis matrix B
+// and returns the singularity flag. If the matrix B is non-singular,
+// the flag is zero, otherwise non-zero. */
+
+static int basis_col(void *info, int j, int ind[], mpq_t val[])
+{ /* this auxiliary routine provides row indices and numeric values
+ of non-zero elements in j-th column of the matrix B */
+ SSX *ssx = info;
+ int m = ssx->m;
+ int n = ssx->n;
+ int *A_ptr = ssx->A_ptr;
+ int *A_ind = ssx->A_ind;
+ mpq_t *A_val = ssx->A_val;
+ int *Q_col = ssx->Q_col;
+ int k, len, ptr;
+ xassert(1 <= j && j <= m);
+ k = Q_col[j]; /* x[k] = xB[j] */
+ xassert(1 <= k && k <= m+n);
+ /* j-th column of the matrix B is k-th column of the augmented
+ constraint matrix (I | -A) */
+ if (k <= m)
+ { /* it is a column of the unity matrix I */
+ len = 1, ind[1] = k, mpq_set_si(val[1], 1, 1);
+ }
+ else
+ { /* it is a column of the original constraint matrix -A */
+ len = 0;
+ for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+ { len++;
+ ind[len] = A_ind[ptr];
+ mpq_neg(val[len], A_val[ptr]);
+ }
+ }
+ return len;
+}
+
+int ssx_factorize(SSX *ssx)
+{ int ret;
+ ret = bfx_factorize(ssx->binv, ssx->m, basis_col, ssx);
+ return ret;
+}
+
+/*----------------------------------------------------------------------
+// ssx_get_xNj - determine value of non-basic variable.
+//
+// This routine determines the value of non-basic variable xN[j] in the
+// current basic solution defined as follows:
+//
+// 0, if xN[j] is free variable
+// lN[j], if xN[j] is on its lower bound
+// uN[j], if xN[j] is on its upper bound
+// lN[j] = uN[j], if xN[j] is fixed variable
+//
+// where lN[j] and uN[j] are lower and upper bounds of xN[j]. */
+
+void ssx_get_xNj(SSX *ssx, int j, mpq_t x)
+{ int m = ssx->m;
+ int n = ssx->n;
+ mpq_t *lb = ssx->lb;
+ mpq_t *ub = ssx->ub;
+ int *stat = ssx->stat;
+ int *Q_col = ssx->Q_col;
+ int k;
+ xassert(1 <= j && j <= n);
+ k = Q_col[m+j]; /* x[k] = xN[j] */
+ xassert(1 <= k && k <= m+n);
+ switch (stat[k])
+ { case SSX_NL:
+ /* xN[j] is on its lower bound */
+ mpq_set(x, lb[k]); break;
+ case SSX_NU:
+ /* xN[j] is on its upper bound */
+ mpq_set(x, ub[k]); break;
+ case SSX_NF:
+ /* xN[j] is free variable */
+ mpq_set_si(x, 0, 1); break;
+ case SSX_NS:
+ /* xN[j] is fixed variable */
+ mpq_set(x, lb[k]); break;
+ default:
+ xassert(stat != stat);
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_bbar - compute values of basic variables.
+//
+// This routine computes values of basic variables xB in the current
+// basic solution as follows:
+//
+// beta = - inv(B) * N * xN,
+//
+// where B is the basis matrix, N is the matrix of non-basic columns,
+// xN is a vector of current values of non-basic variables. */
+
+void ssx_eval_bbar(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ mpq_t *coef = ssx->coef;
+ int *A_ptr = ssx->A_ptr;
+ int *A_ind = ssx->A_ind;
+ mpq_t *A_val = ssx->A_val;
+ int *Q_col = ssx->Q_col;
+ mpq_t *bbar = ssx->bbar;
+ int i, j, k, ptr;
+ mpq_t x, temp;
+ mpq_init(x);
+ mpq_init(temp);
+ /* bbar := 0 */
+ for (i = 1; i <= m; i++)
+ mpq_set_si(bbar[i], 0, 1);
+ /* bbar := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n] */
+ for (j = 1; j <= n; j++)
+ { ssx_get_xNj(ssx, j, x);
+ if (mpq_sgn(x) == 0) continue;
+ k = Q_col[m+j]; /* x[k] = xN[j] */
+ if (k <= m)
+ { /* N[j] is a column of the unity matrix I */
+ mpq_sub(bbar[k], bbar[k], x);
+ }
+ else
+ { /* N[j] is a column of the original constraint matrix -A */
+ for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+ { mpq_mul(temp, A_val[ptr], x);
+ mpq_add(bbar[A_ind[ptr]], bbar[A_ind[ptr]], temp);
+ }
+ }
+ }
+ /* bbar := inv(B) * bbar */
+ bfx_ftran(ssx->binv, bbar, 0);
+#if 1
+ /* compute value of the objective function */
+ /* bbar[0] := c[0] */
+ mpq_set(bbar[0], coef[0]);
+ /* bbar[0] := bbar[0] + sum{i in B} cB[i] * xB[i] */
+ for (i = 1; i <= m; i++)
+ { k = Q_col[i]; /* x[k] = xB[i] */
+ if (mpq_sgn(coef[k]) == 0) continue;
+ mpq_mul(temp, coef[k], bbar[i]);
+ mpq_add(bbar[0], bbar[0], temp);
+ }
+ /* bbar[0] := bbar[0] + sum{j in N} cN[j] * xN[j] */
+ for (j = 1; j <= n; j++)
+ { k = Q_col[m+j]; /* x[k] = xN[j] */
+ if (mpq_sgn(coef[k]) == 0) continue;
+ ssx_get_xNj(ssx, j, x);
+ mpq_mul(temp, coef[k], x);
+ mpq_add(bbar[0], bbar[0], temp);
+ }
+#endif
+ mpq_clear(x);
+ mpq_clear(temp);
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_pi - compute values of simplex multipliers.
+//
+// This routine computes values of simplex multipliers (shadow prices)
+// pi in the current basic solution as follows:
+//
+// pi = inv(B') * cB,
+//
+// where B' is a matrix transposed to the basis matrix B, cB is a vector
+// of objective coefficients at basic variables xB. */
+
+void ssx_eval_pi(SSX *ssx)
+{ int m = ssx->m;
+ mpq_t *coef = ssx->coef;
+ int *Q_col = ssx->Q_col;
+ mpq_t *pi = ssx->pi;
+ int i;
+ /* pi := cB */
+ for (i = 1; i <= m; i++) mpq_set(pi[i], coef[Q_col[i]]);
+ /* pi := inv(B') * cB */
+ bfx_btran(ssx->binv, pi);
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_dj - compute reduced cost of non-basic variable.
+//
+// This routine computes reduced cost d[j] of non-basic variable xN[j]
+// in the current basic solution as follows:
+//
+// d[j] = cN[j] - N[j] * pi,
+//
+// where cN[j] is an objective coefficient at xN[j], N[j] is a column
+// of the augmented constraint matrix (I | -A) corresponding to xN[j],
+// pi is the vector of simplex multipliers (shadow prices). */
+
+void ssx_eval_dj(SSX *ssx, int j, mpq_t dj)
+{ int m = ssx->m;
+ int n = ssx->n;
+ mpq_t *coef = ssx->coef;
+ int *A_ptr = ssx->A_ptr;
+ int *A_ind = ssx->A_ind;
+ mpq_t *A_val = ssx->A_val;
+ int *Q_col = ssx->Q_col;
+ mpq_t *pi = ssx->pi;
+ int k, ptr, end;
+ mpq_t temp;
+ mpq_init(temp);
+ xassert(1 <= j && j <= n);
+ k = Q_col[m+j]; /* x[k] = xN[j] */
+ xassert(1 <= k && k <= m+n);
+ /* j-th column of the matrix N is k-th column of the augmented
+ constraint matrix (I | -A) */
+ if (k <= m)
+ { /* it is a column of the unity matrix I */
+ mpq_sub(dj, coef[k], pi[k]);
+ }
+ else
+ { /* it is a column of the original constraint matrix -A */
+ mpq_set(dj, coef[k]);
+ for (ptr = A_ptr[k-m], end = A_ptr[k-m+1]; ptr < end; ptr++)
+ { mpq_mul(temp, A_val[ptr], pi[A_ind[ptr]]);
+ mpq_add(dj, dj, temp);
+ }
+ }
+ mpq_clear(temp);
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_cbar - compute reduced costs of all non-basic variables.
+//
+// This routine computes the vector of reduced costs pi in the current
+// basic solution for all non-basic variables, including fixed ones. */
+
+void ssx_eval_cbar(SSX *ssx)
+{ int n = ssx->n;
+ mpq_t *cbar = ssx->cbar;
+ int j;
+ for (j = 1; j <= n; j++)
+ ssx_eval_dj(ssx, j, cbar[j]);
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_rho - compute p-th row of the inverse.
+//
+// This routine computes p-th row of the matrix inv(B), where B is the
+// current basis matrix.
+//
+// p-th row of the inverse is computed using the following formula:
+//
+// rho = inv(B') * e[p],
+//
+// where B' is a matrix transposed to B, e[p] is a unity vector, which
+// contains one in p-th position. */
+
+void ssx_eval_rho(SSX *ssx)
+{ int m = ssx->m;
+ int p = ssx->p;
+ mpq_t *rho = ssx->rho;
+ int i;
+ xassert(1 <= p && p <= m);
+ /* rho := 0 */
+ for (i = 1; i <= m; i++) mpq_set_si(rho[i], 0, 1);
+ /* rho := e[p] */
+ mpq_set_si(rho[p], 1, 1);
+ /* rho := inv(B') * rho */
+ bfx_btran(ssx->binv, rho);
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_row - compute pivot row of the simplex table.
+//
+// This routine computes p-th (pivot) row of the current simplex table
+// A~ = - inv(B) * N using the following formula:
+//
+// A~[p] = - N' * inv(B') * e[p] = - N' * rho[p],
+//
+// where N' is a matrix transposed to the matrix N, rho[p] is p-th row
+// of the inverse inv(B). */
+
+void ssx_eval_row(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ int *A_ptr = ssx->A_ptr;
+ int *A_ind = ssx->A_ind;
+ mpq_t *A_val = ssx->A_val;
+ int *Q_col = ssx->Q_col;
+ mpq_t *rho = ssx->rho;
+ mpq_t *ap = ssx->ap;
+ int j, k, ptr;
+ mpq_t temp;
+ mpq_init(temp);
+ for (j = 1; j <= n; j++)
+ { /* ap[j] := - N'[j] * rho (inner product) */
+ k = Q_col[m+j]; /* x[k] = xN[j] */
+ if (k <= m)
+ mpq_neg(ap[j], rho[k]);
+ else
+ { mpq_set_si(ap[j], 0, 1);
+ for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+ { mpq_mul(temp, A_val[ptr], rho[A_ind[ptr]]);
+ mpq_add(ap[j], ap[j], temp);
+ }
+ }
+ }
+ mpq_clear(temp);
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_col - compute pivot column of the simplex table.
+//
+// This routine computes q-th (pivot) column of the current simplex
+// table A~ = - inv(B) * N using the following formula:
+//
+// A~[q] = - inv(B) * N[q],
+//
+// where N[q] is q-th column of the matrix N corresponding to chosen
+// non-basic variable xN[q]. */
+
+void ssx_eval_col(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ int *A_ptr = ssx->A_ptr;
+ int *A_ind = ssx->A_ind;
+ mpq_t *A_val = ssx->A_val;
+ int *Q_col = ssx->Q_col;
+ int q = ssx->q;
+ mpq_t *aq = ssx->aq;
+ int i, k, ptr;
+ xassert(1 <= q && q <= n);
+ /* aq := 0 */
+ for (i = 1; i <= m; i++) mpq_set_si(aq[i], 0, 1);
+ /* aq := N[q] */
+ k = Q_col[m+q]; /* x[k] = xN[q] */
+ if (k <= m)
+ { /* N[q] is a column of the unity matrix I */
+ mpq_set_si(aq[k], 1, 1);
+ }
+ else
+ { /* N[q] is a column of the original constraint matrix -A */
+ for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+ mpq_neg(aq[A_ind[ptr]], A_val[ptr]);
+ }
+ /* aq := inv(B) * aq */
+ bfx_ftran(ssx->binv, aq, 1);
+ /* aq := - aq */
+ for (i = 1; i <= m; i++) mpq_neg(aq[i], aq[i]);
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_chuzc - choose pivot column.
+//
+// This routine chooses non-basic variable xN[q] whose reduced cost
+// indicates possible improving of the objective function to enter it
+// in the basis.
+//
+// Currently the standard (textbook) pricing is used, i.e. that
+// non-basic variable is preferred which has greatest reduced cost (in
+// magnitude).
+//
+// If xN[q] has been chosen, the routine stores its number q and also
+// sets the flag q_dir that indicates direction in which xN[q] has to
+// change (+1 means increasing, -1 means decreasing).
+//
+// If the choice cannot be made, because the current basic solution is
+// dual feasible, the routine sets the number q to 0. */
+
+void ssx_chuzc(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ int dir = (ssx->dir == SSX_MIN ? +1 : -1);
+ int *Q_col = ssx->Q_col;
+ int *stat = ssx->stat;
+ mpq_t *cbar = ssx->cbar;
+ int j, k, s, q, q_dir;
+ double best, temp;
+ /* nothing is chosen so far */
+ q = 0, q_dir = 0, best = 0.0;
+ /* look through the list of non-basic variables */
+ for (j = 1; j <= n; j++)
+ { k = Q_col[m+j]; /* x[k] = xN[j] */
+ s = dir * mpq_sgn(cbar[j]);
+ if ((stat[k] == SSX_NF || stat[k] == SSX_NL) && s < 0 ||
+ (stat[k] == SSX_NF || stat[k] == SSX_NU) && s > 0)
+ { /* reduced cost of xN[j] indicates possible improving of
+ the objective function */
+ temp = fabs(mpq_get_d(cbar[j]));
+ xassert(temp != 0.0);
+ if (q == 0 || best < temp)
+ q = j, q_dir = - s, best = temp;
+ }
+ }
+ ssx->q = q, ssx->q_dir = q_dir;
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_chuzr - choose pivot row.
+//
+// This routine looks through elements of q-th column of the simplex
+// table and chooses basic variable xB[p] which should leave the basis.
+//
+// The choice is based on the standard (textbook) ratio test.
+//
+// If xB[p] has been chosen, the routine stores its number p and also
+// sets its non-basic status p_stat which should be assigned to xB[p]
+// when it has left the basis and become xN[q].
+//
+// Special case p < 0 means that xN[q] is double-bounded variable and
+// it reaches its opposite bound before any basic variable does that,
+// so the current basis remains unchanged.
+//
+// If the choice cannot be made, because xN[q] can infinitely change in
+// the feasible direction, the routine sets the number p to 0. */
+
+void ssx_chuzr(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ int *type = ssx->type;
+ mpq_t *lb = ssx->lb;
+ mpq_t *ub = ssx->ub;
+ int *Q_col = ssx->Q_col;
+ mpq_t *bbar = ssx->bbar;
+ int q = ssx->q;
+ mpq_t *aq = ssx->aq;
+ int q_dir = ssx->q_dir;
+ int i, k, s, t, p, p_stat;
+ mpq_t teta, temp;
+ mpq_init(teta);
+ mpq_init(temp);
+ xassert(1 <= q && q <= n);
+ xassert(q_dir == +1 || q_dir == -1);
+ /* nothing is chosen so far */
+ p = 0, p_stat = 0;
+ /* look through the list of basic variables */
+ for (i = 1; i <= m; i++)
+ { s = q_dir * mpq_sgn(aq[i]);
+ if (s < 0)
+ { /* xB[i] decreases */
+ k = Q_col[i]; /* x[k] = xB[i] */
+ t = type[k];
+ if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
+ { /* xB[i] has finite lower bound */
+ mpq_sub(temp, bbar[i], lb[k]);
+ mpq_div(temp, temp, aq[i]);
+ mpq_abs(temp, temp);
+ if (p == 0 || mpq_cmp(teta, temp) > 0)
+ { p = i;
+ p_stat = (t == SSX_FX ? SSX_NS : SSX_NL);
+ mpq_set(teta, temp);
+ }
+ }
+ }
+ else if (s > 0)
+ { /* xB[i] increases */
+ k = Q_col[i]; /* x[k] = xB[i] */
+ t = type[k];
+ if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
+ { /* xB[i] has finite upper bound */
+ mpq_sub(temp, bbar[i], ub[k]);
+ mpq_div(temp, temp, aq[i]);
+ mpq_abs(temp, temp);
+ if (p == 0 || mpq_cmp(teta, temp) > 0)
+ { p = i;
+ p_stat = (t == SSX_FX ? SSX_NS : SSX_NU);
+ mpq_set(teta, temp);
+ }
+ }
+ }
+ /* if something has been chosen and the ratio test indicates
+ exact degeneracy, the search can be finished */
+ if (p != 0 && mpq_sgn(teta) == 0) break;
+ }
+ /* if xN[q] is double-bounded, check if it can reach its opposite
+ bound before any basic variable */
+ k = Q_col[m+q]; /* x[k] = xN[q] */
+ if (type[k] == SSX_DB)
+ { mpq_sub(temp, ub[k], lb[k]);
+ if (p == 0 || mpq_cmp(teta, temp) > 0)
+ { p = -1;
+ p_stat = -1;
+ mpq_set(teta, temp);
+ }
+ }
+ ssx->p = p;
+ ssx->p_stat = p_stat;
+ /* if xB[p] has been chosen, determine its actual change in the
+ adjacent basis (it has the same sign as q_dir) */
+ if (p != 0)
+ { xassert(mpq_sgn(teta) >= 0);
+ if (q_dir > 0)
+ mpq_set(ssx->delta, teta);
+ else
+ mpq_neg(ssx->delta, teta);
+ }
+ mpq_clear(teta);
+ mpq_clear(temp);
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_update_bbar - update values of basic variables.
+//
+// This routine recomputes the current values of basic variables for
+// the adjacent basis.
+//
+// The simplex table for the current basis is the following:
+//
+// xB[i] = sum{j in 1..n} alfa[i,j] * xN[q], i = 1,...,m
+//
+// therefore
+//
+// delta xB[i] = alfa[i,q] * delta xN[q], i = 1,...,m
+//
+// where delta xN[q] = xN.new[q] - xN[q] is the change of xN[q] in the
+// adjacent basis, and delta xB[i] = xB.new[i] - xB[i] is the change of
+// xB[i]. This gives formulae for recomputing values of xB[i]:
+//
+// xB.new[p] = xN[q] + delta xN[q]
+//
+// (because xN[q] becomes xB[p] in the adjacent basis), and
+//
+// xB.new[i] = xB[i] + alfa[i,q] * delta xN[q], i != p
+//
+// for other basic variables. */
+
+void ssx_update_bbar(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ mpq_t *bbar = ssx->bbar;
+ mpq_t *cbar = ssx->cbar;
+ int p = ssx->p;
+ int q = ssx->q;
+ mpq_t *aq = ssx->aq;
+ int i;
+ mpq_t temp;
+ mpq_init(temp);
+ xassert(1 <= q && q <= n);
+ if (p < 0)
+ { /* xN[q] is double-bounded and goes to its opposite bound */
+ /* nop */;
+ }
+ else
+ { /* xN[q] becomes xB[p] in the adjacent basis */
+ /* xB.new[p] = xN[q] + delta xN[q] */
+ xassert(1 <= p && p <= m);
+ ssx_get_xNj(ssx, q, temp);
+ mpq_add(bbar[p], temp, ssx->delta);
+ }
+ /* update values of other basic variables depending on xN[q] */
+ for (i = 1; i <= m; i++)
+ { if (i == p) continue;
+ /* xB.new[i] = xB[i] + alfa[i,q] * delta xN[q] */
+ if (mpq_sgn(aq[i]) == 0) continue;
+ mpq_mul(temp, aq[i], ssx->delta);
+ mpq_add(bbar[i], bbar[i], temp);
+ }
+#if 1
+ /* update value of the objective function */
+ /* z.new = z + d[q] * delta xN[q] */
+ mpq_mul(temp, cbar[q], ssx->delta);
+ mpq_add(bbar[0], bbar[0], temp);
+#endif
+ mpq_clear(temp);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- ssx_update_pi - update simplex multipliers.
+--
+-- This routine recomputes the vector of simplex multipliers for the
+-- adjacent basis. */
+
+void ssx_update_pi(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ mpq_t *pi = ssx->pi;
+ mpq_t *cbar = ssx->cbar;
+ int p = ssx->p;
+ int q = ssx->q;
+ mpq_t *aq = ssx->aq;
+ mpq_t *rho = ssx->rho;
+ int i;
+ mpq_t new_dq, temp;
+ mpq_init(new_dq);
+ mpq_init(temp);
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n);
+ /* compute d[q] in the adjacent basis */
+ mpq_div(new_dq, cbar[q], aq[p]);
+ /* update the vector of simplex multipliers */
+ for (i = 1; i <= m; i++)
+ { if (mpq_sgn(rho[i]) == 0) continue;
+ mpq_mul(temp, new_dq, rho[i]);
+ mpq_sub(pi[i], pi[i], temp);
+ }
+ mpq_clear(new_dq);
+ mpq_clear(temp);
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_update_cbar - update reduced costs of non-basic variables.
+//
+// This routine recomputes the vector of reduced costs of non-basic
+// variables for the adjacent basis. */
+
+void ssx_update_cbar(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ mpq_t *cbar = ssx->cbar;
+ int p = ssx->p;
+ int q = ssx->q;
+ mpq_t *ap = ssx->ap;
+ int j;
+ mpq_t temp;
+ mpq_init(temp);
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n);
+ /* compute d[q] in the adjacent basis */
+ /* d.new[q] = d[q] / alfa[p,q] */
+ mpq_div(cbar[q], cbar[q], ap[q]);
+ /* update reduced costs of other non-basic variables */
+ for (j = 1; j <= n; j++)
+ { if (j == q) continue;
+ /* d.new[j] = d[j] - (alfa[p,j] / alfa[p,q]) * d[q] */
+ if (mpq_sgn(ap[j]) == 0) continue;
+ mpq_mul(temp, ap[j], cbar[q]);
+ mpq_sub(cbar[j], cbar[j], temp);
+ }
+ mpq_clear(temp);
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_change_basis - change current basis to adjacent one.
+//
+// This routine changes the current basis to the adjacent one swapping
+// basic variable xB[p] and non-basic variable xN[q]. */
+
+void ssx_change_basis(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ int *type = ssx->type;
+ int *stat = ssx->stat;
+ int *Q_row = ssx->Q_row;
+ int *Q_col = ssx->Q_col;
+ int p = ssx->p;
+ int q = ssx->q;
+ int p_stat = ssx->p_stat;
+ int k, kp, kq;
+ if (p < 0)
+ { /* special case: xN[q] goes to its opposite bound */
+ xassert(1 <= q && q <= n);
+ k = Q_col[m+q]; /* x[k] = xN[q] */
+ xassert(type[k] == SSX_DB);
+ switch (stat[k])
+ { case SSX_NL:
+ stat[k] = SSX_NU;
+ break;
+ case SSX_NU:
+ stat[k] = SSX_NL;
+ break;
+ default:
+ xassert(stat != stat);
+ }
+ }
+ else
+ { /* xB[p] leaves the basis, xN[q] enters the basis */
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n);
+ kp = Q_col[p]; /* x[kp] = xB[p] */
+ kq = Q_col[m+q]; /* x[kq] = xN[q] */
+ /* check non-basic status of xB[p] which becomes xN[q] */
+ switch (type[kp])
+ { case SSX_FR:
+ xassert(p_stat == SSX_NF);
+ break;
+ case SSX_LO:
+ xassert(p_stat == SSX_NL);
+ break;
+ case SSX_UP:
+ xassert(p_stat == SSX_NU);
+ break;
+ case SSX_DB:
+ xassert(p_stat == SSX_NL || p_stat == SSX_NU);
+ break;
+ case SSX_FX:
+ xassert(p_stat == SSX_NS);
+ break;
+ default:
+ xassert(type != type);
+ }
+ /* swap xB[p] and xN[q] */
+ stat[kp] = (char)p_stat, stat[kq] = SSX_BS;
+ Q_row[kp] = m+q, Q_row[kq] = p;
+ Q_col[p] = kq, Q_col[m+q] = kp;
+ /* update factorization of the basis matrix */
+ if (bfx_update(ssx->binv, p))
+ { if (ssx_factorize(ssx))
+ xassert(("Internal error: basis matrix is singular", 0));
+ }
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_delete - delete simplex solver workspace.
+//
+// This routine deletes the simplex solver workspace freeing all the
+// memory allocated to this object. */
+
+void ssx_delete(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ int nnz = ssx->A_ptr[n+1]-1;
+ int i, j, k;
+ xfree(ssx->type);
+ for (k = 1; k <= m+n; k++) mpq_clear(ssx->lb[k]);
+ xfree(ssx->lb);
+ for (k = 1; k <= m+n; k++) mpq_clear(ssx->ub[k]);
+ xfree(ssx->ub);
+ for (k = 0; k <= m+n; k++) mpq_clear(ssx->coef[k]);
+ xfree(ssx->coef);
+ xfree(ssx->A_ptr);
+ xfree(ssx->A_ind);
+ for (k = 1; k <= nnz; k++) mpq_clear(ssx->A_val[k]);
+ xfree(ssx->A_val);
+ xfree(ssx->stat);
+ xfree(ssx->Q_row);
+ xfree(ssx->Q_col);
+ bfx_delete_binv(ssx->binv);
+ for (i = 0; i <= m; i++) mpq_clear(ssx->bbar[i]);
+ xfree(ssx->bbar);
+ for (i = 1; i <= m; i++) mpq_clear(ssx->pi[i]);
+ xfree(ssx->pi);
+ for (j = 1; j <= n; j++) mpq_clear(ssx->cbar[j]);
+ xfree(ssx->cbar);
+ for (i = 1; i <= m; i++) mpq_clear(ssx->rho[i]);
+ xfree(ssx->rho);
+ for (j = 1; j <= n; j++) mpq_clear(ssx->ap[j]);
+ xfree(ssx->ap);
+ for (i = 1; i <= m; i++) mpq_clear(ssx->aq[i]);
+ xfree(ssx->aq);
+ mpq_clear(ssx->delta);
+ xfree(ssx);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/glpssx02.c b/test/monniaux/glpk-4.65/src/draft/glpssx02.c
new file mode 100644
index 00000000..81db1350
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/glpssx02.c
@@ -0,0 +1,523 @@
+/* glpssx02.c (simplex method, rational arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "glpssx.h"
+
+static void show_progress(SSX *ssx, int phase)
+{ /* this auxiliary routine displays information about progress of
+ the search */
+ int i, def = 0;
+ for (i = 1; i <= ssx->m; i++)
+ if (ssx->type[ssx->Q_col[i]] == SSX_FX) def++;
+ xprintf("%s%6d: %s = %22.15g (%d)\n", phase == 1 ? " " : "*",
+ ssx->it_cnt, phase == 1 ? "infsum" : "objval",
+ mpq_get_d(ssx->bbar[0]), def);
+#if 0
+ ssx->tm_lag = utime();
+#else
+ ssx->tm_lag = xtime();
+#endif
+ return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_phase_I - find primal feasible solution.
+//
+// This routine implements phase I of the primal simplex method.
+//
+// On exit the routine returns one of the following codes:
+//
+// 0 - feasible solution found;
+// 1 - problem has no feasible solution;
+// 2 - iterations limit exceeded;
+// 3 - time limit exceeded.
+----------------------------------------------------------------------*/
+
+int ssx_phase_I(SSX *ssx)
+{ int m = ssx->m;
+ int n = ssx->n;
+ int *type = ssx->type;
+ mpq_t *lb = ssx->lb;
+ mpq_t *ub = ssx->ub;
+ mpq_t *coef = ssx->coef;
+ int *A_ptr = ssx->A_ptr;
+ int *A_ind = ssx->A_ind;
+ mpq_t *A_val = ssx->A_val;
+ int *Q_col = ssx->Q_col;
+ mpq_t *bbar = ssx->bbar;
+ mpq_t *pi = ssx->pi;
+ mpq_t *cbar = ssx->cbar;
+ int *orig_type, orig_dir;
+ mpq_t *orig_lb, *orig_ub, *orig_coef;
+ int i, k, ret;
+ /* save components of the original LP problem, which are changed
+ by the routine */
+ orig_type = xcalloc(1+m+n, sizeof(int));
+ orig_lb = xcalloc(1+m+n, sizeof(mpq_t));
+ orig_ub = xcalloc(1+m+n, sizeof(mpq_t));
+ orig_coef = xcalloc(1+m+n, sizeof(mpq_t));
+ for (k = 1; k <= m+n; k++)
+ { orig_type[k] = type[k];
+ mpq_init(orig_lb[k]);
+ mpq_set(orig_lb[k], lb[k]);
+ mpq_init(orig_ub[k]);
+ mpq_set(orig_ub[k], ub[k]);
+ }
+ orig_dir = ssx->dir;
+ for (k = 0; k <= m+n; k++)
+ { mpq_init(orig_coef[k]);
+ mpq_set(orig_coef[k], coef[k]);
+ }
+ /* build an artificial basic solution, which is primal feasible,
+ and also build an auxiliary objective function to minimize the
+ sum of infeasibilities for the original problem */
+ ssx->dir = SSX_MIN;
+ for (k = 0; k <= m+n; k++) mpq_set_si(coef[k], 0, 1);
+ mpq_set_si(bbar[0], 0, 1);
+ for (i = 1; i <= m; i++)
+ { int t;
+ k = Q_col[i]; /* x[k] = xB[i] */
+ t = type[k];
+ if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
+ { /* in the original problem x[k] has lower bound */
+ if (mpq_cmp(bbar[i], lb[k]) < 0)
+ { /* which is violated */
+ type[k] = SSX_UP;
+ mpq_set(ub[k], lb[k]);
+ mpq_set_si(lb[k], 0, 1);
+ mpq_set_si(coef[k], -1, 1);
+ mpq_add(bbar[0], bbar[0], ub[k]);
+ mpq_sub(bbar[0], bbar[0], bbar[i]);
+ }
+ }
+ if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
+ { /* in the original problem x[k] has upper bound */
+ if (mpq_cmp(bbar[i], ub[k]) > 0)
+ { /* which is violated */
+ type[k] = SSX_LO;
+ mpq_set(lb[k], ub[k]);
+ mpq_set_si(ub[k], 0, 1);
+ mpq_set_si(coef[k], +1, 1);
+ mpq_add(bbar[0], bbar[0], bbar[i]);
+ mpq_sub(bbar[0], bbar[0], lb[k]);
+ }
+ }
+ }
+ /* now the initial basic solution should be primal feasible due
+ to changes of bounds of some basic variables, which turned to
+ implicit artifical variables */
+ /* compute simplex multipliers and reduced costs */
+ ssx_eval_pi(ssx);
+ ssx_eval_cbar(ssx);
+ /* display initial progress of the search */
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ON)
+#endif
+ show_progress(ssx, 1);
+ /* main loop starts here */
+ for (;;)
+ { /* display current progress of the search */
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ON)
+#endif
+#if 0
+ if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001)
+#else
+ if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001)
+#endif
+ show_progress(ssx, 1);
+ /* we do not need to wait until all artificial variables have
+ left the basis */
+ if (mpq_sgn(bbar[0]) == 0)
+ { /* the sum of infeasibilities is zero, therefore the current
+ solution is primal feasible for the original problem */
+ ret = 0;
+ break;
+ }
+ /* check if the iterations limit has been exhausted */
+ if (ssx->it_lim == 0)
+ { ret = 2;
+ break;
+ }
+ /* check if the time limit has been exhausted */
+#if 0
+ if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg)
+#else
+ if (ssx->tm_lim >= 0.0 &&
+ ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg))
+#endif
+ { ret = 3;
+ break;
+ }
+ /* choose non-basic variable xN[q] */
+ ssx_chuzc(ssx);
+ /* if xN[q] cannot be chosen, the sum of infeasibilities is
+ minimal but non-zero; therefore the original problem has no
+ primal feasible solution */
+ if (ssx->q == 0)
+ { ret = 1;
+ break;
+ }
+ /* compute q-th column of the simplex table */
+ ssx_eval_col(ssx);
+ /* choose basic variable xB[p] */
+ ssx_chuzr(ssx);
+ /* the sum of infeasibilities cannot be negative, therefore
+ the auxiliary lp problem cannot have unbounded solution */
+ xassert(ssx->p != 0);
+ /* update values of basic variables */
+ ssx_update_bbar(ssx);
+ if (ssx->p > 0)
+ { /* compute p-th row of the inverse inv(B) */
+ ssx_eval_rho(ssx);
+ /* compute p-th row of the simplex table */
+ ssx_eval_row(ssx);
+ xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0);
+ /* update simplex multipliers */
+ ssx_update_pi(ssx);
+ /* update reduced costs of non-basic variables */
+ ssx_update_cbar(ssx);
+ }
+ /* xB[p] is leaving the basis; if it is implicit artificial
+ variable, the corresponding residual vanishes; therefore
+ bounds of this variable should be restored to the original
+ values */
+ if (ssx->p > 0)
+ { k = Q_col[ssx->p]; /* x[k] = xB[p] */
+ if (type[k] != orig_type[k])
+ { /* x[k] is implicit artificial variable */
+ type[k] = orig_type[k];
+ mpq_set(lb[k], orig_lb[k]);
+ mpq_set(ub[k], orig_ub[k]);
+ xassert(ssx->p_stat == SSX_NL || ssx->p_stat == SSX_NU);
+ ssx->p_stat = (ssx->p_stat == SSX_NL ? SSX_NU : SSX_NL);
+ if (type[k] == SSX_FX) ssx->p_stat = SSX_NS;
+ /* nullify the objective coefficient at x[k] */
+ mpq_set_si(coef[k], 0, 1);
+ /* since coef[k] has been changed, we need to compute
+ new reduced cost of x[k], which it will have in the
+ adjacent basis */
+ /* the formula d[j] = cN[j] - pi' * N[j] is used (note
+ that the vector pi is not changed, because it depends
+ on objective coefficients at basic variables, but in
+ the adjacent basis, for which the vector pi has been
+ just recomputed, x[k] is non-basic) */
+ if (k <= m)
+ { /* x[k] is auxiliary variable */
+ mpq_neg(cbar[ssx->q], pi[k]);
+ }
+ else
+ { /* x[k] is structural variable */
+ int ptr;
+ mpq_t temp;
+ mpq_init(temp);
+ mpq_set_si(cbar[ssx->q], 0, 1);
+ for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+ { mpq_mul(temp, pi[A_ind[ptr]], A_val[ptr]);
+ mpq_add(cbar[ssx->q], cbar[ssx->q], temp);
+ }
+ mpq_clear(temp);
+ }
+ }
+ }
+ /* jump to the adjacent vertex of the polyhedron */
+ ssx_change_basis(ssx);
+ /* one simplex iteration has been performed */
+ if (ssx->it_lim > 0) ssx->it_lim--;
+ ssx->it_cnt++;
+ }
+ /* display final progress of the search */
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ON)
+#endif
+ show_progress(ssx, 1);
+ /* restore components of the original problem, which were changed
+ by the routine */
+ for (k = 1; k <= m+n; k++)
+ { type[k] = orig_type[k];
+ mpq_set(lb[k], orig_lb[k]);
+ mpq_clear(orig_lb[k]);
+ mpq_set(ub[k], orig_ub[k]);
+ mpq_clear(orig_ub[k]);
+ }
+ ssx->dir = orig_dir;
+ for (k = 0; k <= m+n; k++)
+ { mpq_set(coef[k], orig_coef[k]);
+ mpq_clear(orig_coef[k]);
+ }
+ xfree(orig_type);
+ xfree(orig_lb);
+ xfree(orig_ub);
+ xfree(orig_coef);
+ /* return to the calling program */
+ return ret;
+}
+
+/*----------------------------------------------------------------------
+// ssx_phase_II - find optimal solution.
+//
+// This routine implements phase II of the primal simplex method.
+//
+// On exit the routine returns one of the following codes:
+//
+// 0 - optimal solution found;
+// 1 - problem has unbounded solution;
+// 2 - iterations limit exceeded;
+// 3 - time limit exceeded.
+----------------------------------------------------------------------*/
+
+int ssx_phase_II(SSX *ssx)
+{ int ret;
+ /* display initial progress of the search */
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ON)
+#endif
+ show_progress(ssx, 2);
+ /* main loop starts here */
+ for (;;)
+ { /* display current progress of the search */
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ON)
+#endif
+#if 0
+ if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001)
+#else
+ if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001)
+#endif
+ show_progress(ssx, 2);
+ /* check if the iterations limit has been exhausted */
+ if (ssx->it_lim == 0)
+ { ret = 2;
+ break;
+ }
+ /* check if the time limit has been exhausted */
+#if 0
+ if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg)
+#else
+ if (ssx->tm_lim >= 0.0 &&
+ ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg))
+#endif
+ { ret = 3;
+ break;
+ }
+ /* choose non-basic variable xN[q] */
+ ssx_chuzc(ssx);
+ /* if xN[q] cannot be chosen, the current basic solution is
+ dual feasible and therefore optimal */
+ if (ssx->q == 0)
+ { ret = 0;
+ break;
+ }
+ /* compute q-th column of the simplex table */
+ ssx_eval_col(ssx);
+ /* choose basic variable xB[p] */
+ ssx_chuzr(ssx);
+ /* if xB[p] cannot be chosen, the problem has no dual feasible
+ solution (i.e. unbounded) */
+ if (ssx->p == 0)
+ { ret = 1;
+ break;
+ }
+ /* update values of basic variables */
+ ssx_update_bbar(ssx);
+ if (ssx->p > 0)
+ { /* compute p-th row of the inverse inv(B) */
+ ssx_eval_rho(ssx);
+ /* compute p-th row of the simplex table */
+ ssx_eval_row(ssx);
+ xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0);
+#if 0
+ /* update simplex multipliers */
+ ssx_update_pi(ssx);
+#endif
+ /* update reduced costs of non-basic variables */
+ ssx_update_cbar(ssx);
+ }
+ /* jump to the adjacent vertex of the polyhedron */
+ ssx_change_basis(ssx);
+ /* one simplex iteration has been performed */
+ if (ssx->it_lim > 0) ssx->it_lim--;
+ ssx->it_cnt++;
+ }
+ /* display final progress of the search */
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ON)
+#endif
+ show_progress(ssx, 2);
+ /* return to the calling program */
+ return ret;
+}
+
+/*----------------------------------------------------------------------
+// ssx_driver - base driver to exact simplex method.
+//
+// This routine is a base driver to a version of the primal simplex
+// method using exact (bignum) arithmetic.
+//
+// On exit the routine returns one of the following codes:
+//
+// 0 - optimal solution found;
+// 1 - problem has no feasible solution;
+// 2 - problem has unbounded solution;
+// 3 - iterations limit exceeded (phase I);
+// 4 - iterations limit exceeded (phase II);
+// 5 - time limit exceeded (phase I);
+// 6 - time limit exceeded (phase II);
+// 7 - initial basis matrix is exactly singular.
+----------------------------------------------------------------------*/
+
+int ssx_driver(SSX *ssx)
+{ int m = ssx->m;
+ int *type = ssx->type;
+ mpq_t *lb = ssx->lb;
+ mpq_t *ub = ssx->ub;
+ int *Q_col = ssx->Q_col;
+ mpq_t *bbar = ssx->bbar;
+ int i, k, ret;
+ ssx->tm_beg = xtime();
+ /* factorize the initial basis matrix */
+ if (ssx_factorize(ssx))
+#if 0 /* 25/XI-2017 */
+ { xprintf("Initial basis matrix is singular\n");
+#else
+ { if (ssx->msg_lev >= GLP_MSG_ERR)
+ xprintf("Initial basis matrix is singular\n");
+#endif
+ ret = 7;
+ goto done;
+ }
+ /* compute values of basic variables */
+ ssx_eval_bbar(ssx);
+ /* check if the initial basic solution is primal feasible */
+ for (i = 1; i <= m; i++)
+ { int t;
+ k = Q_col[i]; /* x[k] = xB[i] */
+ t = type[k];
+ if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
+ { /* x[k] has lower bound */
+ if (mpq_cmp(bbar[i], lb[k]) < 0)
+ { /* which is violated */
+ break;
+ }
+ }
+ if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
+ { /* x[k] has upper bound */
+ if (mpq_cmp(bbar[i], ub[k]) > 0)
+ { /* which is violated */
+ break;
+ }
+ }
+ }
+ if (i > m)
+ { /* no basic variable violates its bounds */
+ ret = 0;
+ goto skip;
+ }
+ /* phase I: find primal feasible solution */
+ ret = ssx_phase_I(ssx);
+ switch (ret)
+ { case 0:
+ ret = 0;
+ break;
+ case 1:
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ALL)
+#endif
+ xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
+ ret = 1;
+ break;
+ case 2:
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ALL)
+#endif
+ xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n");
+ ret = 3;
+ break;
+ case 3:
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ALL)
+#endif
+ xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+ ret = 5;
+ break;
+ default:
+ xassert(ret != ret);
+ }
+ /* compute values of basic variables (actually only the objective
+ value needs to be computed) */
+ ssx_eval_bbar(ssx);
+skip: /* compute simplex multipliers */
+ ssx_eval_pi(ssx);
+ /* compute reduced costs of non-basic variables */
+ ssx_eval_cbar(ssx);
+ /* if phase I failed, do not start phase II */
+ if (ret != 0) goto done;
+ /* phase II: find optimal solution */
+ ret = ssx_phase_II(ssx);
+ switch (ret)
+ { case 0:
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ALL)
+#endif
+ xprintf("OPTIMAL SOLUTION FOUND\n");
+ ret = 0;
+ break;
+ case 1:
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ALL)
+#endif
+ xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
+ ret = 2;
+ break;
+ case 2:
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ALL)
+#endif
+ xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n");
+ ret = 4;
+ break;
+ case 3:
+#if 1 /* 25/XI-2017 */
+ if (ssx->msg_lev >= GLP_MSG_ALL)
+#endif
+ xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+ ret = 6;
+ break;
+ default:
+ xassert(ret != ret);
+ }
+done: /* decrease the time limit by the spent amount of time */
+ if (ssx->tm_lim >= 0.0)
+#if 0
+ { ssx->tm_lim -= utime() - ssx->tm_beg;
+#else
+ { ssx->tm_lim -= xdifftime(xtime(), ssx->tm_beg);
+#endif
+ if (ssx->tm_lim < 0.0) ssx->tm_lim = 0.0;
+ }
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/ios.h b/test/monniaux/glpk-4.65/src/draft/ios.h
new file mode 100644
index 00000000..1cb07ee0
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/ios.h
@@ -0,0 +1,547 @@
+/* ios.h (integer optimization suite) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013, 2018 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/>.
+***********************************************************************/
+
+#ifndef IOS_H
+#define IOS_H
+
+#include "prob.h"
+
+#if 1 /* 02/II-2018 */
+#define NEW_LOCAL 1
+#endif
+
+#if 1 /* 15/II-2018 */
+#define NEW_COVER 1
+#endif
+
+typedef struct IOSLOT IOSLOT;
+typedef struct IOSNPD IOSNPD;
+typedef struct IOSBND IOSBND;
+typedef struct IOSTAT IOSTAT;
+typedef struct IOSROW IOSROW;
+typedef struct IOSAIJ IOSAIJ;
+#ifdef NEW_LOCAL /* 02/II-2018 */
+typedef glp_prob IOSPOOL;
+typedef GLPROW IOSCUT;
+#else
+typedef struct IOSPOOL IOSPOOL;
+typedef struct IOSCUT IOSCUT;
+#endif
+
+struct glp_tree
+{ /* branch-and-bound tree */
+ int magic;
+ /* magic value used for debugging */
+ DMP *pool;
+ /* memory pool to store all IOS components */
+ int n;
+ /* number of columns (variables) */
+ /*--------------------------------------------------------------*/
+ /* problem components corresponding to the original MIP and its
+ LP relaxation (used to restore the original problem object on
+ exit from the solver) */
+ int orig_m;
+ /* number of rows */
+ unsigned char *orig_type; /* uchar orig_type[1+orig_m+n]; */
+ /* types of all variables */
+ double *orig_lb; /* double orig_lb[1+orig_m+n]; */
+ /* lower bounds of all variables */
+ double *orig_ub; /* double orig_ub[1+orig_m+n]; */
+ /* upper bounds of all variables */
+ unsigned char *orig_stat; /* uchar orig_stat[1+orig_m+n]; */
+ /* statuses of all variables */
+ double *orig_prim; /* double orig_prim[1+orig_m+n]; */
+ /* primal values of all variables */
+ double *orig_dual; /* double orig_dual[1+orig_m+n]; */
+ /* dual values of all variables */
+ double orig_obj;
+ /* optimal objective value for LP relaxation */
+ /*--------------------------------------------------------------*/
+ /* branch-and-bound tree */
+ int nslots;
+ /* length of the array of slots (enlarged automatically) */
+ int avail;
+ /* index of the first free slot; 0 means all slots are in use */
+ IOSLOT *slot; /* IOSLOT slot[1+nslots]; */
+ /* array of slots:
+ slot[0] is not used;
+ slot[p], 1 <= p <= nslots, either contains a pointer to some
+ node of the branch-and-bound tree, in which case p is used on
+ API level as the reference number of corresponding subproblem,
+ or is free; all free slots are linked into single linked list;
+ slot[1] always contains a pointer to the root node (it is free
+ only if the tree is empty) */
+ IOSNPD *head;
+ /* pointer to the head of the active list */
+ IOSNPD *tail;
+ /* pointer to the tail of the active list */
+ /* the active list is a doubly linked list of active subproblems
+ which correspond to leaves of the tree; all subproblems in the
+ active list are ordered chronologically (each a new subproblem
+ is always added to the tail of the list) */
+ int a_cnt;
+ /* current number of active nodes (including the current one) */
+ int n_cnt;
+ /* current number of all (active and inactive) nodes */
+ int t_cnt;
+ /* total number of nodes including those which have been already
+ removed from the tree; this count is increased by one whenever
+ a new node is created and never decreased */
+ /*--------------------------------------------------------------*/
+ /* problem components corresponding to the root subproblem */
+ int root_m;
+ /* number of rows */
+ unsigned char *root_type; /* uchar root_type[1+root_m+n]; */
+ /* types of all variables */
+ double *root_lb; /* double root_lb[1+root_m+n]; */
+ /* lower bounds of all variables */
+ double *root_ub; /* double root_ub[1+root_m+n]; */
+ /* upper bounds of all variables */
+ unsigned char *root_stat; /* uchar root_stat[1+root_m+n]; */
+ /* statuses of all variables */
+ /*--------------------------------------------------------------*/
+ /* current subproblem and its LP relaxation */
+ IOSNPD *curr;
+ /* pointer to the current subproblem (which can be only active);
+ NULL means the current subproblem does not exist */
+ glp_prob *mip;
+ /* original problem object passed to the solver; if the current
+ subproblem exists, its LP segment corresponds to LP relaxation
+ of the current subproblem; if the current subproblem does not
+ exist, its LP segment corresponds to LP relaxation of the root
+ subproblem (note that the root subproblem may differ from the
+ original MIP, because it may be preprocessed and/or may have
+ additional rows) */
+ unsigned char *non_int; /* uchar non_int[1+n]; */
+ /* these column flags are set each time when LP relaxation of the
+ current subproblem has been solved;
+ non_int[0] is not used;
+ non_int[j], 1 <= j <= n, is j-th column flag; if this flag is
+ set, corresponding variable is required to be integer, but its
+ value in basic solution is fractional */
+ /*--------------------------------------------------------------*/
+ /* problem components corresponding to the parent (predecessor)
+ subproblem for the current subproblem; used to inspect changes
+ on freezing the current subproblem */
+ int pred_m;
+ /* number of rows */
+ int pred_max;
+ /* length of the following four arrays (enlarged automatically),
+ pred_max >= pred_m + n */
+ unsigned char *pred_type; /* uchar pred_type[1+pred_m+n]; */
+ /* types of all variables */
+ double *pred_lb; /* double pred_lb[1+pred_m+n]; */
+ /* lower bounds of all variables */
+ double *pred_ub; /* double pred_ub[1+pred_m+n]; */
+ /* upper bounds of all variables */
+ unsigned char *pred_stat; /* uchar pred_stat[1+pred_m+n]; */
+ /* statuses of all variables */
+ /****************************************************************/
+ /* built-in cut generators segment */
+ IOSPOOL *local;
+ /* local cut pool */
+#if 1 /* 13/II-2018 */
+ glp_cov *cov_gen;
+ /* pointer to working area used by the cover cut generator */
+#endif
+ glp_mir *mir_gen;
+ /* pointer to working area used by the MIR cut generator */
+ glp_cfg *clq_gen;
+ /* pointer to conflict graph used by the clique cut generator */
+ /*--------------------------------------------------------------*/
+ void *pcost;
+ /* pointer to working area used on pseudocost branching */
+ int *iwrk; /* int iwrk[1+n]; */
+ /* working array */
+ double *dwrk; /* double dwrk[1+n]; */
+ /* working array */
+ /*--------------------------------------------------------------*/
+ /* control parameters and statistics */
+ const glp_iocp *parm;
+ /* copy of control parameters passed to the solver */
+ double tm_beg;
+ /* starting time of the search, in seconds; the total time of the
+ search is the difference between xtime() and tm_beg */
+ double tm_lag;
+ /* the most recent time, in seconds, at which the progress of the
+ the search was displayed */
+ int sol_cnt;
+ /* number of integer feasible solutions found */
+#if 1 /* 11/VII-2013 */
+ void *P; /* glp_prob *P; */
+ /* problem passed to glp_intopt */
+ void *npp; /* NPP *npp; */
+ /* preprocessor workspace or NULL */
+ const char *save_sol;
+ /* filename (template) to save every new solution */
+ int save_cnt;
+ /* count to generate filename */
+#endif
+ /*--------------------------------------------------------------*/
+ /* advanced solver interface */
+ int reason;
+ /* flag indicating the reason why the callback routine is being
+ called (see glpk.h) */
+ int stop;
+ /* flag indicating that the callback routine requires premature
+ termination of the search */
+ int next_p;
+ /* reference number of active subproblem selected to continue
+ the search; 0 means no subproblem has been selected */
+ int reopt;
+ /* flag indicating that the current LP relaxation needs to be
+ re-optimized */
+ int reinv;
+ /* flag indicating that some (non-active) rows were removed from
+ the current LP relaxation, so if there no new rows appear, the
+ basis must be re-factorized */
+ int br_var;
+ /* the number of variable chosen to branch on */
+ int br_sel;
+ /* flag indicating which branch (subproblem) is suggested to be
+ selected to continue the search:
+ GLP_DN_BRNCH - select down-branch
+ GLP_UP_BRNCH - select up-branch
+ GLP_NO_BRNCH - use general selection technique */
+ int child;
+ /* subproblem reference number corresponding to br_sel */
+};
+
+struct IOSLOT
+{ /* node subproblem slot */
+ IOSNPD *node;
+ /* pointer to subproblem descriptor; NULL means free slot */
+ int next;
+ /* index of another free slot (only if this slot is free) */
+};
+
+struct IOSNPD
+{ /* node subproblem descriptor */
+ int p;
+ /* subproblem reference number (it is the index to corresponding
+ slot, i.e. slot[p] points to this descriptor) */
+ IOSNPD *up;
+ /* pointer to the parent subproblem; NULL means this node is the
+ root of the tree, in which case p = 1 */
+ int level;
+ /* node level (the root node has level 0) */
+ int count;
+ /* if count = 0, this subproblem is active; if count > 0, this
+ subproblem is inactive, in which case count is the number of
+ its child subproblems */
+ /* the following three linked lists are destroyed on reviving and
+ built anew on freezing the subproblem: */
+ IOSBND *b_ptr;
+ /* linked list of rows and columns of the parent subproblem whose
+ types and bounds were changed */
+ IOSTAT *s_ptr;
+ /* linked list of rows and columns of the parent subproblem whose
+ statuses were changed */
+ IOSROW *r_ptr;
+ /* linked list of rows (cuts) added to the parent subproblem */
+ int solved;
+ /* how many times LP relaxation of this subproblem was solved;
+ for inactive subproblem this count is always non-zero;
+ for active subproblem, which is not current, this count may be
+ non-zero, if the subproblem was temporarily suspended */
+ double lp_obj;
+ /* optimal objective value to LP relaxation of this subproblem;
+ on creating a subproblem this value is inherited from its
+ parent; for the root subproblem, which has no parent, this
+ value is initially set to -DBL_MAX (minimization) or +DBL_MAX
+ (maximization); each time the subproblem is re-optimized, this
+ value is appropriately changed */
+ double bound;
+ /* local lower (minimization) or upper (maximization) bound for
+ integer optimal solution to *this* subproblem; this bound is
+ local in the sense that only subproblems in the subtree rooted
+ at this node cannot have better integer feasible solutions;
+ on creating a subproblem its local bound is inherited from its
+ parent and then can be made stronger (never weaker); for the
+ root subproblem its local bound is initially set to -DBL_MAX
+ (minimization) or +DBL_MAX (maximization) and then improved as
+ the root LP relaxation has been solved */
+ /* the following two quantities are defined only if LP relaxation
+ of this subproblem was solved at least once (solved > 0): */
+ int ii_cnt;
+ /* number of integer variables whose value in optimal solution to
+ LP relaxation of this subproblem is fractional */
+ double ii_sum;
+ /* sum of integer infeasibilities */
+#if 1 /* 30/XI-2009 */
+ int changed;
+ /* how many times this subproblem was re-formulated (by adding
+ cutting plane constraints) */
+#endif
+ int br_var;
+ /* ordinal number of branching variable, 1 <= br_var <= n, used
+ to split this subproblem; 0 means that either this subproblem
+ is active or branching was made on a constraint */
+ double br_val;
+ /* (fractional) value of branching variable in optimal solution
+ to final LP relaxation of this subproblem */
+ void *data; /* char data[tree->cb_size]; */
+ /* pointer to the application-specific data */
+ IOSNPD *temp;
+ /* working pointer used by some routines */
+ IOSNPD *prev;
+ /* pointer to previous subproblem in the active list */
+ IOSNPD *next;
+ /* pointer to next subproblem in the active list */
+};
+
+struct IOSBND
+{ /* bounds change entry */
+ int k;
+ /* ordinal number of corresponding row (1 <= k <= m) or column
+ (m+1 <= k <= m+n), where m and n are the number of rows and
+ columns, resp., in the parent subproblem */
+ unsigned char type;
+ /* new type */
+ double lb;
+ /* new lower bound */
+ double ub;
+ /* new upper bound */
+ IOSBND *next;
+ /* pointer to next entry for the same subproblem */
+};
+
+struct IOSTAT
+{ /* status change entry */
+ int k;
+ /* ordinal number of corresponding row (1 <= k <= m) or column
+ (m+1 <= k <= m+n), where m and n are the number of rows and
+ columns, resp., in the parent subproblem */
+ unsigned char stat;
+ /* new status */
+ IOSTAT *next;
+ /* pointer to next entry for the same subproblem */
+};
+
+struct IOSROW
+{ /* row (constraint) addition entry */
+ char *name;
+ /* row name or NULL */
+ unsigned char origin;
+ /* row origin flag (see glp_attr.origin) */
+ unsigned char klass;
+ /* row class descriptor (see glp_attr.klass) */
+ unsigned char type;
+ /* row type (GLP_LO, GLP_UP, etc.) */
+ double lb;
+ /* row lower bound */
+ double ub;
+ /* row upper bound */
+ IOSAIJ *ptr;
+ /* pointer to the row coefficient list */
+ double rii;
+ /* row scale factor */
+ unsigned char stat;
+ /* row status (GLP_BS, GLP_NL, etc.) */
+ IOSROW *next;
+ /* pointer to next entry for the same subproblem */
+};
+
+struct IOSAIJ
+{ /* constraint coefficient */
+ int j;
+ /* variable (column) number, 1 <= j <= n */
+ double val;
+ /* non-zero coefficient value */
+ IOSAIJ *next;
+ /* pointer to next coefficient for the same row */
+};
+
+#ifndef NEW_LOCAL /* 02/II-2018 */
+struct IOSPOOL
+{ /* cut pool */
+ int size;
+ /* pool size = number of cuts in the pool */
+ IOSCUT *head;
+ /* pointer to the first cut */
+ IOSCUT *tail;
+ /* pointer to the last cut */
+ int ord;
+ /* ordinal number of the current cut, 1 <= ord <= size */
+ IOSCUT *curr;
+ /* pointer to the current cut */
+};
+#endif
+
+#ifndef NEW_LOCAL /* 02/II-2018 */
+struct IOSCUT
+{ /* cut (cutting plane constraint) */
+ char *name;
+ /* cut name or NULL */
+ unsigned char klass;
+ /* cut class descriptor (see glp_attr.klass) */
+ IOSAIJ *ptr;
+ /* pointer to the cut coefficient list */
+ unsigned char type;
+ /* cut type:
+ GLP_LO: sum a[j] * x[j] >= b
+ GLP_UP: sum a[j] * x[j] <= b
+ GLP_FX: sum a[j] * x[j] = b */
+ double rhs;
+ /* cut right-hand side */
+ IOSCUT *prev;
+ /* pointer to previous cut */
+ IOSCUT *next;
+ /* pointer to next cut */
+};
+#endif
+
+#define ios_create_tree _glp_ios_create_tree
+glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
+/* create branch-and-bound tree */
+
+#define ios_revive_node _glp_ios_revive_node
+void ios_revive_node(glp_tree *tree, int p);
+/* revive specified subproblem */
+
+#define ios_freeze_node _glp_ios_freeze_node
+void ios_freeze_node(glp_tree *tree);
+/* freeze current subproblem */
+
+#define ios_clone_node _glp_ios_clone_node
+void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
+/* clone specified subproblem */
+
+#define ios_delete_node _glp_ios_delete_node
+void ios_delete_node(glp_tree *tree, int p);
+/* delete specified subproblem */
+
+#define ios_delete_tree _glp_ios_delete_tree
+void ios_delete_tree(glp_tree *tree);
+/* delete branch-and-bound tree */
+
+#define ios_eval_degrad _glp_ios_eval_degrad
+void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
+/* estimate obj. degrad. for down- and up-branches */
+
+#define ios_round_bound _glp_ios_round_bound
+double ios_round_bound(glp_tree *tree, double bound);
+/* improve local bound by rounding */
+
+#define ios_is_hopeful _glp_ios_is_hopeful
+int ios_is_hopeful(glp_tree *tree, double bound);
+/* check if subproblem is hopeful */
+
+#define ios_best_node _glp_ios_best_node
+int ios_best_node(glp_tree *tree);
+/* find active node with best local bound */
+
+#define ios_relative_gap _glp_ios_relative_gap
+double ios_relative_gap(glp_tree *tree);
+/* compute relative mip gap */
+
+#define ios_solve_node _glp_ios_solve_node
+int ios_solve_node(glp_tree *tree);
+/* solve LP relaxation of current subproblem */
+
+#define ios_create_pool _glp_ios_create_pool
+IOSPOOL *ios_create_pool(glp_tree *tree);
+/* create cut pool */
+
+#define ios_add_row _glp_ios_add_row
+int ios_add_row(glp_tree *tree, IOSPOOL *pool,
+ const char *name, int klass, int flags, int len, const int ind[],
+ const double val[], int type, double rhs);
+/* add row (constraint) to the cut pool */
+
+#define ios_find_row _glp_ios_find_row
+IOSCUT *ios_find_row(IOSPOOL *pool, int i);
+/* find row (constraint) in the cut pool */
+
+#define ios_del_row _glp_ios_del_row
+void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i);
+/* remove row (constraint) from the cut pool */
+
+#define ios_clear_pool _glp_ios_clear_pool
+void ios_clear_pool(glp_tree *tree, IOSPOOL *pool);
+/* remove all rows (constraints) from the cut pool */
+
+#define ios_delete_pool _glp_ios_delete_pool
+void ios_delete_pool(glp_tree *tree, IOSPOOL *pool);
+/* delete cut pool */
+
+#if 1 /* 11/VII-2013 */
+#define ios_process_sol _glp_ios_process_sol
+void ios_process_sol(glp_tree *T);
+/* process integer feasible solution just found */
+#endif
+
+#define ios_preprocess_node _glp_ios_preprocess_node
+int ios_preprocess_node(glp_tree *tree, int max_pass);
+/* preprocess current subproblem */
+
+#define ios_driver _glp_ios_driver
+int ios_driver(glp_tree *tree);
+/* branch-and-bound driver */
+
+#define ios_cov_gen _glp_ios_cov_gen
+void ios_cov_gen(glp_tree *tree);
+/* generate mixed cover cuts */
+
+#define ios_pcost_init _glp_ios_pcost_init
+void *ios_pcost_init(glp_tree *tree);
+/* initialize working data used on pseudocost branching */
+
+#define ios_pcost_branch _glp_ios_pcost_branch
+int ios_pcost_branch(glp_tree *T, int *next);
+/* choose branching variable with pseudocost branching */
+
+#define ios_pcost_update _glp_ios_pcost_update
+void ios_pcost_update(glp_tree *tree);
+/* update history information for pseudocost branching */
+
+#define ios_pcost_free _glp_ios_pcost_free
+void ios_pcost_free(glp_tree *tree);
+/* free working area used on pseudocost branching */
+
+#define ios_feas_pump _glp_ios_feas_pump
+void ios_feas_pump(glp_tree *T);
+/* feasibility pump heuristic */
+
+#if 1 /* 25/V-2013 */
+#define ios_proxy_heur _glp_ios_proxy_heur
+void ios_proxy_heur(glp_tree *T);
+/* proximity search heuristic */
+#endif
+
+#define ios_process_cuts _glp_ios_process_cuts
+void ios_process_cuts(glp_tree *T);
+/* process cuts stored in the local cut pool */
+
+#define ios_choose_node _glp_ios_choose_node
+int ios_choose_node(glp_tree *T);
+/* select subproblem to continue the search */
+
+#define ios_choose_var _glp_ios_choose_var
+int ios_choose_var(glp_tree *T, int *next);
+/* select variable to branch on */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/lux.c b/test/monniaux/glpk-4.65/src/draft/lux.c
new file mode 100644
index 00000000..38cb758c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/lux.c
@@ -0,0 +1,1030 @@
+/* lux.c (LU-factorization, rational arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "lux.h"
+
+#define xfault xerror
+#define dmp_create_poolx(size) dmp_create_pool()
+
+/***********************************************************************
+* lux_create - create LU-factorization
+*
+* SYNOPSIS
+*
+* #include "lux.h"
+* LUX *lux_create(int n);
+*
+* DESCRIPTION
+*
+* The routine lux_create creates LU-factorization data structure for
+* a matrix of the order n. Initially the factorization corresponds to
+* the unity matrix (F = V = P = Q = I, so A = I).
+*
+* RETURNS
+*
+* The routine returns a pointer to the created LU-factorization data
+* structure, which represents the unity matrix of the order n. */
+
+LUX *lux_create(int n)
+{ LUX *lux;
+ int k;
+ if (n < 1)
+ xfault("lux_create: n = %d; invalid parameter\n", n);
+ lux = xmalloc(sizeof(LUX));
+ lux->n = n;
+ lux->pool = dmp_create_poolx(sizeof(LUXELM));
+ lux->F_row = xcalloc(1+n, sizeof(LUXELM *));
+ lux->F_col = xcalloc(1+n, sizeof(LUXELM *));
+ lux->V_piv = xcalloc(1+n, sizeof(mpq_t));
+ lux->V_row = xcalloc(1+n, sizeof(LUXELM *));
+ lux->V_col = xcalloc(1+n, sizeof(LUXELM *));
+ lux->P_row = xcalloc(1+n, sizeof(int));
+ lux->P_col = xcalloc(1+n, sizeof(int));
+ lux->Q_row = xcalloc(1+n, sizeof(int));
+ lux->Q_col = xcalloc(1+n, sizeof(int));
+ for (k = 1; k <= n; k++)
+ { lux->F_row[k] = lux->F_col[k] = NULL;
+ mpq_init(lux->V_piv[k]);
+ mpq_set_si(lux->V_piv[k], 1, 1);
+ lux->V_row[k] = lux->V_col[k] = NULL;
+ lux->P_row[k] = lux->P_col[k] = k;
+ lux->Q_row[k] = lux->Q_col[k] = k;
+ }
+ lux->rank = n;
+ return lux;
+}
+
+/***********************************************************************
+* initialize - initialize LU-factorization data structures
+*
+* This routine initializes data structures for subsequent computing
+* the LU-factorization of a given matrix A, which is specified by the
+* formal routine col. On exit V = A and F = P = Q = I, where I is the
+* unity matrix. */
+
+static void initialize(LUX *lux, int (*col)(void *info, int j,
+ int ind[], mpq_t val[]), void *info, LUXWKA *wka)
+{ int n = lux->n;
+ DMP *pool = lux->pool;
+ LUXELM **F_row = lux->F_row;
+ LUXELM **F_col = lux->F_col;
+ mpq_t *V_piv = lux->V_piv;
+ LUXELM **V_row = lux->V_row;
+ LUXELM **V_col = lux->V_col;
+ int *P_row = lux->P_row;
+ int *P_col = lux->P_col;
+ int *Q_row = lux->Q_row;
+ int *Q_col = lux->Q_col;
+ int *R_len = wka->R_len;
+ int *R_head = wka->R_head;
+ int *R_prev = wka->R_prev;
+ int *R_next = wka->R_next;
+ int *C_len = wka->C_len;
+ int *C_head = wka->C_head;
+ int *C_prev = wka->C_prev;
+ int *C_next = wka->C_next;
+ LUXELM *fij, *vij;
+ int i, j, k, len, *ind;
+ mpq_t *val;
+ /* F := I */
+ for (i = 1; i <= n; i++)
+ { while (F_row[i] != NULL)
+ { fij = F_row[i], F_row[i] = fij->r_next;
+ mpq_clear(fij->val);
+ dmp_free_atom(pool, fij, sizeof(LUXELM));
+ }
+ }
+ for (j = 1; j <= n; j++) F_col[j] = NULL;
+ /* V := 0 */
+ for (k = 1; k <= n; k++) mpq_set_si(V_piv[k], 0, 1);
+ for (i = 1; i <= n; i++)
+ { while (V_row[i] != NULL)
+ { vij = V_row[i], V_row[i] = vij->r_next;
+ mpq_clear(vij->val);
+ dmp_free_atom(pool, vij, sizeof(LUXELM));
+ }
+ }
+ for (j = 1; j <= n; j++) V_col[j] = NULL;
+ /* V := A */
+ ind = xcalloc(1+n, sizeof(int));
+ val = xcalloc(1+n, sizeof(mpq_t));
+ for (k = 1; k <= n; k++) mpq_init(val[k]);
+ for (j = 1; j <= n; j++)
+ { /* obtain j-th column of matrix A */
+ len = col(info, j, ind, val);
+ if (!(0 <= len && len <= n))
+ xfault("lux_decomp: j = %d: len = %d; invalid column length"
+ "\n", j, len);
+ /* copy elements of j-th column to matrix V */
+ for (k = 1; k <= len; k++)
+ { /* get row index of a[i,j] */
+ i = ind[k];
+ if (!(1 <= i && i <= n))
+ xfault("lux_decomp: j = %d: i = %d; row index out of ran"
+ "ge\n", j, i);
+ /* check for duplicate indices */
+ if (V_row[i] != NULL && V_row[i]->j == j)
+ xfault("lux_decomp: j = %d: i = %d; duplicate row indice"
+ "s not allowed\n", j, i);
+ /* check for zero value */
+ if (mpq_sgn(val[k]) == 0)
+ xfault("lux_decomp: j = %d: i = %d; zero elements not al"
+ "lowed\n", j, i);
+ /* add new element v[i,j] = a[i,j] to V */
+ vij = dmp_get_atom(pool, sizeof(LUXELM));
+ vij->i = i, vij->j = j;
+ mpq_init(vij->val);
+ mpq_set(vij->val, val[k]);
+ vij->r_prev = NULL;
+ vij->r_next = V_row[i];
+ vij->c_prev = NULL;
+ vij->c_next = V_col[j];
+ if (vij->r_next != NULL) vij->r_next->r_prev = vij;
+ if (vij->c_next != NULL) vij->c_next->c_prev = vij;
+ V_row[i] = V_col[j] = vij;
+ }
+ }
+ xfree(ind);
+ for (k = 1; k <= n; k++) mpq_clear(val[k]);
+ xfree(val);
+ /* P := Q := I */
+ for (k = 1; k <= n; k++)
+ P_row[k] = P_col[k] = Q_row[k] = Q_col[k] = k;
+ /* the rank of A and V is not determined yet */
+ lux->rank = -1;
+ /* initially the entire matrix V is active */
+ /* determine its row lengths */
+ for (i = 1; i <= n; i++)
+ { len = 0;
+ for (vij = V_row[i]; vij != NULL; vij = vij->r_next) len++;
+ R_len[i] = len;
+ }
+ /* build linked lists of active rows */
+ for (len = 0; len <= n; len++) R_head[len] = 0;
+ for (i = 1; i <= n; i++)
+ { len = R_len[i];
+ R_prev[i] = 0;
+ R_next[i] = R_head[len];
+ if (R_next[i] != 0) R_prev[R_next[i]] = i;
+ R_head[len] = i;
+ }
+ /* determine its column lengths */
+ for (j = 1; j <= n; j++)
+ { len = 0;
+ for (vij = V_col[j]; vij != NULL; vij = vij->c_next) len++;
+ C_len[j] = len;
+ }
+ /* build linked lists of active columns */
+ for (len = 0; len <= n; len++) C_head[len] = 0;
+ for (j = 1; j <= n; j++)
+ { len = C_len[j];
+ C_prev[j] = 0;
+ C_next[j] = C_head[len];
+ if (C_next[j] != 0) C_prev[C_next[j]] = j;
+ C_head[len] = j;
+ }
+ return;
+}
+
+/***********************************************************************
+* find_pivot - choose a pivot element
+*
+* This routine chooses a pivot element v[p,q] in the active submatrix
+* of matrix U = P*V*Q.
+*
+* It is assumed that on entry the matrix U has the following partially
+* triangularized form:
+*
+* 1 k n
+* 1 x x x x x x x x x x
+* . x x x x x x x x x
+* . . x x x x x x x x
+* . . . x x x x x x x
+* k . . . . * * * * * *
+* . . . . * * * * * *
+* . . . . * * * * * *
+* . . . . * * * * * *
+* . . . . * * * * * *
+* n . . . . * * * * * *
+*
+* where rows and columns k, k+1, ..., n belong to the active submatrix
+* (elements of the active submatrix are marked by '*').
+*
+* Since the matrix U = P*V*Q is not stored, the routine works with the
+* matrix V. It is assumed that the row-wise representation corresponds
+* to the matrix V, but the column-wise representation corresponds to
+* the active submatrix of the matrix V, i.e. elements of the matrix V,
+* which does not belong to the active submatrix, are missing from the
+* column linked lists. It is also assumed that each active row of the
+* matrix V is in the set R[len], where len is number of non-zeros in
+* the row, and each active column of the matrix V is in the set C[len],
+* where len is number of non-zeros in the column (in the latter case
+* only elements of the active submatrix are counted; such elements are
+* marked by '*' on the figure above).
+*
+* Due to exact arithmetic any non-zero element of the active submatrix
+* can be chosen as a pivot. However, to keep sparsity of the matrix V
+* the routine uses Markowitz strategy, trying to choose such element
+* v[p,q], which has smallest Markowitz cost (nr[p]-1) * (nc[q]-1),
+* where nr[p] and nc[q] are the number of non-zero elements, resp., in
+* p-th row and in q-th column of the active submatrix.
+*
+* In order to reduce the search, i.e. not to walk through all elements
+* of the active submatrix, the routine exploits a technique proposed by
+* I.Duff. This technique is based on using the sets R[len] and C[len]
+* of active rows and columns.
+*
+* On exit the routine returns a pointer to a pivot v[p,q] chosen, or
+* NULL, if the active submatrix is empty. */
+
+static LUXELM *find_pivot(LUX *lux, LUXWKA *wka)
+{ int n = lux->n;
+ LUXELM **V_row = lux->V_row;
+ LUXELM **V_col = lux->V_col;
+ int *R_len = wka->R_len;
+ int *R_head = wka->R_head;
+ int *R_next = wka->R_next;
+ int *C_len = wka->C_len;
+ int *C_head = wka->C_head;
+ int *C_next = wka->C_next;
+ LUXELM *piv, *some, *vij;
+ int i, j, len, min_len, ncand, piv_lim = 5;
+ double best, cost;
+ /* nothing is chosen so far */
+ piv = NULL, best = DBL_MAX, ncand = 0;
+ /* if in the active submatrix there is a column that has the only
+ non-zero (column singleton), choose it as a pivot */
+ j = C_head[1];
+ if (j != 0)
+ { xassert(C_len[j] == 1);
+ piv = V_col[j];
+ xassert(piv != NULL && piv->c_next == NULL);
+ goto done;
+ }
+ /* if in the active submatrix there is a row that has the only
+ non-zero (row singleton), choose it as a pivot */
+ i = R_head[1];
+ if (i != 0)
+ { xassert(R_len[i] == 1);
+ piv = V_row[i];
+ xassert(piv != NULL && piv->r_next == NULL);
+ goto done;
+ }
+ /* there are no singletons in the active submatrix; walk through
+ other non-empty rows and columns */
+ for (len = 2; len <= n; len++)
+ { /* consider active columns having len non-zeros */
+ for (j = C_head[len]; j != 0; j = C_next[j])
+ { /* j-th column has len non-zeros */
+ /* find an element in the row of minimal length */
+ some = NULL, min_len = INT_MAX;
+ for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
+ { if (min_len > R_len[vij->i])
+ some = vij, min_len = R_len[vij->i];
+ /* if Markowitz cost of this element is not greater than
+ (len-1)**2, it can be chosen right now; this heuristic
+ reduces the search and works well in many cases */
+ if (min_len <= len)
+ { piv = some;
+ goto done;
+ }
+ }
+ /* j-th column has been scanned */
+ /* the minimal element found is a next pivot candidate */
+ xassert(some != NULL);
+ ncand++;
+ /* compute its Markowitz cost */
+ cost = (double)(min_len - 1) * (double)(len - 1);
+ /* choose between the current candidate and this element */
+ if (cost < best) piv = some, best = cost;
+ /* if piv_lim candidates have been considered, there is a
+ doubt that a much better candidate exists; therefore it
+ is the time to terminate the search */
+ if (ncand == piv_lim) goto done;
+ }
+ /* now consider active rows having len non-zeros */
+ for (i = R_head[len]; i != 0; i = R_next[i])
+ { /* i-th row has len non-zeros */
+ /* find an element in the column of minimal length */
+ some = NULL, min_len = INT_MAX;
+ for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
+ { if (min_len > C_len[vij->j])
+ some = vij, min_len = C_len[vij->j];
+ /* if Markowitz cost of this element is not greater than
+ (len-1)**2, it can be chosen right now; this heuristic
+ reduces the search and works well in many cases */
+ if (min_len <= len)
+ { piv = some;
+ goto done;
+ }
+ }
+ /* i-th row has been scanned */
+ /* the minimal element found is a next pivot candidate */
+ xassert(some != NULL);
+ ncand++;
+ /* compute its Markowitz cost */
+ cost = (double)(len - 1) * (double)(min_len - 1);
+ /* choose between the current candidate and this element */
+ if (cost < best) piv = some, best = cost;
+ /* if piv_lim candidates have been considered, there is a
+ doubt that a much better candidate exists; therefore it
+ is the time to terminate the search */
+ if (ncand == piv_lim) goto done;
+ }
+ }
+done: /* bring the pivot v[p,q] to the factorizing routine */
+ return piv;
+}
+
+/***********************************************************************
+* eliminate - perform gaussian elimination
+*
+* This routine performs elementary gaussian transformations in order
+* to eliminate subdiagonal elements in the k-th column of the matrix
+* U = P*V*Q using the pivot element u[k,k], where k is the number of
+* the current elimination step.
+*
+* The parameter piv specifies the pivot element v[p,q] = u[k,k].
+*
+* Each time when the routine applies the elementary transformation to
+* a non-pivot row of the matrix V, it stores the corresponding element
+* to the matrix F in order to keep the main equality A = F*V.
+*
+* The routine assumes that on entry the matrices L = P*F*inv(P) and
+* U = P*V*Q are the following:
+*
+* 1 k 1 k n
+* 1 1 . . . . . . . . . 1 x x x x x x x x x x
+* x 1 . . . . . . . . . x x x x x x x x x
+* x x 1 . . . . . . . . . x x x x x x x x
+* x x x 1 . . . . . . . . . x x x x x x x
+* k x x x x 1 . . . . . k . . . . * * * * * *
+* x x x x _ 1 . . . . . . . . # * * * * *
+* x x x x _ . 1 . . . . . . . # * * * * *
+* x x x x _ . . 1 . . . . . . # * * * * *
+* x x x x _ . . . 1 . . . . . # * * * * *
+* n x x x x _ . . . . 1 n . . . . # * * * * *
+*
+* matrix L matrix U
+*
+* where rows and columns of the matrix U with numbers k, k+1, ..., n
+* form the active submatrix (eliminated elements are marked by '#' and
+* other elements of the active submatrix are marked by '*'). Note that
+* each eliminated non-zero element u[i,k] of the matrix U gives the
+* corresponding element l[i,k] of the matrix L (marked by '_').
+*
+* Actually all operations are performed on the matrix V. Should note
+* that the row-wise representation corresponds to the matrix V, but the
+* column-wise representation corresponds to the active submatrix of the
+* matrix V, i.e. elements of the matrix V, which doesn't belong to the
+* active submatrix, are missing from the column linked lists.
+*
+* Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
+* elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
+* the following elementary gaussian transformations:
+*
+* (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
+*
+* where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
+*
+* Additionally, in order to keep the main equality A = F*V, each time
+* when the routine applies the transformation to i-th row of the matrix
+* V, it also adds f[i,p] as a new element to the matrix F.
+*
+* IMPORTANT: On entry the working arrays flag and work should contain
+* zeros. This status is provided by the routine on exit. */
+
+static void eliminate(LUX *lux, LUXWKA *wka, LUXELM *piv, int flag[],
+ mpq_t work[])
+{ DMP *pool = lux->pool;
+ LUXELM **F_row = lux->F_row;
+ LUXELM **F_col = lux->F_col;
+ mpq_t *V_piv = lux->V_piv;
+ LUXELM **V_row = lux->V_row;
+ LUXELM **V_col = lux->V_col;
+ int *R_len = wka->R_len;
+ int *R_head = wka->R_head;
+ int *R_prev = wka->R_prev;
+ int *R_next = wka->R_next;
+ int *C_len = wka->C_len;
+ int *C_head = wka->C_head;
+ int *C_prev = wka->C_prev;
+ int *C_next = wka->C_next;
+ LUXELM *fip, *vij, *vpj, *viq, *next;
+ mpq_t temp;
+ int i, j, p, q;
+ mpq_init(temp);
+ /* determine row and column indices of the pivot v[p,q] */
+ xassert(piv != NULL);
+ p = piv->i, q = piv->j;
+ /* remove p-th (pivot) row from the active set; it will never
+ return there */
+ if (R_prev[p] == 0)
+ R_head[R_len[p]] = R_next[p];
+ else
+ R_next[R_prev[p]] = R_next[p];
+ if (R_next[p] == 0)
+ ;
+ else
+ R_prev[R_next[p]] = R_prev[p];
+ /* remove q-th (pivot) column from the active set; it will never
+ return there */
+ if (C_prev[q] == 0)
+ C_head[C_len[q]] = C_next[q];
+ else
+ C_next[C_prev[q]] = C_next[q];
+ if (C_next[q] == 0)
+ ;
+ else
+ C_prev[C_next[q]] = C_prev[q];
+ /* store the pivot value in a separate array */
+ mpq_set(V_piv[p], piv->val);
+ /* remove the pivot from p-th row */
+ if (piv->r_prev == NULL)
+ V_row[p] = piv->r_next;
+ else
+ piv->r_prev->r_next = piv->r_next;
+ if (piv->r_next == NULL)
+ ;
+ else
+ piv->r_next->r_prev = piv->r_prev;
+ R_len[p]--;
+ /* remove the pivot from q-th column */
+ if (piv->c_prev == NULL)
+ V_col[q] = piv->c_next;
+ else
+ piv->c_prev->c_next = piv->c_next;
+ if (piv->c_next == NULL)
+ ;
+ else
+ piv->c_next->c_prev = piv->c_prev;
+ C_len[q]--;
+ /* free the space occupied by the pivot */
+ mpq_clear(piv->val);
+ dmp_free_atom(pool, piv, sizeof(LUXELM));
+ /* walk through p-th (pivot) row, which already does not contain
+ the pivot v[p,q], and do the following... */
+ for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
+ { /* get column index of v[p,j] */
+ j = vpj->j;
+ /* store v[p,j] in the working array */
+ flag[j] = 1;
+ mpq_set(work[j], vpj->val);
+ /* remove j-th column from the active set; it will return there
+ later with a new length */
+ if (C_prev[j] == 0)
+ C_head[C_len[j]] = C_next[j];
+ else
+ C_next[C_prev[j]] = C_next[j];
+ if (C_next[j] == 0)
+ ;
+ else
+ C_prev[C_next[j]] = C_prev[j];
+ /* v[p,j] leaves the active submatrix, so remove it from j-th
+ column; however, v[p,j] is kept in p-th row */
+ if (vpj->c_prev == NULL)
+ V_col[j] = vpj->c_next;
+ else
+ vpj->c_prev->c_next = vpj->c_next;
+ if (vpj->c_next == NULL)
+ ;
+ else
+ vpj->c_next->c_prev = vpj->c_prev;
+ C_len[j]--;
+ }
+ /* now walk through q-th (pivot) column, which already does not
+ contain the pivot v[p,q], and perform gaussian elimination */
+ while (V_col[q] != NULL)
+ { /* element v[i,q] has to be eliminated */
+ viq = V_col[q];
+ /* get row index of v[i,q] */
+ i = viq->i;
+ /* remove i-th row from the active set; later it will return
+ there with a new length */
+ if (R_prev[i] == 0)
+ R_head[R_len[i]] = R_next[i];
+ else
+ R_next[R_prev[i]] = R_next[i];
+ if (R_next[i] == 0)
+ ;
+ else
+ R_prev[R_next[i]] = R_prev[i];
+ /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] and
+ store it in the matrix F */
+ fip = dmp_get_atom(pool, sizeof(LUXELM));
+ fip->i = i, fip->j = p;
+ mpq_init(fip->val);
+ mpq_div(fip->val, viq->val, V_piv[p]);
+ fip->r_prev = NULL;
+ fip->r_next = F_row[i];
+ fip->c_prev = NULL;
+ fip->c_next = F_col[p];
+ if (fip->r_next != NULL) fip->r_next->r_prev = fip;
+ if (fip->c_next != NULL) fip->c_next->c_prev = fip;
+ F_row[i] = F_col[p] = fip;
+ /* v[i,q] has to be eliminated, so remove it from i-th row */
+ if (viq->r_prev == NULL)
+ V_row[i] = viq->r_next;
+ else
+ viq->r_prev->r_next = viq->r_next;
+ if (viq->r_next == NULL)
+ ;
+ else
+ viq->r_next->r_prev = viq->r_prev;
+ R_len[i]--;
+ /* and also from q-th column */
+ V_col[q] = viq->c_next;
+ C_len[q]--;
+ /* free the space occupied by v[i,q] */
+ mpq_clear(viq->val);
+ dmp_free_atom(pool, viq, sizeof(LUXELM));
+ /* perform gaussian transformation:
+ (i-th row) := (i-th row) - f[i,p] * (p-th row)
+ note that now p-th row, which is in the working array,
+ does not contain the pivot v[p,q], and i-th row does not
+ contain the element v[i,q] to be eliminated */
+ /* walk through i-th row and transform existing non-zero
+ elements */
+ for (vij = V_row[i]; vij != NULL; vij = next)
+ { next = vij->r_next;
+ /* get column index of v[i,j] */
+ j = vij->j;
+ /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
+ if (flag[j])
+ { /* v[p,j] != 0 */
+ flag[j] = 0;
+ mpq_mul(temp, fip->val, work[j]);
+ mpq_sub(vij->val, vij->val, temp);
+ if (mpq_sgn(vij->val) == 0)
+ { /* new v[i,j] is zero, so remove it from the active
+ submatrix */
+ /* remove v[i,j] from i-th row */
+ if (vij->r_prev == NULL)
+ V_row[i] = vij->r_next;
+ else
+ vij->r_prev->r_next = vij->r_next;
+ if (vij->r_next == NULL)
+ ;
+ else
+ vij->r_next->r_prev = vij->r_prev;
+ R_len[i]--;
+ /* remove v[i,j] from j-th column */
+ if (vij->c_prev == NULL)
+ V_col[j] = vij->c_next;
+ else
+ vij->c_prev->c_next = vij->c_next;
+ if (vij->c_next == NULL)
+ ;
+ else
+ vij->c_next->c_prev = vij->c_prev;
+ C_len[j]--;
+ /* free the space occupied by v[i,j] */
+ mpq_clear(vij->val);
+ dmp_free_atom(pool, vij, sizeof(LUXELM));
+ }
+ }
+ }
+ /* now flag is the pattern of the set v[p,*] \ v[i,*] */
+ /* walk through p-th (pivot) row and create new elements in
+ i-th row, which appear due to fill-in */
+ for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
+ { j = vpj->j;
+ if (flag[j])
+ { /* create new non-zero v[i,j] = 0 - f[i,p] * v[p,j] and
+ add it to i-th row and j-th column */
+ vij = dmp_get_atom(pool, sizeof(LUXELM));
+ vij->i = i, vij->j = j;
+ mpq_init(vij->val);
+ mpq_mul(vij->val, fip->val, work[j]);
+ mpq_neg(vij->val, vij->val);
+ vij->r_prev = NULL;
+ vij->r_next = V_row[i];
+ vij->c_prev = NULL;
+ vij->c_next = V_col[j];
+ if (vij->r_next != NULL) vij->r_next->r_prev = vij;
+ if (vij->c_next != NULL) vij->c_next->c_prev = vij;
+ V_row[i] = V_col[j] = vij;
+ R_len[i]++, C_len[j]++;
+ }
+ else
+ { /* there is no fill-in, because v[i,j] already exists in
+ i-th row; restore the flag, which was reset before */
+ flag[j] = 1;
+ }
+ }
+ /* now i-th row has been completely transformed and can return
+ to the active set with a new length */
+ R_prev[i] = 0;
+ R_next[i] = R_head[R_len[i]];
+ if (R_next[i] != 0) R_prev[R_next[i]] = i;
+ R_head[R_len[i]] = i;
+ }
+ /* at this point q-th (pivot) column must be empty */
+ xassert(C_len[q] == 0);
+ /* walk through p-th (pivot) row again and do the following... */
+ for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
+ { /* get column index of v[p,j] */
+ j = vpj->j;
+ /* erase v[p,j] from the working array */
+ flag[j] = 0;
+ mpq_set_si(work[j], 0, 1);
+ /* now j-th column has been completely transformed, so it can
+ return to the active list with a new length */
+ C_prev[j] = 0;
+ C_next[j] = C_head[C_len[j]];
+ if (C_next[j] != 0) C_prev[C_next[j]] = j;
+ C_head[C_len[j]] = j;
+ }
+ mpq_clear(temp);
+ /* return to the factorizing routine */
+ return;
+}
+
+/***********************************************************************
+* lux_decomp - compute LU-factorization
+*
+* SYNOPSIS
+*
+* #include "lux.h"
+* int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
+* mpq_t val[]), void *info);
+*
+* DESCRIPTION
+*
+* The routine lux_decomp computes LU-factorization of a given square
+* matrix A.
+*
+* The parameter lux specifies LU-factorization data structure built by
+* means of the routine lux_create.
+*
+* The formal routine col specifies the original matrix A. In order to
+* obtain j-th column of the matrix A the routine lux_decomp calls the
+* routine col with the parameter j (1 <= j <= n, where n is the order
+* of A). In response the routine col should store row indices and
+* numerical values of non-zero elements of j-th column of A to the
+* locations ind[1], ..., ind[len] and val[1], ..., val[len], resp.,
+* where len is the number of non-zeros in j-th column, which should be
+* returned on exit. Neiter zero nor duplicate elements are allowed.
+*
+* The parameter info is a transit pointer passed to the formal routine
+* col; it can be used for various purposes.
+*
+* RETURNS
+*
+* The routine lux_decomp returns the singularity flag. Zero flag means
+* that the original matrix A is non-singular while non-zero flag means
+* that A is (exactly!) singular.
+*
+* Note that LU-factorization is valid in both cases, however, in case
+* of singularity some rows of the matrix V (including pivot elements)
+* will be empty.
+*
+* REPAIRING SINGULAR MATRIX
+*
+* If the routine lux_decomp returns non-zero flag, it provides all
+* necessary information that can be used for "repairing" the matrix A,
+* where "repairing" means replacing linearly dependent columns of the
+* matrix A by appropriate columns of the unity matrix. This feature is
+* needed when the routine lux_decomp is used for reinverting the basis
+* matrix within the simplex method procedure.
+*
+* On exit linearly dependent columns of the matrix U have the numbers
+* rank+1, rank+2, ..., n, where rank is the exact rank of the matrix A
+* stored by the routine to the member lux->rank. The correspondence
+* between columns of A and U is the same as between columns of V and U.
+* Thus, linearly dependent columns of the matrix A have the numbers
+* Q_col[rank+1], Q_col[rank+2], ..., Q_col[n], where Q_col is an array
+* representing the permutation matrix Q in column-like format. It is
+* understood that each j-th linearly dependent column of the matrix U
+* should be replaced by the unity vector, where all elements are zero
+* except the unity diagonal element u[j,j]. On the other hand j-th row
+* of the matrix U corresponds to the row of the matrix V (and therefore
+* of the matrix A) with the number P_row[j], where P_row is an array
+* representing the permutation matrix P in row-like format. Thus, each
+* j-th linearly dependent column of the matrix U should be replaced by
+* a column of the unity matrix with the number P_row[j].
+*
+* The code that repairs the matrix A may look like follows:
+*
+* for (j = rank+1; j <= n; j++)
+* { replace column Q_col[j] of the matrix A by column P_row[j] of
+* the unity matrix;
+* }
+*
+* where rank, P_row, and Q_col are members of the structure LUX. */
+
+int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
+ mpq_t val[]), void *info)
+{ int n = lux->n;
+ LUXELM **V_row = lux->V_row;
+ LUXELM **V_col = lux->V_col;
+ int *P_row = lux->P_row;
+ int *P_col = lux->P_col;
+ int *Q_row = lux->Q_row;
+ int *Q_col = lux->Q_col;
+ LUXELM *piv, *vij;
+ LUXWKA *wka;
+ int i, j, k, p, q, t, *flag;
+ mpq_t *work;
+ /* allocate working area */
+ wka = xmalloc(sizeof(LUXWKA));
+ wka->R_len = xcalloc(1+n, sizeof(int));
+ wka->R_head = xcalloc(1+n, sizeof(int));
+ wka->R_prev = xcalloc(1+n, sizeof(int));
+ wka->R_next = xcalloc(1+n, sizeof(int));
+ wka->C_len = xcalloc(1+n, sizeof(int));
+ wka->C_head = xcalloc(1+n, sizeof(int));
+ wka->C_prev = xcalloc(1+n, sizeof(int));
+ wka->C_next = xcalloc(1+n, sizeof(int));
+ /* initialize LU-factorization data structures */
+ initialize(lux, col, info, wka);
+ /* allocate working arrays */
+ flag = xcalloc(1+n, sizeof(int));
+ work = xcalloc(1+n, sizeof(mpq_t));
+ for (k = 1; k <= n; k++)
+ { flag[k] = 0;
+ mpq_init(work[k]);
+ }
+ /* main elimination loop */
+ for (k = 1; k <= n; k++)
+ { /* choose a pivot element v[p,q] */
+ piv = find_pivot(lux, wka);
+ if (piv == NULL)
+ { /* no pivot can be chosen, because the active submatrix is
+ empty */
+ break;
+ }
+ /* determine row and column indices of the pivot element */
+ p = piv->i, q = piv->j;
+ /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
+ rows and k-th and j'-th columns of the matrix U = P*V*Q to
+ move the element u[i',j'] to the position u[k,k] */
+ i = P_col[p], j = Q_row[q];
+ xassert(k <= i && i <= n && k <= j && j <= n);
+ /* permute k-th and i-th rows of the matrix U */
+ t = P_row[k];
+ P_row[i] = t, P_col[t] = i;
+ P_row[k] = p, P_col[p] = k;
+ /* permute k-th and j-th columns of the matrix U */
+ t = Q_col[k];
+ Q_col[j] = t, Q_row[t] = j;
+ Q_col[k] = q, Q_row[q] = k;
+ /* eliminate subdiagonal elements of k-th column of the matrix
+ U = P*V*Q using the pivot element u[k,k] = v[p,q] */
+ eliminate(lux, wka, piv, flag, work);
+ }
+ /* determine the rank of A (and V) */
+ lux->rank = k - 1;
+ /* free working arrays */
+ xfree(flag);
+ for (k = 1; k <= n; k++) mpq_clear(work[k]);
+ xfree(work);
+ /* build column lists of the matrix V using its row lists */
+ for (j = 1; j <= n; j++)
+ xassert(V_col[j] == NULL);
+ for (i = 1; i <= n; i++)
+ { for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
+ { j = vij->j;
+ vij->c_prev = NULL;
+ vij->c_next = V_col[j];
+ if (vij->c_next != NULL) vij->c_next->c_prev = vij;
+ V_col[j] = vij;
+ }
+ }
+ /* free working area */
+ xfree(wka->R_len);
+ xfree(wka->R_head);
+ xfree(wka->R_prev);
+ xfree(wka->R_next);
+ xfree(wka->C_len);
+ xfree(wka->C_head);
+ xfree(wka->C_prev);
+ xfree(wka->C_next);
+ xfree(wka);
+ /* return to the calling program */
+ return (lux->rank < n);
+}
+
+/***********************************************************************
+* lux_f_solve - solve system F*x = b or F'*x = b
+*
+* SYNOPSIS
+*
+* #include "lux.h"
+* void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
+*
+* DESCRIPTION
+*
+* The routine lux_f_solve solves either the system F*x = b (if the
+* flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
+* where the matrix F is a component of LU-factorization specified by
+* the parameter lux, F' is a matrix transposed to F.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix F. On exit this array will contain elements of the solution
+* vector x in the same locations. */
+
+void lux_f_solve(LUX *lux, int tr, mpq_t x[])
+{ int n = lux->n;
+ LUXELM **F_row = lux->F_row;
+ LUXELM **F_col = lux->F_col;
+ int *P_row = lux->P_row;
+ LUXELM *fik, *fkj;
+ int i, j, k;
+ mpq_t temp;
+ mpq_init(temp);
+ if (!tr)
+ { /* solve the system F*x = b */
+ for (j = 1; j <= n; j++)
+ { k = P_row[j];
+ if (mpq_sgn(x[k]) != 0)
+ { for (fik = F_col[k]; fik != NULL; fik = fik->c_next)
+ { mpq_mul(temp, fik->val, x[k]);
+ mpq_sub(x[fik->i], x[fik->i], temp);
+ }
+ }
+ }
+ }
+ else
+ { /* solve the system F'*x = b */
+ for (i = n; i >= 1; i--)
+ { k = P_row[i];
+ if (mpq_sgn(x[k]) != 0)
+ { for (fkj = F_row[k]; fkj != NULL; fkj = fkj->r_next)
+ { mpq_mul(temp, fkj->val, x[k]);
+ mpq_sub(x[fkj->j], x[fkj->j], temp);
+ }
+ }
+ }
+ }
+ mpq_clear(temp);
+ return;
+}
+
+/***********************************************************************
+* lux_v_solve - solve system V*x = b or V'*x = b
+*
+* SYNOPSIS
+*
+* #include "lux.h"
+* void lux_v_solve(LUX *lux, int tr, double x[]);
+*
+* DESCRIPTION
+*
+* The routine lux_v_solve solves either the system V*x = b (if the
+* flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
+* where the matrix V is a component of LU-factorization specified by
+* the parameter lux, V' is a matrix transposed to V.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix V. On exit this array will contain elements of the solution
+* vector x in the same locations. */
+
+void lux_v_solve(LUX *lux, int tr, mpq_t x[])
+{ int n = lux->n;
+ mpq_t *V_piv = lux->V_piv;
+ LUXELM **V_row = lux->V_row;
+ LUXELM **V_col = lux->V_col;
+ int *P_row = lux->P_row;
+ int *Q_col = lux->Q_col;
+ LUXELM *vij;
+ int i, j, k;
+ mpq_t *b, temp;
+ b = xcalloc(1+n, sizeof(mpq_t));
+ for (k = 1; k <= n; k++)
+ mpq_init(b[k]), mpq_set(b[k], x[k]), mpq_set_si(x[k], 0, 1);
+ mpq_init(temp);
+ if (!tr)
+ { /* solve the system V*x = b */
+ for (k = n; k >= 1; k--)
+ { i = P_row[k], j = Q_col[k];
+ if (mpq_sgn(b[i]) != 0)
+ { mpq_set(x[j], b[i]);
+ mpq_div(x[j], x[j], V_piv[i]);
+ for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
+ { mpq_mul(temp, vij->val, x[j]);
+ mpq_sub(b[vij->i], b[vij->i], temp);
+ }
+ }
+ }
+ }
+ else
+ { /* solve the system V'*x = b */
+ for (k = 1; k <= n; k++)
+ { i = P_row[k], j = Q_col[k];
+ if (mpq_sgn(b[j]) != 0)
+ { mpq_set(x[i], b[j]);
+ mpq_div(x[i], x[i], V_piv[i]);
+ for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
+ { mpq_mul(temp, vij->val, x[i]);
+ mpq_sub(b[vij->j], b[vij->j], temp);
+ }
+ }
+ }
+ }
+ for (k = 1; k <= n; k++) mpq_clear(b[k]);
+ mpq_clear(temp);
+ xfree(b);
+ return;
+}
+
+/***********************************************************************
+* lux_solve - solve system A*x = b or A'*x = b
+*
+* SYNOPSIS
+*
+* #include "lux.h"
+* void lux_solve(LUX *lux, int tr, mpq_t x[]);
+*
+* DESCRIPTION
+*
+* The routine lux_solve solves either the system A*x = b (if the flag
+* tr is zero) or the system A'*x = b (if the flag tr is non-zero),
+* where the parameter lux specifies LU-factorization of the matrix A,
+* A' is a matrix transposed to A.
+*
+* On entry the array x should contain elements of the right-hand side
+* vector b in locations x[1], ..., x[n], where n is the order of the
+* matrix A. On exit this array will contain elements of the solution
+* vector x in the same locations. */
+
+void lux_solve(LUX *lux, int tr, mpq_t x[])
+{ if (lux->rank < lux->n)
+ xfault("lux_solve: LU-factorization has incomplete rank\n");
+ if (!tr)
+ { /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
+ lux_f_solve(lux, 0, x);
+ lux_v_solve(lux, 0, x);
+ }
+ else
+ { /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
+ lux_v_solve(lux, 1, x);
+ lux_f_solve(lux, 1, x);
+ }
+ return;
+}
+
+/***********************************************************************
+* lux_delete - delete LU-factorization
+*
+* SYNOPSIS
+*
+* #include "lux.h"
+* void lux_delete(LUX *lux);
+*
+* DESCRIPTION
+*
+* The routine lux_delete deletes LU-factorization data structure,
+* which the parameter lux points to, freeing all the memory allocated
+* to this object. */
+
+void lux_delete(LUX *lux)
+{ int n = lux->n;
+ LUXELM *fij, *vij;
+ int i;
+ for (i = 1; i <= n; i++)
+ { for (fij = lux->F_row[i]; fij != NULL; fij = fij->r_next)
+ mpq_clear(fij->val);
+ mpq_clear(lux->V_piv[i]);
+ for (vij = lux->V_row[i]; vij != NULL; vij = vij->r_next)
+ mpq_clear(vij->val);
+ }
+ dmp_delete_pool(lux->pool);
+ xfree(lux->F_row);
+ xfree(lux->F_col);
+ xfree(lux->V_piv);
+ xfree(lux->V_row);
+ xfree(lux->V_col);
+ xfree(lux->P_row);
+ xfree(lux->P_col);
+ xfree(lux->Q_row);
+ xfree(lux->Q_col);
+ xfree(lux);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/draft/lux.h b/test/monniaux/glpk-4.65/src/draft/lux.h
new file mode 100644
index 00000000..8767bb8e
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/draft/lux.h
@@ -0,0 +1,220 @@
+/* lux.h (LU-factorization, rational arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+* 2009, 2010, 2011, 2013 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/>.
+***********************************************************************/
+
+#ifndef LUX_H
+#define LUX_H
+
+#include "dmp.h"
+#include "mygmp.h"
+
+/***********************************************************************
+* The structure LUX defines LU-factorization of a square matrix A,
+* which is the following quartet:
+*
+* [A] = (F, V, P, Q), (1)
+*
+* where F and V are such matrices that
+*
+* A = F * V, (2)
+*
+* and P and Q are such permutation matrices that the matrix
+*
+* L = P * F * inv(P) (3)
+*
+* is lower triangular with unity diagonal, and the matrix
+*
+* U = P * V * Q (4)
+*
+* is upper triangular. All the matrices have the order n.
+*
+* The matrices F and V are stored in row/column-wise sparse format as
+* row and column linked lists of non-zero elements. Unity elements on
+* the main diagonal of the matrix F are not stored. Pivot elements of
+* the matrix V (that correspond to diagonal elements of the matrix U)
+* are also missing from the row and column lists and stored separately
+* in an ordinary array.
+*
+* The permutation matrices P and Q are stored as ordinary arrays using
+* both row- and column-like formats.
+*
+* The matrices L and U being completely defined by the matrices F, V,
+* P, and Q are not stored explicitly.
+*
+* It is easy to show that the factorization (1)-(3) is some version of
+* LU-factorization. Indeed, from (3) and (4) it follows that:
+*
+* F = inv(P) * L * P,
+*
+* V = inv(P) * U * inv(Q),
+*
+* and substitution into (2) gives:
+*
+* A = F * V = inv(P) * L * U * inv(Q).
+*
+* For more details see the program documentation. */
+
+typedef struct LUX LUX;
+typedef struct LUXELM LUXELM;
+typedef struct LUXWKA LUXWKA;
+
+struct LUX
+{ /* LU-factorization of a square matrix */
+ int n;
+ /* the order of matrices A, F, V, P, Q */
+ DMP *pool;
+ /* memory pool for elements of matrices F and V */
+ LUXELM **F_row; /* LUXELM *F_row[1+n]; */
+ /* F_row[0] is not used;
+ F_row[i], 1 <= i <= n, is a pointer to the list of elements in
+ i-th row of matrix F (diagonal elements are not stored) */
+ LUXELM **F_col; /* LUXELM *F_col[1+n]; */
+ /* F_col[0] is not used;
+ F_col[j], 1 <= j <= n, is a pointer to the list of elements in
+ j-th column of matrix F (diagonal elements are not stored) */
+ mpq_t *V_piv; /* mpq_t V_piv[1+n]; */
+ /* V_piv[0] is not used;
+ V_piv[p], 1 <= p <= n, is a pivot element v[p,q] corresponding
+ to a diagonal element u[k,k] of matrix U = P*V*Q (used on k-th
+ elimination step, k = 1, 2, ..., n) */
+ LUXELM **V_row; /* LUXELM *V_row[1+n]; */
+ /* V_row[0] is not used;
+ V_row[i], 1 <= i <= n, is a pointer to the list of elements in
+ i-th row of matrix V (except pivot elements) */
+ LUXELM **V_col; /* LUXELM *V_col[1+n]; */
+ /* V_col[0] is not used;
+ V_col[j], 1 <= j <= n, is a pointer to the list of elements in
+ j-th column of matrix V (except pivot elements) */
+ int *P_row; /* int P_row[1+n]; */
+ /* P_row[0] is not used;
+ P_row[i] = j means that p[i,j] = 1, where p[i,j] is an element
+ of permutation matrix P */
+ int *P_col; /* int P_col[1+n]; */
+ /* P_col[0] is not used;
+ P_col[j] = i means that p[i,j] = 1, where p[i,j] is an element
+ of permutation matrix P */
+ /* if i-th row or column of matrix F is i'-th row or column of
+ matrix L = P*F*inv(P), or if i-th row of matrix V is i'-th row
+ of matrix U = P*V*Q, then P_row[i'] = i and P_col[i] = i' */
+ int *Q_row; /* int Q_row[1+n]; */
+ /* Q_row[0] is not used;
+ Q_row[i] = j means that q[i,j] = 1, where q[i,j] is an element
+ of permutation matrix Q */
+ int *Q_col; /* int Q_col[1+n]; */
+ /* Q_col[0] is not used;
+ Q_col[j] = i means that q[i,j] = 1, where q[i,j] is an element
+ of permutation matrix Q */
+ /* if j-th column of matrix V is j'-th column of matrix U = P*V*Q,
+ then Q_row[j] = j' and Q_col[j'] = j */
+ int rank;
+ /* the (exact) rank of matrices A and V */
+};
+
+struct LUXELM
+{ /* element of matrix F or V */
+ int i;
+ /* row index, 1 <= i <= m */
+ int j;
+ /* column index, 1 <= j <= n */
+ mpq_t val;
+ /* numeric (non-zero) element value */
+ LUXELM *r_prev;
+ /* pointer to previous element in the same row */
+ LUXELM *r_next;
+ /* pointer to next element in the same row */
+ LUXELM *c_prev;
+ /* pointer to previous element in the same column */
+ LUXELM *c_next;
+ /* pointer to next element in the same column */
+};
+
+struct LUXWKA
+{ /* working area (used only during factorization) */
+ /* in order to efficiently implement Markowitz strategy and Duff
+ search technique there are two families {R[0], R[1], ..., R[n]}
+ and {C[0], C[1], ..., C[n]}; member R[k] is a set of active
+ rows of matrix V having k non-zeros, and member C[k] is a set
+ of active columns of matrix V having k non-zeros (in the active
+ submatrix); each set R[k] and C[k] is implemented as a separate
+ doubly linked list */
+ int *R_len; /* int R_len[1+n]; */
+ /* R_len[0] is not used;
+ R_len[i], 1 <= i <= n, is the number of non-zero elements in
+ i-th row of matrix V (that is the length of i-th row) */
+ int *R_head; /* int R_head[1+n]; */
+ /* R_head[k], 0 <= k <= n, is the number of a first row, which is
+ active and whose length is k */
+ int *R_prev; /* int R_prev[1+n]; */
+ /* R_prev[0] is not used;
+ R_prev[i], 1 <= i <= n, is the number of a previous row, which
+ is active and has the same length as i-th row */
+ int *R_next; /* int R_next[1+n]; */
+ /* R_prev[0] is not used;
+ R_prev[i], 1 <= i <= n, is the number of a next row, which is
+ active and has the same length as i-th row */
+ int *C_len; /* int C_len[1+n]; */
+ /* C_len[0] is not used;
+ C_len[j], 1 <= j <= n, is the number of non-zero elements in
+ j-th column of the active submatrix of matrix V (that is the
+ length of j-th column in the active submatrix) */
+ int *C_head; /* int C_head[1+n]; */
+ /* C_head[k], 0 <= k <= n, is the number of a first column, which
+ is active and whose length is k */
+ int *C_prev; /* int C_prev[1+n]; */
+ /* C_prev[0] is not used;
+ C_prev[j], 1 <= j <= n, is the number of a previous column,
+ which is active and has the same length as j-th column */
+ int *C_next; /* int C_next[1+n]; */
+ /* C_next[0] is not used;
+ C_next[j], 1 <= j <= n, is the number of a next column, which
+ is active and has the same length as j-th column */
+};
+
+#define lux_create _glp_lux_create
+LUX *lux_create(int n);
+/* create LU-factorization */
+
+#define lux_decomp _glp_lux_decomp
+int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
+ mpq_t val[]), void *info);
+/* compute LU-factorization */
+
+#define lux_f_solve _glp_lux_f_solve
+void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
+/* solve system F*x = b or F'*x = b */
+
+#define lux_v_solve _glp_lux_v_solve
+void lux_v_solve(LUX *lux, int tr, mpq_t x[]);
+/* solve system V*x = b or V'*x = b */
+
+#define lux_solve _glp_lux_solve
+void lux_solve(LUX *lux, int tr, mpq_t x[]);
+/* solve system A*x = b or A'*x = b */
+
+#define lux_delete _glp_lux_delete
+void lux_delete(LUX *lux);
+/* delete LU-factorization */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/alloc.c b/test/monniaux/glpk-4.65/src/env/alloc.c
new file mode 100644
index 00000000..8e2d613d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/alloc.c
@@ -0,0 +1,252 @@
+/* alloc.c (dynamic memory allocation) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+
+#define ALIGN 16
+/* some processors need data to be properly aligned, so this macro
+ * defines the alignment boundary, in bytes, provided by glpk memory
+ * allocation routines; looks like 16-byte alignment boundary is
+ * sufficient for all 32- and 64-bit platforms (8-byte boundary is not
+ * sufficient for some 64-bit platforms because of jmp_buf) */
+
+#define MBD_SIZE (((sizeof(MBD) + (ALIGN - 1)) / ALIGN) * ALIGN)
+/* size of memory block descriptor, in bytes, rounded up to multiple
+ * of the alignment boundary */
+
+/***********************************************************************
+* dma - dynamic memory allocation (basic routine)
+*
+* This routine performs dynamic memory allocation. It is similar to
+* the standard realloc function, however, it provides every allocated
+* memory block with a descriptor, which is used for sanity checks on
+* reallocating/freeing previously allocated memory blocks as well as
+* for book-keeping the memory usage statistics. */
+
+static void *dma(const char *func, void *ptr, size_t size)
+{ ENV *env = get_env_ptr();
+ MBD *mbd;
+ if (ptr == NULL)
+ { /* new memory block will be allocated */
+ mbd = NULL;
+ }
+ else
+ { /* allocated memory block will be reallocated or freed */
+ /* get pointer to the block descriptor */
+ mbd = (MBD *)((char *)ptr - MBD_SIZE);
+ /* make sure that the block descriptor is valid */
+ if (mbd->self != mbd)
+ xerror("%s: ptr = %p; invalid pointer\n", func, ptr);
+ /* remove the block from the linked list */
+ mbd->self = NULL;
+ if (mbd->prev == NULL)
+ env->mem_ptr = mbd->next;
+ else
+ mbd->prev->next = mbd->next;
+ if (mbd->next == NULL)
+ ;
+ else
+ mbd->next->prev = mbd->prev;
+ /* decrease usage counts */
+ if (!(env->mem_count >= 1 && env->mem_total >= mbd->size))
+ xerror("%s: memory allocation error\n", func);
+ env->mem_count--;
+ env->mem_total -= mbd->size;
+ if (size == 0)
+ { /* free the memory block */
+ free(mbd);
+ return NULL;
+ }
+ }
+ /* allocate/reallocate memory block */
+ if (size > SIZE_T_MAX - MBD_SIZE)
+ xerror("%s: block too large\n", func);
+ size += MBD_SIZE;
+ if (size > env->mem_limit - env->mem_total)
+ xerror("%s: memory allocation limit exceeded\n", func);
+ if (env->mem_count == INT_MAX)
+ xerror("%s: too many memory blocks allocated\n", func);
+ mbd = (mbd == NULL ? malloc(size) : realloc(mbd, size));
+ if (mbd == NULL)
+ xerror("%s: no memory available\n", func);
+ /* setup the block descriptor */
+ mbd->size = size;
+ mbd->self = mbd;
+ mbd->prev = NULL;
+ mbd->next = env->mem_ptr;
+ /* add the block to the beginning of the linked list */
+ if (mbd->next != NULL)
+ mbd->next->prev = mbd;
+ env->mem_ptr = mbd;
+ /* increase usage counts */
+ env->mem_count++;
+ if (env->mem_cpeak < env->mem_count)
+ env->mem_cpeak = env->mem_count;
+ env->mem_total += size;
+ if (env->mem_tpeak < env->mem_total)
+ env->mem_tpeak = env->mem_total;
+ return (char *)mbd + MBD_SIZE;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_alloc - allocate memory block
+*
+* SYNOPSIS
+*
+* void *glp_alloc(int n, int size);
+*
+* DESCRIPTION
+*
+* The routine glp_alloc allocates a memory block of n * size bytes
+* long.
+*
+* Note that being allocated the memory block contains arbitrary data
+* (not binary zeros!).
+*
+* RETURNS
+*
+* The routine glp_alloc returns a pointer to the block allocated.
+* To free this block the routine glp_free (not free!) must be used. */
+
+void *glp_alloc(int n, int size)
+{ if (n < 1)
+ xerror("glp_alloc: n = %d; invalid parameter\n", n);
+ if (size < 1)
+ xerror("glp_alloc: size = %d; invalid parameter\n", size);
+ if ((size_t)n > SIZE_T_MAX / (size_t)size)
+ xerror("glp_alloc: n = %d, size = %d; block too large\n",
+ n, size);
+ return dma("glp_alloc", NULL, (size_t)n * (size_t)size);
+}
+
+/**********************************************************************/
+
+void *glp_realloc(void *ptr, int n, int size)
+{ /* reallocate memory block */
+ if (ptr == NULL)
+ xerror("glp_realloc: ptr = %p; invalid pointer\n", ptr);
+ if (n < 1)
+ xerror("glp_realloc: n = %d; invalid parameter\n", n);
+ if (size < 1)
+ xerror("glp_realloc: size = %d; invalid parameter\n", size);
+ if ((size_t)n > SIZE_T_MAX / (size_t)size)
+ xerror("glp_realloc: n = %d, size = %d; block too large\n",
+ n, size);
+ return dma("glp_realloc", ptr, (size_t)n * (size_t)size);
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_free - free (deallocate) memory block
+*
+* SYNOPSIS
+*
+* void glp_free(void *ptr);
+*
+* DESCRIPTION
+*
+* The routine glp_free frees (deallocates) a memory block pointed to
+* by ptr, which was previuosly allocated by the routine glp_alloc or
+* reallocated by the routine glp_realloc. */
+
+void glp_free(void *ptr)
+{ if (ptr == NULL)
+ xerror("glp_free: ptr = %p; invalid pointer\n", ptr);
+ dma("glp_free", ptr, 0);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_mem_limit - set memory usage limit
+*
+* SYNOPSIS
+*
+* void glp_mem_limit(int limit);
+*
+* DESCRIPTION
+*
+* The routine glp_mem_limit limits the amount of memory available for
+* dynamic allocation (in GLPK routines) to limit megabytes. */
+
+void glp_mem_limit(int limit)
+{ ENV *env = get_env_ptr();
+ if (limit < 1)
+ xerror("glp_mem_limit: limit = %d; invalid parameter\n",
+ limit);
+ if ((size_t)limit <= (SIZE_T_MAX >> 20))
+ env->mem_limit = (size_t)limit << 20;
+ else
+ env->mem_limit = SIZE_T_MAX;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_mem_usage - get memory usage information
+*
+* SYNOPSIS
+*
+* void glp_mem_usage(int *count, int *cpeak, size_t *total,
+* size_t *tpeak);
+*
+* DESCRIPTION
+*
+* The routine glp_mem_usage reports some information about utilization
+* of the memory by GLPK routines. Information is stored to locations
+* specified by corresponding parameters (see below). Any parameter can
+* be specified as NULL, in which case its value is not stored.
+*
+* *count is the number of the memory blocks currently allocated by the
+* routines glp_malloc and glp_calloc (one call to glp_malloc or
+* glp_calloc results in allocating one memory block).
+*
+* *cpeak is the peak value of *count reached since the initialization
+* of the GLPK library environment.
+*
+* *total is the total amount, in bytes, of the memory blocks currently
+* allocated by the routines glp_malloc and glp_calloc.
+*
+* *tpeak is the peak value of *total reached since the initialization
+* of the GLPK library envirionment. */
+
+void glp_mem_usage(int *count, int *cpeak, size_t *total,
+ size_t *tpeak)
+{ ENV *env = get_env_ptr();
+ if (count != NULL)
+ *count = env->mem_count;
+ if (cpeak != NULL)
+ *cpeak = env->mem_cpeak;
+ if (total != NULL)
+ *total = env->mem_total;
+ if (tpeak != NULL)
+ *tpeak = env->mem_tpeak;
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/dlsup.c b/test/monniaux/glpk-4.65/src/env/dlsup.c
new file mode 100644
index 00000000..54c56c6d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/dlsup.c
@@ -0,0 +1,167 @@
+/* dlsup.c (dynamic linking support) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2008-2013 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/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "env.h"
+
+/* GNU version ********************************************************/
+
+#if defined(HAVE_LTDL)
+
+#include <ltdl.h>
+
+void *xdlopen(const char *module)
+{ /* open dynamically linked library */
+ void *h = NULL;
+ if (lt_dlinit() != 0)
+ { put_err_msg(lt_dlerror());
+ goto done;
+ }
+ h = lt_dlopen(module);
+ if (h == NULL)
+ { put_err_msg(lt_dlerror());
+ if (lt_dlexit() != 0)
+ xerror("xdlopen: %s\n", lt_dlerror());
+ }
+done: return h;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{ /* obtain address of symbol from dynamically linked library */
+ void *ptr;
+ xassert(h != NULL);
+ ptr = lt_dlsym(h, symbol);
+ if (ptr == NULL)
+ xerror("xdlsym: %s: %s\n", symbol, lt_dlerror());
+ return ptr;
+}
+
+void xdlclose(void *h)
+{ /* close dynamically linked library */
+ xassert(h != NULL);
+ if (lt_dlclose(h) != 0)
+ xerror("xdlclose: %s\n", lt_dlerror());
+ if (lt_dlexit() != 0)
+ xerror("xdlclose: %s\n", lt_dlerror());
+ return;
+}
+
+/* POSIX version ******************************************************/
+
+#elif defined(HAVE_DLFCN)
+
+#include <dlfcn.h>
+
+void *xdlopen(const char *module)
+{ /* open dynamically linked library */
+ void *h;
+ h = dlopen(module, RTLD_NOW);
+ if (h == NULL)
+ put_err_msg(dlerror());
+ return h;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{ /* obtain address of symbol from dynamically linked library */
+ void *ptr;
+ xassert(h != NULL);
+ ptr = dlsym(h, symbol);
+ if (ptr == NULL)
+ xerror("xdlsym: %s: %s\n", symbol, dlerror());
+ return ptr;
+}
+
+void xdlclose(void *h)
+{ /* close dynamically linked library */
+ xassert(h != NULL);
+ if (dlclose(h) != 0)
+ xerror("xdlclose: %s\n", dlerror());
+ return;
+}
+
+/* MS Windows version *************************************************/
+
+#elif defined(__WOE__)
+
+#include <windows.h>
+
+void *xdlopen(const char *module)
+{ /* open dynamically linked library */
+ void *h;
+ h = LoadLibrary(module);
+ if (h == NULL)
+ { char msg[20];
+ sprintf(msg, "Error %d", GetLastError());
+ put_err_msg(msg);
+ }
+ return h;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{ /* obtain address of symbol from dynamically linked library */
+ void *ptr;
+ xassert(h != NULL);
+ ptr = GetProcAddress(h, symbol);
+ if (ptr == NULL)
+ xerror("xdlsym: %s: Error %d\n", symbol, GetLastError());
+ return ptr;
+}
+
+void xdlclose(void *h)
+{ /* close dynamically linked library */
+ xassert(h != NULL);
+ if (!FreeLibrary(h))
+ xerror("xdlclose: Error %d\n", GetLastError());
+ return;
+}
+
+/* NULL version *******************************************************/
+
+#else
+
+void *xdlopen(const char *module)
+{ /* open dynamically linked library */
+ xassert(module == module);
+ put_err_msg("Shared libraries not supported");
+ return NULL;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{ /* obtain address of symbol from dynamically linked library */
+ xassert(h != h);
+ xassert(symbol != symbol);
+ return NULL;
+}
+
+void xdlclose(void *h)
+{ /* close dynamically linked library */
+ xassert(h != h);
+ return;
+}
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/env.c b/test/monniaux/glpk-4.65/src/env/env.c
new file mode 100644
index 00000000..5b901f35
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/env.c
@@ -0,0 +1,316 @@
+/* env.c (GLPK environment initialization/termination) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2017 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/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glpk.h"
+#include "env.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_init_env - initialize GLPK environment
+*
+* SYNOPSIS
+*
+* int glp_init_env(void);
+*
+* DESCRIPTION
+*
+* The routine glp_init_env initializes the GLPK environment. Normally
+* the application program does not need to call this routine, because
+* it is called automatically on the first call to any API routine.
+*
+* RETURNS
+*
+* The routine glp_init_env returns one of the following codes:
+*
+* 0 - initialization successful;
+* 1 - environment has been already initialized;
+* 2 - initialization failed (insufficient memory);
+* 3 - initialization failed (unsupported programming model). */
+
+int glp_init_env(void)
+{ ENV *env;
+ int ok;
+ /* check if the programming model is supported */
+ ok = (CHAR_BIT == 8 && sizeof(char) == 1 &&
+ sizeof(short) == 2 && sizeof(int) == 4 &&
+ (sizeof(void *) == 4 || sizeof(void *) == 8));
+ if (!ok)
+ return 3;
+ /* check if the environment is already initialized */
+ if (tls_get_ptr() != NULL)
+ return 1;
+ /* allocate and initialize the environment block */
+ env = malloc(sizeof(ENV));
+ if (env == NULL)
+ return 2;
+ memset(env, 0, sizeof(ENV));
+#if 0 /* 14/I-2017 */
+ sprintf(env->version, "%d.%d",
+ GLP_MAJOR_VERSION, GLP_MINOR_VERSION);
+#endif
+ env->self = env;
+ env->term_buf = malloc(TBUF_SIZE);
+ if (env->term_buf == NULL)
+ { free(env);
+ return 2;
+ }
+ env->term_out = GLP_ON;
+ env->term_hook = NULL;
+ env->term_info = NULL;
+ env->tee_file = NULL;
+#if 1 /* 23/XI-2015 */
+ env->err_st = 0;
+#endif
+ env->err_file = NULL;
+ env->err_line = 0;
+ env->err_hook = NULL;
+ env->err_info = NULL;
+ env->err_buf = malloc(EBUF_SIZE);
+ if (env->err_buf == NULL)
+ { free(env->term_buf);
+ free(env);
+ return 2;
+ }
+ env->err_buf[0] = '\0';
+ env->mem_limit = SIZE_T_MAX;
+ env->mem_ptr = NULL;
+ env->mem_count = env->mem_cpeak = 0;
+ env->mem_total = env->mem_tpeak = 0;
+#if 1 /* 23/XI-2015 */
+ env->gmp_pool = NULL;
+ env->gmp_size = 0;
+ env->gmp_work = NULL;
+#endif
+ env->h_odbc = env->h_mysql = NULL;
+ /* save pointer to the environment block */
+ tls_set_ptr(env);
+ /* initialization successful */
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* get_env_ptr - retrieve pointer to environment block
+*
+* SYNOPSIS
+*
+* #include "env.h"
+* ENV *get_env_ptr(void);
+*
+* DESCRIPTION
+*
+* The routine get_env_ptr retrieves and returns a pointer to the GLPK
+* environment block.
+*
+* If the GLPK environment has not been initialized yet, the routine
+* performs initialization. If initialization fails, the routine prints
+* an error message to stderr and terminates the program.
+*
+* RETURNS
+*
+* The routine returns a pointer to the environment block. */
+
+ENV *get_env_ptr(void)
+{ ENV *env = tls_get_ptr();
+ /* check if the environment has been initialized */
+ if (env == NULL)
+ { /* not initialized yet; perform initialization */
+ if (glp_init_env() != 0)
+ { /* initialization failed; display an error message */
+ fprintf(stderr, "GLPK initialization failed\n");
+ fflush(stderr);
+ /* and abnormally terminate the program */
+ abort();
+ }
+ /* initialization successful; retrieve the pointer */
+ env = tls_get_ptr();
+ }
+ /* check if the environment block is valid */
+ if (env->self != env)
+ { fprintf(stderr, "Invalid GLPK environment\n");
+ fflush(stderr);
+ abort();
+ }
+ return env;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_version - determine library version
+*
+* SYNOPSIS
+*
+* const char *glp_version(void);
+*
+* RETURNS
+*
+* The routine glp_version returns a pointer to a null-terminated
+* character string, which specifies the version of the GLPK library in
+* the form "X.Y", where X is the major version number, and Y is the
+* minor version number, for example, "4.16". */
+
+#define str(s) # s
+#define xstr(s) str(s)
+
+const char *glp_version(void)
+#if 0 /* 14/I-2017 */
+{ ENV *env = get_env_ptr();
+ return env->version;
+}
+#else /* suggested by Heinrich */
+{ return
+ xstr(GLP_MAJOR_VERSION) "." xstr(GLP_MINOR_VERSION);
+}
+#endif
+
+/***********************************************************************
+* NAME
+*
+* glp_config - determine library configuration
+*
+* SYNOPSIS
+*
+* const char *glp_config(const char *option);
+*
+* DESCRIPTION
+*
+* The routine glp_config determines some options which were specified
+* on configuring the GLPK library.
+*
+* RETURNS
+*
+* The routine glp_config returns a pointer to a null-terminating
+* string depending on the option inquired.
+*
+* For option = "TLS" the routine returns the thread local storage
+* class specifier used (e.g. "_Thread_local") if the GLPK library was
+* configured to run in multi-threaded environment, or NULL otherwise.
+*
+* For option = "ODBC_DLNAME" the routine returns the name of ODBC
+* shared library if this option was enabled, or NULL otherwise.
+*
+* For option = "MYSQL_DLNAME" the routine returns the name of MySQL
+* shared library if this option was enabled, or NULL otherwise. */
+
+const char *glp_config(const char *option)
+{ const char *s;
+ if (strcmp(option, "TLS") == 0)
+#ifndef TLS
+ s = NULL;
+#else
+ s = xstr(TLS);
+#endif
+ else if (strcmp(option, "ODBC_DLNAME") == 0)
+#ifndef ODBC_DLNAME
+ s = NULL;
+#else
+ s = ODBC_DLNAME;
+#endif
+ else if (strcmp(option, "MYSQL_DLNAME") == 0)
+#ifndef MYSQL_DLNAME
+ s = NULL;
+#else
+ s = MYSQL_DLNAME;
+#endif
+ else
+ { /* invalid option is always disabled */
+ s = NULL;
+ }
+ return s;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_free_env - free GLPK environment
+*
+* SYNOPSIS
+*
+* int glp_free_env(void);
+*
+* DESCRIPTION
+*
+* The routine glp_free_env frees all resources used by GLPK routines
+* (memory blocks, etc.) which are currently still in use.
+*
+* Normally the application program does not need to call this routine,
+* because GLPK routines always free all unused resources. However, if
+* the application program even has deleted all problem objects, there
+* will be several memory blocks still allocated for the library needs.
+* For some reasons the application program may want GLPK to free this
+* memory, in which case it should call glp_free_env.
+*
+* Note that a call to glp_free_env invalidates all problem objects as
+* if no GLPK routine were called.
+*
+* RETURNS
+*
+* 0 - termination successful;
+* 1 - environment is inactive (was not initialized). */
+
+int glp_free_env(void)
+{ ENV *env = tls_get_ptr();
+ MBD *desc;
+ /* check if the environment is active */
+ if (env == NULL)
+ return 1;
+ /* check if the environment block is valid */
+ if (env->self != env)
+ { fprintf(stderr, "Invalid GLPK environment\n");
+ fflush(stderr);
+ abort();
+ }
+ /* close handles to shared libraries */
+ if (env->h_odbc != NULL)
+ xdlclose(env->h_odbc);
+ if (env->h_mysql != NULL)
+ xdlclose(env->h_mysql);
+ /* free memory blocks which are still allocated */
+ while (env->mem_ptr != NULL)
+ { desc = env->mem_ptr;
+ env->mem_ptr = desc->next;
+ free(desc);
+ }
+ /* close text file used for copying terminal output */
+ if (env->tee_file != NULL)
+ fclose(env->tee_file);
+ /* invalidate the environment block */
+ env->self = NULL;
+ /* free memory allocated to the environment block */
+ free(env->term_buf);
+ free(env->err_buf);
+ free(env);
+ /* reset a pointer to the environment block */
+ tls_set_ptr(NULL);
+ /* termination successful */
+ return 0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/env.h b/test/monniaux/glpk-4.65/src/env/env.h
new file mode 100644
index 00000000..67214ef6
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/env.h
@@ -0,0 +1,274 @@
+/* env.h (GLPK environment) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2017 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/>.
+***********************************************************************/
+
+#ifndef ENV_H
+#define ENV_H
+
+#include "stdc.h"
+
+typedef struct ENV ENV;
+typedef struct MBD MBD;
+
+#define SIZE_T_MAX (~(size_t)0)
+/* largest value of size_t type */
+
+#define TBUF_SIZE 4096
+/* terminal output buffer size, in bytes */
+
+#define EBUF_SIZE 1024
+/* error message buffer size, in bytes */
+
+/* enable/disable flag: */
+#define GLP_ON 1
+#define GLP_OFF 0
+
+struct ENV
+{ /* GLPK environment block */
+#if 0 /* 14/I-2007 */
+ char version[7+1];
+ /* version string returned by the routine glp_version */
+#endif
+ ENV *self;
+ /* pointer to this block to check its validity */
+ /*--------------------------------------------------------------*/
+ /* terminal output */
+ char *term_buf; /* char term_buf[TBUF_SIZE]; */
+ /* terminal output buffer */
+ int term_out;
+ /* flag to enable/disable terminal output */
+ int (*term_hook)(void *info, const char *s);
+ /* user-defined routine to intercept terminal output */
+ void *term_info;
+ /* transit pointer (cookie) passed to the routine term_hook */
+ FILE *tee_file;
+ /* output stream used to copy terminal output */
+ /*--------------------------------------------------------------*/
+ /* error handling */
+#if 1 /* 07/XI-2015 */
+ int err_st;
+ /* error state flag; set on entry to glp_error */
+#endif
+ const char *err_file;
+ /* value of the __FILE__ macro passed to glp_error */
+ int err_line;
+ /* value of the __LINE__ macro passed to glp_error */
+ void (*err_hook)(void *info);
+ /* user-defined routine to intercept abnormal termination */
+ void *err_info;
+ /* transit pointer (cookie) passed to the routine err_hook */
+ char *err_buf; /* char err_buf[EBUF_SIZE]; */
+ /* buffer to store error messages (used by I/O routines) */
+ /*--------------------------------------------------------------*/
+ /* dynamic memory allocation */
+ size_t mem_limit;
+ /* maximal amount of memory, in bytes, available for dynamic
+ * allocation */
+ MBD *mem_ptr;
+ /* pointer to the linked list of allocated memory blocks */
+ int mem_count;
+ /* total number of currently allocated memory blocks */
+ int mem_cpeak;
+ /* peak value of mem_count */
+ size_t mem_total;
+ /* total amount of currently allocated memory, in bytes; it is
+ * the sum of the size field over all memory block descriptors */
+ size_t mem_tpeak;
+ /* peak value of mem_total */
+#if 1 /* 23/XI-2015 */
+ /*--------------------------------------------------------------*/
+ /* bignum module working area */
+ void *gmp_pool; /* DMP *gmp_pool; */
+ /* working memory pool */
+ int gmp_size;
+ /* size of working array */
+ unsigned short *gmp_work; /* ushort gmp_work[gmp_size]; */
+ /* working array */
+#endif
+ /*--------------------------------------------------------------*/
+ /* dynamic linking support (optional) */
+ void *h_odbc;
+ /* handle to ODBC shared library */
+ void *h_mysql;
+ /* handle to MySQL shared library */
+};
+
+struct MBD
+{ /* memory block descriptor */
+ size_t size;
+ /* size of block, in bytes, including descriptor */
+ MBD *self;
+ /* pointer to this descriptor to check its validity */
+ MBD *prev;
+ /* pointer to previous memory block descriptor */
+ MBD *next;
+ /* pointer to next memory block descriptor */
+};
+
+#define get_env_ptr _glp_get_env_ptr
+ENV *get_env_ptr(void);
+/* retrieve pointer to environment block */
+
+#define tls_set_ptr _glp_tls_set_ptr
+void tls_set_ptr(void *ptr);
+/* store global pointer in TLS */
+
+#define tls_get_ptr _glp_tls_get_ptr
+void *tls_get_ptr(void);
+/* retrieve global pointer from TLS */
+
+#define xputs glp_puts
+void glp_puts(const char *s);
+/* write string on terminal */
+
+#define xprintf glp_printf
+void glp_printf(const char *fmt, ...);
+/* write formatted output on terminal */
+
+#define xvprintf glp_vprintf
+void glp_vprintf(const char *fmt, va_list arg);
+/* write formatted output on terminal */
+
+int glp_term_out(int flag);
+/* enable/disable terminal output */
+
+void glp_term_hook(int (*func)(void *info, const char *s), void *info);
+/* install hook to intercept terminal output */
+
+int glp_open_tee(const char *fname);
+/* start copying terminal output to text file */
+
+int glp_close_tee(void);
+/* stop copying terminal output to text file */
+
+#ifndef GLP_ERRFUNC_DEFINED
+#define GLP_ERRFUNC_DEFINED
+typedef void (*glp_errfunc)(const char *fmt, ...);
+#endif
+
+#define xerror glp_error_(__FILE__, __LINE__)
+glp_errfunc glp_error_(const char *file, int line);
+/* display fatal error message and terminate execution */
+
+#define xassert(expr) \
+ ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1)))
+void glp_assert_(const char *expr, const char *file, int line);
+/* check for logical condition */
+
+void glp_error_hook(void (*func)(void *info), void *info);
+/* install hook to intercept abnormal termination */
+
+#define put_err_msg _glp_put_err_msg
+void put_err_msg(const char *msg);
+/* provide error message string */
+
+#define get_err_msg _glp_get_err_msg
+const char *get_err_msg(void);
+/* obtain error message string */
+
+#define xmalloc(size) glp_alloc(1, size)
+/* allocate memory block (obsolete) */
+
+#define xcalloc(n, size) glp_alloc(n, size)
+/* allocate memory block (obsolete) */
+
+#define xalloc(n, size) glp_alloc(n, size)
+#define talloc(n, type) ((type *)glp_alloc(n, sizeof(type)))
+void *glp_alloc(int n, int size);
+/* allocate memory block */
+
+#define xrealloc(ptr, n, size) glp_realloc(ptr, n, size)
+#define trealloc(ptr, n, type) ((type *)glp_realloc(ptr, n, \
+ sizeof(type)))
+void *glp_realloc(void *ptr, int n, int size);
+/* reallocate memory block */
+
+#define xfree(ptr) glp_free(ptr)
+#define tfree(ptr) glp_free(ptr)
+void glp_free(void *ptr);
+/* free memory block */
+
+void glp_mem_limit(int limit);
+/* set memory usage limit */
+
+void glp_mem_usage(int *count, int *cpeak, size_t *total,
+ size_t *tpeak);
+/* get memory usage information */
+
+typedef struct glp_file glp_file;
+/* sequential stream descriptor */
+
+#define glp_open _glp_open
+glp_file *glp_open(const char *name, const char *mode);
+/* open stream */
+
+#define glp_eof _glp_eof
+int glp_eof(glp_file *f);
+/* test end-of-file indicator */
+
+#define glp_ioerr _glp_ioerr
+int glp_ioerr(glp_file *f);
+/* test I/O error indicator */
+
+#define glp_read _glp_read
+int glp_read(glp_file *f, void *buf, int nnn);
+/* read data from stream */
+
+#define glp_getc _glp_getc
+int glp_getc(glp_file *f);
+/* read character from stream */
+
+#define glp_write _glp_write
+int glp_write(glp_file *f, const void *buf, int nnn);
+/* write data to stream */
+
+#define glp_format _glp_format
+int glp_format(glp_file *f, const char *fmt, ...);
+/* write formatted data to stream */
+
+#define glp_close _glp_close
+int glp_close(glp_file *f);
+/* close stream */
+
+#define xtime glp_time
+double glp_time(void);
+/* determine current universal time */
+
+#define xdifftime glp_difftime
+double glp_difftime(double t1, double t0);
+/* compute difference between two time values */
+
+#define xdlopen _glp_dlopen
+void *xdlopen(const char *module);
+/* open dynamically linked library */
+
+#define xdlsym _glp_dlsym
+void *xdlsym(void *h, const char *symbol);
+/* obtain address of symbol from dynamically linked library */
+
+#define xdlclose _glp_dlclose
+void xdlclose(void *h);
+/* close dynamically linked library */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/error.c b/test/monniaux/glpk-4.65/src/env/error.c
new file mode 100644
index 00000000..a898b768
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/error.c
@@ -0,0 +1,200 @@
+/* error.c (error handling) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2015 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/>.
+***********************************************************************/
+
+#include "env.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_error - display fatal error message and terminate execution
+*
+* SYNOPSIS
+*
+* void glp_error(const char *fmt, ...);
+*
+* DESCRIPTION
+*
+* The routine glp_error (implemented as a macro) formats its
+* parameters using the format control string fmt, writes the formatted
+* message on the terminal, and abnormally terminates the program. */
+
+static void errfunc(const char *fmt, ...)
+{ ENV *env = get_env_ptr();
+ va_list arg;
+#if 1 /* 07/XI-2015 */
+ env->err_st = 1;
+#endif
+ env->term_out = GLP_ON;
+ va_start(arg, fmt);
+ xvprintf(fmt, arg);
+ va_end(arg);
+ xprintf("Error detected in file %s at line %d\n",
+ env->err_file, env->err_line);
+ if (env->err_hook != NULL)
+ env->err_hook(env->err_info);
+ abort();
+ exit(EXIT_FAILURE);
+ /* no return */
+}
+
+glp_errfunc glp_error_(const char *file, int line)
+{ ENV *env = get_env_ptr();
+ env->err_file = file;
+ env->err_line = line;
+ return errfunc;
+}
+
+#if 1 /* 07/XI-2015 */
+/***********************************************************************
+* NAME
+*
+* glp_at_error - check for error state
+*
+* SYNOPSIS
+*
+* int glp_at_error(void);
+*
+* DESCRIPTION
+*
+* The routine glp_at_error checks if the GLPK environment is at error
+* state, i.e. if the call to the routine is (indirectly) made from the
+* glp_error routine via an user-defined hook routine.
+*
+* RETURNS
+*
+* If the GLPK environment is at error state, the routine glp_at_error
+* returns non-zero, otherwise zero. */
+
+int glp_at_error(void)
+{ ENV *env = get_env_ptr();
+ return env->err_st;
+}
+#endif
+
+/***********************************************************************
+* NAME
+*
+* glp_assert - check for logical condition
+*
+* SYNOPSIS
+*
+* void glp_assert(int expr);
+*
+* DESCRIPTION
+*
+* The routine glp_assert (implemented as a macro) checks for a logical
+* condition specified by the parameter expr. If the condition is false
+* (i.e. the value of expr is zero), the routine writes a message on
+* the terminal and abnormally terminates the program. */
+
+void glp_assert_(const char *expr, const char *file, int line)
+{ glp_error_(file, line)("Assertion failed: %s\n", expr);
+ /* no return */
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_error_hook - install hook to intercept abnormal termination
+*
+* SYNOPSIS
+*
+* void glp_error_hook(void (*func)(void *info), void *info);
+*
+* DESCRIPTION
+*
+* The routine glp_error_hook installs a user-defined hook routine to
+* intercept abnormal termination.
+*
+* The parameter func specifies the user-defined hook routine. It is
+* called from the routine glp_error before the latter calls the abort
+* function to abnormally terminate the application program because of
+* fatal error. The parameter info is a transit pointer, specified in
+* the corresponding call to the routine glp_error_hook; it may be used
+* to pass some information to the hook routine.
+*
+* To uninstall the hook routine the parameters func and info should be
+* both specified as NULL. */
+
+void glp_error_hook(void (*func)(void *info), void *info)
+{ ENV *env = get_env_ptr();
+ if (func == NULL)
+ { env->err_hook = NULL;
+ env->err_info = NULL;
+ }
+ else
+ { env->err_hook = func;
+ env->err_info = info;
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* put_err_msg - provide error message string
+*
+* SYNOPSIS
+*
+* #include "env.h"
+* void put_err_msg(const char *msg);
+*
+* DESCRIPTION
+*
+* The routine put_err_msg stores an error message string pointed to by
+* msg to the environment block. */
+
+void put_err_msg(const char *msg)
+{ ENV *env = get_env_ptr();
+ int len;
+ len = strlen(msg);
+ if (len >= EBUF_SIZE)
+ len = EBUF_SIZE - 1;
+ memcpy(env->err_buf, msg, len);
+ if (len > 0 && env->err_buf[len-1] == '\n')
+ len--;
+ env->err_buf[len] = '\0';
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* get_err_msg - obtain error message string
+*
+* SYNOPSIS
+*
+* #include "env.h"
+* const char *get_err_msg(void);
+*
+* RETURNS
+*
+* The routine get_err_msg returns a pointer to an error message string
+* previously stored by the routine put_err_msg. */
+
+const char *get_err_msg(void)
+{ ENV *env = get_env_ptr();
+ return env->err_buf;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/stdc.c b/test/monniaux/glpk-4.65/src/env/stdc.c
new file mode 100644
index 00000000..59331e22
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/stdc.c
@@ -0,0 +1,98 @@
+/* stdc.c (replacements for standard non-thread-safe functions) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2017 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/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* portable ANSI C version ********************************************/
+
+#if !defined(TLS)
+
+#define ENABLE_NON_SAFE
+#include "stdc.h"
+
+struct tm *xgmtime(const time_t *timer)
+{ return
+ gmtime(timer);
+}
+
+char *xstrerr(int errnum)
+{ return
+ strerror(errnum);
+}
+
+char *xstrtok(char *s1, const char *s2)
+{ return
+ strtok(s1, s2);
+}
+
+/* MS Windows version *************************************************/
+
+#elif defined(__WOE__)
+
+#include "stdc.h"
+
+struct tm *xgmtime(const time_t *timer)
+{ static TLS struct tm result;
+ gmtime_s(&result, timer);
+ return &result;
+}
+
+char *xstrerr(int errnum)
+{ static TLS char s[1023+1];
+ strerror_s(s, sizeof(s), errnum);
+ return s;
+}
+
+char *xstrtok(char *s1, const char *s2)
+{ static TLS char *ptr;
+ return strtok_s(s1, s2, &ptr);
+}
+
+/* GNU/Linux version **************************************************/
+
+#else
+
+#include "stdc.h"
+
+struct tm *xgmtime(const time_t *timer)
+{ static TLS struct tm result;
+ gmtime_r(timer, &result);
+ return &result;
+}
+
+char *xstrerr(int errnum)
+{ static TLS char s[1023+1];
+ strerror_r(errnum, s, sizeof(s));
+ return s;
+}
+
+char *xstrtok(char *s1, const char *s2)
+{ static TLS char *ptr;
+ return strtok_r(s1, s2, &ptr);
+}
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/stdc.h b/test/monniaux/glpk-4.65/src/env/stdc.h
new file mode 100644
index 00000000..a376f2c9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/stdc.h
@@ -0,0 +1,73 @@
+/* stdc.h (standard ANSI C headers) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2017 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/>.
+***********************************************************************/
+
+#ifndef STDC_H
+#define STDC_H
+
+#include <ctype.h>
+#include <errno.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef ENABLE_NON_SAFE /* 29/I-2017 */
+/* disable using non-thread-safe functions directly */
+#undef gmtime
+#define gmtime ???
+#undef strerror
+#define strerror ???
+#undef strtok
+#define strtok ???
+#endif
+
+#if 1 /* 29/I-2017 */
+/* provide replacements for these functions on a per-thread basis */
+#define xgmtime _glp_xgmtime
+struct tm *xgmtime(const time_t *);
+#define xstrerr _glp_xstrerr
+char *xstrerr(int);
+#define xstrtok _glp_xstrtok
+char *xstrtok(char *, const char *);
+#endif
+
+#if 1 /* 06/II-2018 */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifndef __WOE__
+#define CDECL
+#else
+#define CDECL __cdecl
+#endif
+#endif
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/stdout.c b/test/monniaux/glpk-4.65/src/env/stdout.c
new file mode 100644
index 00000000..94eee02a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/stdout.c
@@ -0,0 +1,262 @@
+/* stdout.c (terminal output) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#undef NDEBUG
+#include <assert.h>
+#include "env.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_puts - write string on terminal
+*
+* SYNOPSIS
+*
+* void glp_puts(const char *s);
+*
+* The routine glp_puts writes the string s on the terminal. */
+
+void glp_puts(const char *s)
+{ ENV *env = get_env_ptr();
+ /* if terminal output is disabled, do nothing */
+ if (!env->term_out)
+ goto skip;
+ /* pass the string to the hook routine, if defined */
+ if (env->term_hook != NULL)
+ { if (env->term_hook(env->term_info, s) != 0)
+ goto skip;
+ }
+ /* write the string on the terminal */
+ fputs(s, stdout);
+ fflush(stdout);
+ /* write the string on the tee file, if required */
+ if (env->tee_file != NULL)
+ { fputs(s, env->tee_file);
+ fflush(env->tee_file);
+ }
+skip: return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_printf - write formatted output on terminal
+*
+* SYNOPSIS
+*
+* void glp_printf(const char *fmt, ...);
+*
+* DESCRIPTION
+*
+* The routine glp_printf uses the format control string fmt to format
+* its parameters and writes the formatted output on the terminal. */
+
+void glp_printf(const char *fmt, ...)
+{ ENV *env = get_env_ptr();
+ va_list arg;
+ /* if terminal output is disabled, do nothing */
+ if (!env->term_out)
+ goto skip;
+ /* format the output */
+ va_start(arg, fmt);
+ vsprintf(env->term_buf, fmt, arg);
+ /* (do not use xassert) */
+ assert(strlen(env->term_buf) < TBUF_SIZE);
+ va_end(arg);
+ /* write the formatted output on the terminal */
+ glp_puts(env->term_buf);
+skip: return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_vprintf - write formatted output on terminal
+*
+* SYNOPSIS
+*
+* void glp_vprintf(const char *fmt, va_list arg);
+*
+* DESCRIPTION
+*
+* The routine glp_vprintf uses the format control string fmt to format
+* its parameters specified by the list arg and writes the formatted
+* output on the terminal. */
+
+void glp_vprintf(const char *fmt, va_list arg)
+{ ENV *env = get_env_ptr();
+ /* if terminal output is disabled, do nothing */
+ if (!env->term_out)
+ goto skip;
+ /* format the output */
+ vsprintf(env->term_buf, fmt, arg);
+ /* (do not use xassert) */
+ assert(strlen(env->term_buf) < TBUF_SIZE);
+ /* write the formatted output on the terminal */
+ glp_puts(env->term_buf);
+skip: return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_term_out - enable/disable terminal output
+*
+* SYNOPSIS
+*
+* int glp_term_out(int flag);
+*
+* DESCRIPTION
+*
+* Depending on the parameter flag the routine glp_term_out enables or
+* disables terminal output performed by glpk routines:
+*
+* GLP_ON - enable terminal output;
+* GLP_OFF - disable terminal output.
+*
+* RETURNS
+*
+* The routine glp_term_out returns the previous value of the terminal
+* output flag. */
+
+int glp_term_out(int flag)
+{ ENV *env = get_env_ptr();
+ int old = env->term_out;
+ if (!(flag == GLP_ON || flag == GLP_OFF))
+ xerror("glp_term_out: flag = %d; invalid parameter\n", flag);
+ env->term_out = flag;
+ return old;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_term_hook - install hook to intercept terminal output
+*
+* SYNOPSIS
+*
+* void glp_term_hook(int (*func)(void *info, const char *s),
+* void *info);
+*
+* DESCRIPTION
+*
+* The routine glp_term_hook installs a user-defined hook routine to
+* intercept all terminal output performed by glpk routines.
+*
+* This feature can be used to redirect the terminal output to other
+* destination, for example to a file or a text window.
+*
+* The parameter func specifies the user-defined hook routine. It is
+* called from an internal printing routine, which passes to it two
+* parameters: info and s. The parameter info is a transit pointer,
+* specified in the corresponding call to the routine glp_term_hook;
+* it may be used to pass some information to the hook routine. The
+* parameter s is a pointer to the null terminated character string,
+* which is intended to be written to the terminal. If the hook routine
+* returns zero, the printing routine writes the string s to the
+* terminal in a usual way; otherwise, if the hook routine returns
+* non-zero, no terminal output is performed.
+*
+* To uninstall the hook routine the parameters func and info should be
+* specified as NULL. */
+
+void glp_term_hook(int (*func)(void *info, const char *s), void *info)
+{ ENV *env = get_env_ptr();
+ if (func == NULL)
+ { env->term_hook = NULL;
+ env->term_info = NULL;
+ }
+ else
+ { env->term_hook = func;
+ env->term_info = info;
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_open_tee - start copying terminal output to text file
+*
+* SYNOPSIS
+*
+* int glp_open_tee(const char *name);
+*
+* DESCRIPTION
+*
+* The routine glp_open_tee starts copying all the terminal output to
+* an output text file, whose name is specified by the character string
+* name.
+*
+* RETURNS
+*
+* 0 - operation successful
+* 1 - copying terminal output is already active
+* 2 - unable to create output file */
+
+int glp_open_tee(const char *name)
+{ ENV *env = get_env_ptr();
+ if (env->tee_file != NULL)
+ { /* copying terminal output is already active */
+ return 1;
+ }
+ env->tee_file = fopen(name, "w");
+ if (env->tee_file == NULL)
+ { /* unable to create output file */
+ return 2;
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_close_tee - stop copying terminal output to text file
+*
+* SYNOPSIS
+*
+* int glp_close_tee(void);
+*
+* DESCRIPTION
+*
+* The routine glp_close_tee stops copying the terminal output to the
+* output text file previously open by the routine glp_open_tee closing
+* that file.
+*
+* RETURNS
+*
+* 0 - operation successful
+* 1 - copying terminal output was not started */
+
+int glp_close_tee(void)
+{ ENV *env = get_env_ptr();
+ if (env->tee_file == NULL)
+ { /* copying terminal output was not started */
+ return 1;
+ }
+ fclose(env->tee_file);
+ env->tee_file = NULL;
+ return 0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/stream.c b/test/monniaux/glpk-4.65/src/env/stream.c
new file mode 100644
index 00000000..906e5b04
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/stream.c
@@ -0,0 +1,517 @@
+/* stream.c (stream input/output) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2008-2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "zlib.h"
+
+struct glp_file
+{ /* sequential stream descriptor */
+ char *base;
+ /* pointer to buffer */
+ int size;
+ /* size of buffer, in bytes */
+ char *ptr;
+ /* pointer to next byte in buffer */
+ int cnt;
+ /* count of bytes in buffer */
+ int flag;
+ /* stream flags: */
+#define IONULL 0x01 /* null file */
+#define IOSTD 0x02 /* standard stream */
+#define IOGZIP 0x04 /* gzipped file */
+#define IOWRT 0x08 /* output stream */
+#define IOEOF 0x10 /* end of file */
+#define IOERR 0x20 /* input/output error */
+ void *file;
+ /* pointer to underlying control object */
+};
+
+/***********************************************************************
+* NAME
+*
+* glp_open - open stream
+*
+* SYNOPSIS
+*
+* glp_file *glp_open(const char *name, const char *mode);
+*
+* DESCRIPTION
+*
+* The routine glp_open opens a file whose name is a string pointed to
+* by name and associates a stream with it.
+*
+* The following special filenames are recognized by the routine (this
+* feature is platform independent):
+*
+* "/dev/null" empty (null) file;
+* "/dev/stdin" standard input stream;
+* "/dev/stdout" standard output stream;
+* "/dev/stderr" standard error stream.
+*
+* If the specified filename is ended with ".gz", it is assumed that
+* the file is in gzipped format. In this case the file is compressed
+* or decompressed by the I/O routines "on the fly".
+*
+* The parameter mode points to a string, which indicates the open mode
+* and should be one of the following:
+*
+* "r" open text file for reading;
+* "w" truncate to zero length or create text file for writing;
+* "a" append, open or create text file for writing at end-of-file;
+* "rb" open binary file for reading;
+* "wb" truncate to zero length or create binary file for writing;
+* "ab" append, open or create binary file for writing at end-of-file.
+*
+* RETURNS
+*
+* The routine glp_open returns a pointer to the object controlling the
+* stream. If the operation fails, the routine returns NULL. */
+
+glp_file *glp_open(const char *name, const char *mode)
+{ glp_file *f;
+ int flag;
+ void *file;
+ if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0)
+ flag = 0;
+ else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0)
+ flag = IOWRT;
+#if 1 /* 08/V-2014 */
+ else if (strcmp(mode, "a") == 0 || strcmp(mode, "ab") == 0)
+ flag = IOWRT;
+#endif
+ else
+ xerror("glp_open: invalid mode string\n");
+ if (strcmp(name, "/dev/null") == 0)
+ { flag |= IONULL;
+ file = NULL;
+ }
+ else if (strcmp(name, "/dev/stdin") == 0)
+ { flag |= IOSTD;
+ file = stdin;
+ }
+ else if (strcmp(name, "/dev/stdout") == 0)
+ { flag |= IOSTD;
+ file = stdout;
+ }
+ else if (strcmp(name, "/dev/stderr") == 0)
+ { flag |= IOSTD;
+ file = stderr;
+ }
+ else
+ { char *ext = strrchr(name, '.');
+ if (ext == NULL || strcmp(ext, ".gz") != 0)
+ { file = fopen(name, mode);
+ if (file == NULL)
+#if 0 /* 29/I-2017 */
+ { put_err_msg(strerror(errno));
+#else
+ { put_err_msg(xstrerr(errno));
+#endif
+ return NULL;
+ }
+ }
+ else
+ { flag |= IOGZIP;
+ if (strcmp(mode, "r") == 0)
+ mode = "rb";
+ else if (strcmp(mode, "w") == 0)
+ mode = "wb";
+#if 1 /* 08/V-2014; this mode seems not to work */
+ else if (strcmp(mode, "a") == 0)
+ mode = "ab";
+#endif
+ file = gzopen(name, mode);
+ if (file == NULL)
+#if 0 /* 29/I-2017 */
+ { put_err_msg(strerror(errno));
+#else
+ { put_err_msg(xstrerr(errno));
+#endif
+ return NULL;
+ }
+ }
+ }
+ f = talloc(1, glp_file);
+ f->base = talloc(BUFSIZ, char);
+ f->size = BUFSIZ;
+ f->ptr = f->base;
+ f->cnt = 0;
+ f->flag = flag;
+ f->file = file;
+ return f;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_eof - test end-of-file indicator
+*
+* SYNOPSIS
+*
+* int glp_eof(glp_file *f);
+*
+* DESCRIPTION
+*
+* The routine glp_eof tests the end-of-file indicator for the stream
+* pointed to by f.
+*
+* RETURNS
+*
+* The routine glp_eof returns non-zero if and only if the end-of-file
+* indicator is set for the specified stream. */
+
+int glp_eof(glp_file *f)
+{ return
+ f->flag & IOEOF;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_ioerr - test I/O error indicator
+*
+* SYNOPSIS
+*
+* int glp_ioerr(glp_file *f);
+*
+* DESCRIPTION
+*
+* The routine glp_ioerr tests the I/O error indicator for the stream
+* pointed to by f.
+*
+* RETURNS
+*
+* The routine glp_ioerr returns non-zero if and only if the I/O error
+* indicator is set for the specified stream. */
+
+int glp_ioerr(glp_file *f)
+{ return
+ f->flag & IOERR;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_read - read data from stream
+*
+* SYNOPSIS
+*
+* int glp_read(glp_file *f, void *buf, int nnn);
+*
+* DESCRIPTION
+*
+* The routine glp_read reads, into the buffer pointed to by buf, up to
+* nnn bytes, from the stream pointed to by f.
+*
+* RETURNS
+*
+* The routine glp_read returns the number of bytes successfully read
+* (which may be less than nnn). If an end-of-file is encountered, the
+* end-of-file indicator for the stream is set and glp_read returns
+* zero. If a read error occurs, the error indicator for the stream is
+* set and glp_read returns a negative value. */
+
+int glp_read(glp_file *f, void *buf, int nnn)
+{ int nrd, cnt;
+ if (f->flag & IOWRT)
+ xerror("glp_read: attempt to read from output stream\n");
+ if (nnn < 1)
+ xerror("glp_read: nnn = %d; invalid parameter\n", nnn);
+ for (nrd = 0; nrd < nnn; nrd += cnt)
+ { if (f->cnt == 0)
+ { /* buffer is empty; fill it */
+ if (f->flag & IONULL)
+ cnt = 0;
+ else if (!(f->flag & IOGZIP))
+ { cnt = fread(f->base, 1, f->size, (FILE *)(f->file));
+ if (ferror((FILE *)(f->file)))
+ { f->flag |= IOERR;
+#if 0 /* 29/I-2017 */
+ put_err_msg(strerror(errno));
+#else
+ put_err_msg(xstrerr(errno));
+#endif
+ return EOF;
+ }
+ }
+ else
+ { int errnum;
+ const char *msg;
+ cnt = gzread((gzFile)(f->file), f->base, f->size);
+ if (cnt < 0)
+ { f->flag |= IOERR;
+ msg = gzerror((gzFile)(f->file), &errnum);
+ if (errnum == Z_ERRNO)
+#if 0 /* 29/I-2017 */
+ put_err_msg(strerror(errno));
+#else
+ put_err_msg(xstrerr(errno));
+#endif
+ else
+ put_err_msg(msg);
+ return EOF;
+ }
+ }
+ if (cnt == 0)
+ { if (nrd == 0)
+ f->flag |= IOEOF;
+ break;
+ }
+ f->ptr = f->base;
+ f->cnt = cnt;
+ }
+ cnt = nnn - nrd;
+ if (cnt > f->cnt)
+ cnt = f->cnt;
+ memcpy((char *)buf + nrd, f->ptr, cnt);
+ f->ptr += cnt;
+ f->cnt -= cnt;
+ }
+ return nrd;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_getc - read character from stream
+*
+* SYNOPSIS
+*
+* int glp_getc(glp_file *f);
+*
+* DESCRIPTION
+*
+* The routine glp_getc obtains a next character as an unsigned char
+* converted to an int from the input stream pointed to by f.
+*
+* RETURNS
+*
+* The routine glp_getc returns the next character obtained. However,
+* if an end-of-file is encountered or a read error occurs, the routine
+* returns EOF. (An end-of-file and a read error can be distinguished
+* by use of the routines glp_eof and glp_ioerr.) */
+
+int glp_getc(glp_file *f)
+{ unsigned char buf[1];
+ if (f->flag & IOWRT)
+ xerror("glp_getc: attempt to read from output stream\n");
+ if (glp_read(f, buf, 1) != 1)
+ return EOF;
+ return buf[0];
+}
+
+/***********************************************************************
+* do_flush - flush output stream
+*
+* This routine causes buffered data for the specified output stream to
+* be written to the associated file.
+*
+* If the operation was successful, the routine returns zero, otherwise
+* non-zero. */
+
+static int do_flush(glp_file *f)
+{ xassert(f->flag & IOWRT);
+ if (f->cnt > 0)
+ { if (f->flag & IONULL)
+ ;
+ else if (!(f->flag & IOGZIP))
+ { if ((int)fwrite(f->base, 1, f->cnt, (FILE *)(f->file))
+ != f->cnt)
+ { f->flag |= IOERR;
+#if 0 /* 29/I-2017 */
+ put_err_msg(strerror(errno));
+#else
+ put_err_msg(xstrerr(errno));
+#endif
+ return EOF;
+ }
+ }
+ else
+ { int errnum;
+ const char *msg;
+ if (gzwrite((gzFile)(f->file), f->base, f->cnt) != f->cnt)
+ { f->flag |= IOERR;
+ msg = gzerror((gzFile)(f->file), &errnum);
+ if (errnum == Z_ERRNO)
+#if 0 /* 29/I-2017 */
+ put_err_msg(strerror(errno));
+#else
+ put_err_msg(xstrerr(errno));
+#endif
+ else
+ put_err_msg(msg);
+ return EOF;
+ }
+ }
+ }
+ f->ptr = f->base;
+ f->cnt = 0;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_write - write data to stream
+*
+* SYNOPSIS
+*
+* int glp_write(glp_file *f, const void *buf, int nnn);
+*
+* DESCRIPTION
+*
+* The routine glp_write writes, from the buffer pointed to by buf, up
+* to nnn bytes, to the stream pointed to by f.
+*
+* RETURNS
+*
+* The routine glp_write returns the number of bytes successfully
+* written (which is equal to nnn). If a write error occurs, the error
+* indicator for the stream is set and glp_write returns a negative
+* value. */
+
+int glp_write(glp_file *f, const void *buf, int nnn)
+{ int nwr, cnt;
+ if (!(f->flag & IOWRT))
+ xerror("glp_write: attempt to write to input stream\n");
+ if (nnn < 1)
+ xerror("glp_write: nnn = %d; invalid parameter\n", nnn);
+ for (nwr = 0; nwr < nnn; nwr += cnt)
+ { cnt = nnn - nwr;
+ if (cnt > f->size - f->cnt)
+ cnt = f->size - f->cnt;
+ memcpy(f->ptr, (const char *)buf + nwr, cnt);
+ f->ptr += cnt;
+ f->cnt += cnt;
+ if (f->cnt == f->size)
+ { /* buffer is full; flush it */
+ if (do_flush(f) != 0)
+ return EOF;
+ }
+ }
+ return nwr;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_format - write formatted data to stream
+*
+* SYNOPSIS
+*
+* int glp_format(glp_file *f, const char *fmt, ...);
+*
+* DESCRIPTION
+*
+* The routine glp_format writes formatted data to the stream pointed
+* to by f. The format control string pointed to by fmt specifies how
+* subsequent arguments are converted for output.
+*
+* RETURNS
+*
+* The routine glp_format returns the number of characters written, or
+* a negative value if an output error occurs. */
+
+int glp_format(glp_file *f, const char *fmt, ...)
+{ ENV *env = get_env_ptr();
+ va_list arg;
+ int nnn;
+ if (!(f->flag & IOWRT))
+ xerror("glp_format: attempt to write to input stream\n");
+ va_start(arg, fmt);
+ nnn = vsprintf(env->term_buf, fmt, arg);
+ xassert(0 <= nnn && nnn < TBUF_SIZE);
+ va_end(arg);
+ return nnn == 0 ? 0 : glp_write(f, env->term_buf, nnn);
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_close - close stream
+*
+* SYNOPSIS
+*
+* int glp_close(glp_file *f);
+*
+* DESCRIPTION
+*
+* The routine glp_close closes the stream pointed to by f.
+*
+* RETURNS
+*
+* If the operation was successful, the routine returns zero, otherwise
+* non-zero. */
+
+int glp_close(glp_file *f)
+{ int ret = 0;
+ if (f->flag & IOWRT)
+ { if (do_flush(f) != 0)
+ ret = EOF;
+ }
+ if (f->flag & (IONULL | IOSTD))
+ ;
+ else if (!(f->flag & IOGZIP))
+ { if (fclose((FILE *)(f->file)) != 0)
+ { if (ret == 0)
+#if 0 /* 29/I-2017 */
+ { put_err_msg(strerror(errno));
+#else
+ { put_err_msg(xstrerr(errno));
+#endif
+ ret = EOF;
+ }
+ }
+ }
+ else
+ { int errnum;
+ errnum = gzclose((gzFile)(f->file));
+ if (errnum == Z_OK)
+ ;
+ else if (errnum == Z_ERRNO)
+ { if (ret == 0)
+#if 0 /* 29/I-2017 */
+ { put_err_msg(strerror(errno));
+#else
+ { put_err_msg(xstrerr(errno));
+#endif
+ ret = EOF;
+ }
+ }
+#if 1 /* FIXME */
+ else
+ { if (ret == 0)
+ { ENV *env = get_env_ptr();
+ sprintf(env->term_buf, "gzclose returned %d", errnum);
+ put_err_msg(env->term_buf);
+ ret = EOF;
+ }
+ }
+#endif
+ }
+ tfree(f->base);
+ tfree(f);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/time.c b/test/monniaux/glpk-4.65/src/env/time.c
new file mode 100644
index 00000000..1ffb28e9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/time.c
@@ -0,0 +1,150 @@
+/* time.c (standard time) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2017 Andrew Makhorin, Department for Applied
+* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
+* reserved. E-mail: <address@hidden>.
+*
+* 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/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "env.h"
+#include "jd.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_time - determine current universal time
+*
+* SYNOPSIS
+*
+* double glp_time(void);
+*
+* RETURNS
+*
+* The routine glp_time returns the current universal time (UTC), in
+* milliseconds, elapsed since 00:00:00 GMT January 1, 1970. */
+
+#define EPOCH 2440588 /* = jday(1, 1, 1970) */
+
+/* POSIX version ******************************************************/
+
+#if defined(HAVE_SYS_TIME_H) && defined(HAVE_GETTIMEOFDAY)
+
+#if 0 /* 29/VI-2017 */
+#include <sys/time.h>
+#include <time.h>
+
+double glp_time(void)
+{ struct timeval tv;
+ struct tm *tm;
+ int j;
+ double t;
+ gettimeofday(&tv, NULL);
+#if 0 /* 29/I-2017 */
+ tm = gmtime(&tv.tv_sec);
+#else
+ tm = xgmtime(&tv.tv_sec);
+#endif
+ j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+ xassert(j >= 0);
+ t = ((((double)(j - EPOCH) * 24.0 + (double)tm->tm_hour) * 60.0 +
+ (double)tm->tm_min) * 60.0 + (double)tm->tm_sec) * 1000.0 +
+ (double)(tv.tv_usec / 1000);
+ return t;
+}
+#else
+#include <sys/time.h>
+
+double glp_time(void)
+{ struct timeval tv;
+ double t;
+ gettimeofday(&tv, NULL);
+ t = (double)tv.tv_sec + (double)(tv.tv_usec) / 1e6;
+ xassert(0.0 <= t && t < 4294967296.0);
+ return 1000.0 * t;
+}
+#endif
+
+/* MS Windows version *************************************************/
+
+#elif defined(__WOE__)
+
+#include <windows.h>
+
+double glp_time(void)
+{ SYSTEMTIME st;
+ int j;
+ double t;
+ GetSystemTime(&st);
+ j = jday(st.wDay, st.wMonth, st.wYear);
+ xassert(j >= 0);
+ t = ((((double)(j - EPOCH) * 24.0 + (double)st.wHour) * 60.0 +
+ (double)st.wMinute) * 60.0 + (double)st.wSecond) * 1000.0 +
+ (double)st.wMilliseconds;
+ return t;
+}
+
+/* portable ANSI C version ********************************************/
+
+#else
+
+#include <time.h>
+
+double glp_time(void)
+{ time_t timer;
+ struct tm *tm;
+ int j;
+ double t;
+ timer = time(NULL);
+#if 0 /* 29/I-2017 */
+ tm = gmtime(&timer);
+#else
+ tm = xgmtime(&timer);
+#endif
+ j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+ xassert(j >= 0);
+ t = ((((double)(j - EPOCH) * 24.0 + (double)tm->tm_hour) * 60.0 +
+ (double)tm->tm_min) * 60.0 + (double)tm->tm_sec) * 1000.0;
+ return t;
+}
+
+#endif
+
+/***********************************************************************
+* NAME
+*
+* glp_difftime - compute difference between two time values
+*
+* SYNOPSIS
+*
+* double glp_difftime(double t1, double t0);
+*
+* RETURNS
+*
+* The routine glp_difftime returns the difference between two time
+* values t1 and t0, expressed in seconds. */
+
+double glp_difftime(double t1, double t0)
+{ return
+ (t1 - t0) / 1000.0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/env/tls.c b/test/monniaux/glpk-4.65/src/env/tls.c
new file mode 100644
index 00000000..4062ee4c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/env/tls.c
@@ -0,0 +1,128 @@
+/* tls.c (thread local storage) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2001-2017 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/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "env.h"
+
+#ifndef TLS
+static void *tls = NULL;
+#else
+static TLS void *tls = NULL;
+/* this option allows running multiple independent instances of GLPK in
+ * different threads of a multi-threaded application, in which case the
+ * variable tls should be placed in the Thread Local Storage (TLS);
+ * it is assumed that the macro TLS is previously defined to something
+ * like '__thread', '_Thread_local', etc. */
+#endif
+
+/***********************************************************************
+* NAME
+*
+* tls_set_ptr - store global pointer in TLS
+*
+* SYNOPSIS
+*
+* #include "env.h"
+* void tls_set_ptr(void *ptr);
+*
+* DESCRIPTION
+*
+* The routine tls_set_ptr stores a pointer specified by the parameter
+* ptr in the Thread Local Storage (TLS). */
+
+void tls_set_ptr(void *ptr)
+{ tls = ptr;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* tls_get_ptr - retrieve global pointer from TLS
+*
+* SYNOPSIS
+*
+* #include "env.h"
+* void *tls_get_ptr(void);
+*
+* RETURNS
+*
+* The routine tls_get_ptr returns a pointer previously stored by the
+* routine tls_set_ptr. If the latter has not been called yet, NULL is
+* returned. */
+
+void *tls_get_ptr(void)
+{ void *ptr;
+ ptr = tls;
+ return ptr;
+}
+
+/**********************************************************************/
+
+#ifdef __WOE__
+
+/*** Author: Heinrich Schuchardt <xypron.glpk@gmx.de> ***/
+
+#pragma comment(lib, "user32.lib")
+
+#include <windows.h>
+
+#define VISTA 0x06
+
+/* This is the main entry point of the DLL. */
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID
+ lpvReserved)
+{ DWORD version;
+ DWORD major_version;
+#ifdef TLS
+ switch (fdwReason)
+ { case DLL_PROCESS_ATTACH:
+ /* @TODO:
+ * GetVersion is deprecated but the version help functions are
+ * not available in Visual Studio 2010. So lets use it until
+ * we remove the outdated Build files. */
+ version = GetVersion();
+ major_version = version & 0xff;
+ if (major_version < VISTA)
+ { MessageBoxA(NULL,
+ "The GLPK library called by this application is configur"
+ "ed to use thread local storage which is not fully suppo"
+ "rted by your version of Microsoft Windows.\n\n"
+ "Microsoft Windows Vista or a later version of Windows i"
+ "s required to run this application.",
+ "GLPK", MB_OK | MB_ICONERROR);
+ return FALSE;
+ }
+ break;
+ }
+#endif /* TLS */
+ return TRUE;
+}
+
+#endif /* __WOE__ */
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/glpk.h b/test/monniaux/glpk-4.65/src/glpk.h
new file mode 100644
index 00000000..f4e250f9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/glpk.h
@@ -0,0 +1,1175 @@
+/* glpk.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2018 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/>.
+***********************************************************************/
+
+#ifndef GLPK_H
+#define GLPK_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* library version numbers: */
+#define GLP_MAJOR_VERSION 4
+#define GLP_MINOR_VERSION 65
+
+typedef struct glp_prob glp_prob;
+/* LP/MIP problem object */
+
+/* optimization direction flag: */
+#define GLP_MIN 1 /* minimization */
+#define GLP_MAX 2 /* maximization */
+
+/* kind of structural variable: */
+#define GLP_CV 1 /* continuous variable */
+#define GLP_IV 2 /* integer variable */
+#define GLP_BV 3 /* binary variable */
+
+/* type of auxiliary/structural variable: */
+#define GLP_FR 1 /* free (unbounded) variable */
+#define GLP_LO 2 /* variable with lower bound */
+#define GLP_UP 3 /* variable with upper bound */
+#define GLP_DB 4 /* double-bounded variable */
+#define GLP_FX 5 /* fixed variable */
+
+/* status of auxiliary/structural variable: */
+#define GLP_BS 1 /* basic variable */
+#define GLP_NL 2 /* non-basic variable on lower bound */
+#define GLP_NU 3 /* non-basic variable on upper bound */
+#define GLP_NF 4 /* non-basic free (unbounded) variable */
+#define GLP_NS 5 /* non-basic fixed variable */
+
+/* scaling options: */
+#define GLP_SF_GM 0x01 /* perform geometric mean scaling */
+#define GLP_SF_EQ 0x10 /* perform equilibration scaling */
+#define GLP_SF_2N 0x20 /* round scale factors to power of two */
+#define GLP_SF_SKIP 0x40 /* skip if problem is well scaled */
+#define GLP_SF_AUTO 0x80 /* choose scaling options automatically */
+
+/* solution indicator: */
+#define GLP_SOL 1 /* basic solution */
+#define GLP_IPT 2 /* interior-point solution */
+#define GLP_MIP 3 /* mixed integer solution */
+
+/* solution status: */
+#define GLP_UNDEF 1 /* solution is undefined */
+#define GLP_FEAS 2 /* solution is feasible */
+#define GLP_INFEAS 3 /* solution is infeasible */
+#define GLP_NOFEAS 4 /* no feasible solution exists */
+#define GLP_OPT 5 /* solution is optimal */
+#define GLP_UNBND 6 /* solution is unbounded */
+
+typedef struct
+{ /* basis factorization control parameters */
+ int msg_lev; /* (not used) */
+ int type; /* factorization type: */
+#if 1 /* 05/III-2014 */
+#define GLP_BF_LUF 0x00 /* plain LU-factorization */
+#define GLP_BF_BTF 0x10 /* block triangular LU-factorization */
+#endif
+#define GLP_BF_FT 0x01 /* Forrest-Tomlin (LUF only) */
+#define GLP_BF_BG 0x02 /* Schur compl. + Bartels-Golub */
+#define GLP_BF_GR 0x03 /* Schur compl. + Givens rotation */
+ int lu_size; /* (not used) */
+ double piv_tol; /* sgf_piv_tol */
+ int piv_lim; /* sgf_piv_lim */
+ int suhl; /* sgf_suhl */
+ double eps_tol; /* sgf_eps_tol */
+ double max_gro; /* (not used) */
+ int nfs_max; /* fhvint.nfs_max */
+ double upd_tol; /* (not used) */
+ int nrs_max; /* scfint.nn_max */
+ int rs_size; /* (not used) */
+ double foo_bar[38]; /* (reserved) */
+} glp_bfcp;
+
+typedef struct
+{ /* simplex solver control parameters */
+ int msg_lev; /* message level: */
+#define GLP_MSG_OFF 0 /* no output */
+#define GLP_MSG_ERR 1 /* warning and error messages only */
+#define GLP_MSG_ON 2 /* normal output */
+#define GLP_MSG_ALL 3 /* full output */
+#define GLP_MSG_DBG 4 /* debug output */
+ int meth; /* simplex method option: */
+#define GLP_PRIMAL 1 /* use primal simplex */
+#define GLP_DUALP 2 /* use dual; if it fails, use primal */
+#define GLP_DUAL 3 /* use dual simplex */
+ int pricing; /* pricing technique: */
+#define GLP_PT_STD 0x11 /* standard (Dantzig's rule) */
+#define GLP_PT_PSE 0x22 /* projected steepest edge */
+ int r_test; /* ratio test technique: */
+#define GLP_RT_STD 0x11 /* standard (textbook) */
+#define GLP_RT_HAR 0x22 /* Harris' two-pass ratio test */
+#if 1 /* 16/III-2016 */
+#define GLP_RT_FLIP 0x33 /* long-step (flip-flop) ratio test */
+#endif
+ double tol_bnd; /* primal feasibility tolerance */
+ double tol_dj; /* dual feasibility tolerance */
+ double tol_piv; /* pivot tolerance */
+ double obj_ll; /* lower objective limit */
+ double obj_ul; /* upper objective limit */
+ int it_lim; /* simplex iteration limit */
+ int tm_lim; /* time limit, ms */
+ int out_frq; /* display output frequency, ms */
+ int out_dly; /* display output delay, ms */
+ int presolve; /* enable/disable using LP presolver */
+#if 1 /* 11/VII-2017 (not documented yet) */
+ int excl; /* exclude fixed non-basic variables */
+ int shift; /* shift bounds of variables to zero */
+ int aorn; /* option to use A or N: */
+#define GLP_USE_AT 1 /* use A matrix in row-wise format */
+#define GLP_USE_NT 2 /* use N matrix in row-wise format */
+ double foo_bar[33]; /* (reserved) */
+#endif
+} glp_smcp;
+
+typedef struct
+{ /* interior-point solver control parameters */
+ int msg_lev; /* message level (see glp_smcp) */
+ int ord_alg; /* ordering algorithm: */
+#define GLP_ORD_NONE 0 /* natural (original) ordering */
+#define GLP_ORD_QMD 1 /* quotient minimum degree (QMD) */
+#define GLP_ORD_AMD 2 /* approx. minimum degree (AMD) */
+#define GLP_ORD_SYMAMD 3 /* approx. minimum degree (SYMAMD) */
+ double foo_bar[48]; /* (reserved) */
+} glp_iptcp;
+
+typedef struct glp_tree glp_tree;
+/* branch-and-bound tree */
+
+typedef struct
+{ /* integer optimizer control parameters */
+ int msg_lev; /* message level (see glp_smcp) */
+ int br_tech; /* branching technique: */
+#define GLP_BR_FFV 1 /* first fractional variable */
+#define GLP_BR_LFV 2 /* last fractional variable */
+#define GLP_BR_MFV 3 /* most fractional variable */
+#define GLP_BR_DTH 4 /* heuristic by Driebeck and Tomlin */
+#define GLP_BR_PCH 5 /* hybrid pseudocost heuristic */
+ int bt_tech; /* backtracking technique: */
+#define GLP_BT_DFS 1 /* depth first search */
+#define GLP_BT_BFS 2 /* breadth first search */
+#define GLP_BT_BLB 3 /* best local bound */
+#define GLP_BT_BPH 4 /* best projection heuristic */
+ double tol_int; /* mip.tol_int */
+ double tol_obj; /* mip.tol_obj */
+ int tm_lim; /* mip.tm_lim (milliseconds) */
+ int out_frq; /* mip.out_frq (milliseconds) */
+ int out_dly; /* mip.out_dly (milliseconds) */
+ void (*cb_func)(glp_tree *T, void *info);
+ /* mip.cb_func */
+ void *cb_info; /* mip.cb_info */
+ int cb_size; /* mip.cb_size */
+ int pp_tech; /* preprocessing technique: */
+#define GLP_PP_NONE 0 /* disable preprocessing */
+#define GLP_PP_ROOT 1 /* preprocessing only on root level */
+#define GLP_PP_ALL 2 /* preprocessing on all levels */
+ double mip_gap; /* relative MIP gap tolerance */
+ int mir_cuts; /* MIR cuts (GLP_ON/GLP_OFF) */
+ int gmi_cuts; /* Gomory's cuts (GLP_ON/GLP_OFF) */
+ int cov_cuts; /* cover cuts (GLP_ON/GLP_OFF) */
+ int clq_cuts; /* clique cuts (GLP_ON/GLP_OFF) */
+ int presolve; /* enable/disable using MIP presolver */
+ int binarize; /* try to binarize integer variables */
+ int fp_heur; /* feasibility pump heuristic */
+ int ps_heur; /* proximity search heuristic */
+ int ps_tm_lim; /* proxy time limit, milliseconds */
+ int sr_heur; /* simple rounding heuristic */
+#if 1 /* 24/X-2015; not documented--should not be used */
+ int use_sol; /* use existing solution */
+ const char *save_sol; /* filename to save every new solution */
+ int alien; /* use alien solver */
+#endif
+#if 1 /* 16/III-2016; not documented--should not be used */
+ int flip; /* use long-step dual simplex */
+#endif
+ double foo_bar[23]; /* (reserved) */
+} glp_iocp;
+
+typedef struct
+{ /* additional row attributes */
+ int level;
+ /* subproblem level at which the row was added */
+ int origin;
+ /* row origin flag: */
+#define GLP_RF_REG 0 /* regular constraint */
+#define GLP_RF_LAZY 1 /* "lazy" constraint */
+#define GLP_RF_CUT 2 /* cutting plane constraint */
+ int klass;
+ /* row class descriptor: */
+#define GLP_RF_GMI 1 /* Gomory's mixed integer cut */
+#define GLP_RF_MIR 2 /* mixed integer rounding cut */
+#define GLP_RF_COV 3 /* mixed cover cut */
+#define GLP_RF_CLQ 4 /* clique cut */
+ double foo_bar[7];
+ /* (reserved) */
+} glp_attr;
+
+/* enable/disable flag: */
+#define GLP_ON 1 /* enable something */
+#define GLP_OFF 0 /* disable something */
+
+/* reason codes: */
+#define GLP_IROWGEN 0x01 /* request for row generation */
+#define GLP_IBINGO 0x02 /* better integer solution found */
+#define GLP_IHEUR 0x03 /* request for heuristic solution */
+#define GLP_ICUTGEN 0x04 /* request for cut generation */
+#define GLP_IBRANCH 0x05 /* request for branching */
+#define GLP_ISELECT 0x06 /* request for subproblem selection */
+#define GLP_IPREPRO 0x07 /* request for preprocessing */
+
+/* branch selection indicator: */
+#define GLP_NO_BRNCH 0 /* select no branch */
+#define GLP_DN_BRNCH 1 /* select down-branch */
+#define GLP_UP_BRNCH 2 /* select up-branch */
+
+/* return codes: */
+#define GLP_EBADB 0x01 /* invalid basis */
+#define GLP_ESING 0x02 /* singular matrix */
+#define GLP_ECOND 0x03 /* ill-conditioned matrix */
+#define GLP_EBOUND 0x04 /* invalid bounds */
+#define GLP_EFAIL 0x05 /* solver failed */
+#define GLP_EOBJLL 0x06 /* objective lower limit reached */
+#define GLP_EOBJUL 0x07 /* objective upper limit reached */
+#define GLP_EITLIM 0x08 /* iteration limit exceeded */
+#define GLP_ETMLIM 0x09 /* time limit exceeded */
+#define GLP_ENOPFS 0x0A /* no primal feasible solution */
+#define GLP_ENODFS 0x0B /* no dual feasible solution */
+#define GLP_EROOT 0x0C /* root LP optimum not provided */
+#define GLP_ESTOP 0x0D /* search terminated by application */
+#define GLP_EMIPGAP 0x0E /* relative mip gap tolerance reached */
+#define GLP_ENOFEAS 0x0F /* no primal/dual feasible solution */
+#define GLP_ENOCVG 0x10 /* no convergence */
+#define GLP_EINSTAB 0x11 /* numerical instability */
+#define GLP_EDATA 0x12 /* invalid data */
+#define GLP_ERANGE 0x13 /* result out of range */
+
+/* condition indicator: */
+#define GLP_KKT_PE 1 /* primal equalities */
+#define GLP_KKT_PB 2 /* primal bounds */
+#define GLP_KKT_DE 3 /* dual equalities */
+#define GLP_KKT_DB 4 /* dual bounds */
+#define GLP_KKT_CS 5 /* complementary slackness */
+
+/* MPS file format: */
+#define GLP_MPS_DECK 1 /* fixed (ancient) */
+#define GLP_MPS_FILE 2 /* free (modern) */
+
+typedef struct
+{ /* MPS format control parameters */
+ int blank;
+ /* character code to replace blanks in symbolic names */
+ char *obj_name;
+ /* objective row name */
+ double tol_mps;
+ /* zero tolerance for MPS data */
+ double foo_bar[17];
+ /* (reserved for use in the future) */
+} glp_mpscp;
+
+typedef struct
+{ /* CPLEX LP format control parameters */
+ double foo_bar[20];
+ /* (reserved for use in the future) */
+} glp_cpxcp;
+
+#if 1 /* 10/XII-2017 */
+typedef struct glp_prep glp_prep;
+/* LP/MIP preprocessor workspace */
+#endif
+
+typedef struct glp_tran glp_tran;
+/* MathProg translator workspace */
+
+glp_prob *glp_create_prob(void);
+/* create problem object */
+
+void glp_set_prob_name(glp_prob *P, const char *name);
+/* assign (change) problem name */
+
+void glp_set_obj_name(glp_prob *P, const char *name);
+/* assign (change) objective function name */
+
+void glp_set_obj_dir(glp_prob *P, int dir);
+/* set (change) optimization direction flag */
+
+int glp_add_rows(glp_prob *P, int nrs);
+/* add new rows to problem object */
+
+int glp_add_cols(glp_prob *P, int ncs);
+/* add new columns to problem object */
+
+void glp_set_row_name(glp_prob *P, int i, const char *name);
+/* assign (change) row name */
+
+void glp_set_col_name(glp_prob *P, int j, const char *name);
+/* assign (change) column name */
+
+void glp_set_row_bnds(glp_prob *P, int i, int type, double lb,
+ double ub);
+/* set (change) row bounds */
+
+void glp_set_col_bnds(glp_prob *P, int j, int type, double lb,
+ double ub);
+/* set (change) column bounds */
+
+void glp_set_obj_coef(glp_prob *P, int j, double coef);
+/* set (change) obj. coefficient or constant term */
+
+void glp_set_mat_row(glp_prob *P, int i, int len, const int ind[],
+ const double val[]);
+/* set (replace) row of the constraint matrix */
+
+void glp_set_mat_col(glp_prob *P, int j, int len, const int ind[],
+ const double val[]);
+/* set (replace) column of the constraint matrix */
+
+void glp_load_matrix(glp_prob *P, int ne, const int ia[],
+ const int ja[], const double ar[]);
+/* load (replace) the whole constraint matrix */
+
+int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[]);
+/* check for duplicate elements in sparse matrix */
+
+void glp_sort_matrix(glp_prob *P);
+/* sort elements of the constraint matrix */
+
+void glp_del_rows(glp_prob *P, int nrs, const int num[]);
+/* delete specified rows from problem object */
+
+void glp_del_cols(glp_prob *P, int ncs, const int num[]);
+/* delete specified columns from problem object */
+
+void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
+/* copy problem object content */
+
+void glp_erase_prob(glp_prob *P);
+/* erase problem object content */
+
+void glp_delete_prob(glp_prob *P);
+/* delete problem object */
+
+const char *glp_get_prob_name(glp_prob *P);
+/* retrieve problem name */
+
+const char *glp_get_obj_name(glp_prob *P);
+/* retrieve objective function name */
+
+int glp_get_obj_dir(glp_prob *P);
+/* retrieve optimization direction flag */
+
+int glp_get_num_rows(glp_prob *P);
+/* retrieve number of rows */
+
+int glp_get_num_cols(glp_prob *P);
+/* retrieve number of columns */
+
+const char *glp_get_row_name(glp_prob *P, int i);
+/* retrieve row name */
+
+const char *glp_get_col_name(glp_prob *P, int j);
+/* retrieve column name */
+
+int glp_get_row_type(glp_prob *P, int i);
+/* retrieve row type */
+
+double glp_get_row_lb(glp_prob *P, int i);
+/* retrieve row lower bound */
+
+double glp_get_row_ub(glp_prob *P, int i);
+/* retrieve row upper bound */
+
+int glp_get_col_type(glp_prob *P, int j);
+/* retrieve column type */
+
+double glp_get_col_lb(glp_prob *P, int j);
+/* retrieve column lower bound */
+
+double glp_get_col_ub(glp_prob *P, int j);
+/* retrieve column upper bound */
+
+double glp_get_obj_coef(glp_prob *P, int j);
+/* retrieve obj. coefficient or constant term */
+
+int glp_get_num_nz(glp_prob *P);
+/* retrieve number of constraint coefficients */
+
+int glp_get_mat_row(glp_prob *P, int i, int ind[], double val[]);
+/* retrieve row of the constraint matrix */
+
+int glp_get_mat_col(glp_prob *P, int j, int ind[], double val[]);
+/* retrieve column of the constraint matrix */
+
+void glp_create_index(glp_prob *P);
+/* create the name index */
+
+int glp_find_row(glp_prob *P, const char *name);
+/* find row by its name */
+
+int glp_find_col(glp_prob *P, const char *name);
+/* find column by its name */
+
+void glp_delete_index(glp_prob *P);
+/* delete the name index */
+
+void glp_set_rii(glp_prob *P, int i, double rii);
+/* set (change) row scale factor */
+
+void glp_set_sjj(glp_prob *P, int j, double sjj);
+/* set (change) column scale factor */
+
+double glp_get_rii(glp_prob *P, int i);
+/* retrieve row scale factor */
+
+double glp_get_sjj(glp_prob *P, int j);
+/* retrieve column scale factor */
+
+void glp_scale_prob(glp_prob *P, int flags);
+/* scale problem data */
+
+void glp_unscale_prob(glp_prob *P);
+/* unscale problem data */
+
+void glp_set_row_stat(glp_prob *P, int i, int stat);
+/* set (change) row status */
+
+void glp_set_col_stat(glp_prob *P, int j, int stat);
+/* set (change) column status */
+
+void glp_std_basis(glp_prob *P);
+/* construct standard initial LP basis */
+
+void glp_adv_basis(glp_prob *P, int flags);
+/* construct advanced initial LP basis */
+
+void glp_cpx_basis(glp_prob *P);
+/* construct Bixby's initial LP basis */
+
+int glp_simplex(glp_prob *P, const glp_smcp *parm);
+/* solve LP problem with the simplex method */
+
+int glp_exact(glp_prob *P, const glp_smcp *parm);
+/* solve LP problem in exact arithmetic */
+
+void glp_init_smcp(glp_smcp *parm);
+/* initialize simplex method control parameters */
+
+int glp_get_status(glp_prob *P);
+/* retrieve generic status of basic solution */
+
+int glp_get_prim_stat(glp_prob *P);
+/* retrieve status of primal basic solution */
+
+int glp_get_dual_stat(glp_prob *P);
+/* retrieve status of dual basic solution */
+
+double glp_get_obj_val(glp_prob *P);
+/* retrieve objective value (basic solution) */
+
+int glp_get_row_stat(glp_prob *P, int i);
+/* retrieve row status */
+
+double glp_get_row_prim(glp_prob *P, int i);
+/* retrieve row primal value (basic solution) */
+
+double glp_get_row_dual(glp_prob *P, int i);
+/* retrieve row dual value (basic solution) */
+
+int glp_get_col_stat(glp_prob *P, int j);
+/* retrieve column status */
+
+double glp_get_col_prim(glp_prob *P, int j);
+/* retrieve column primal value (basic solution) */
+
+double glp_get_col_dual(glp_prob *P, int j);
+/* retrieve column dual value (basic solution) */
+
+int glp_get_unbnd_ray(glp_prob *P);
+/* determine variable causing unboundedness */
+
+#if 1 /* 08/VIII-2013; not documented yet */
+int glp_get_it_cnt(glp_prob *P);
+/* get simplex solver iteration count */
+#endif
+
+#if 1 /* 08/VIII-2013; not documented yet */
+void glp_set_it_cnt(glp_prob *P, int it_cnt);
+/* set simplex solver iteration count */
+#endif
+
+int glp_interior(glp_prob *P, const glp_iptcp *parm);
+/* solve LP problem with the interior-point method */
+
+void glp_init_iptcp(glp_iptcp *parm);
+/* initialize interior-point solver control parameters */
+
+int glp_ipt_status(glp_prob *P);
+/* retrieve status of interior-point solution */
+
+double glp_ipt_obj_val(glp_prob *P);
+/* retrieve objective value (interior point) */
+
+double glp_ipt_row_prim(glp_prob *P, int i);
+/* retrieve row primal value (interior point) */
+
+double glp_ipt_row_dual(glp_prob *P, int i);
+/* retrieve row dual value (interior point) */
+
+double glp_ipt_col_prim(glp_prob *P, int j);
+/* retrieve column primal value (interior point) */
+
+double glp_ipt_col_dual(glp_prob *P, int j);
+/* retrieve column dual value (interior point) */
+
+void glp_set_col_kind(glp_prob *P, int j, int kind);
+/* set (change) column kind */
+
+int glp_get_col_kind(glp_prob *P, int j);
+/* retrieve column kind */
+
+int glp_get_num_int(glp_prob *P);
+/* retrieve number of integer columns */
+
+int glp_get_num_bin(glp_prob *P);
+/* retrieve number of binary columns */
+
+int glp_intopt(glp_prob *P, const glp_iocp *parm);
+/* solve MIP problem with the branch-and-bound method */
+
+void glp_init_iocp(glp_iocp *parm);
+/* initialize integer optimizer control parameters */
+
+int glp_mip_status(glp_prob *P);
+/* retrieve status of MIP solution */
+
+double glp_mip_obj_val(glp_prob *P);
+/* retrieve objective value (MIP solution) */
+
+double glp_mip_row_val(glp_prob *P, int i);
+/* retrieve row value (MIP solution) */
+
+double glp_mip_col_val(glp_prob *P, int j);
+/* retrieve column value (MIP solution) */
+
+void glp_check_kkt(glp_prob *P, int sol, int cond, double *ae_max,
+ int *ae_ind, double *re_max, int *re_ind);
+/* check feasibility/optimality conditions */
+
+int glp_print_sol(glp_prob *P, const char *fname);
+/* write basic solution in printable format */
+
+int glp_read_sol(glp_prob *P, const char *fname);
+/* read basic solution from text file */
+
+int glp_write_sol(glp_prob *P, const char *fname);
+/* write basic solution to text file */
+
+int glp_print_ranges(glp_prob *P, int len, const int list[],
+ int flags, const char *fname);
+/* print sensitivity analysis report */
+
+int glp_print_ipt(glp_prob *P, const char *fname);
+/* write interior-point solution in printable format */
+
+int glp_read_ipt(glp_prob *P, const char *fname);
+/* read interior-point solution from text file */
+
+int glp_write_ipt(glp_prob *P, const char *fname);
+/* write interior-point solution to text file */
+
+int glp_print_mip(glp_prob *P, const char *fname);
+/* write MIP solution in printable format */
+
+int glp_read_mip(glp_prob *P, const char *fname);
+/* read MIP solution from text file */
+
+int glp_write_mip(glp_prob *P, const char *fname);
+/* write MIP solution to text file */
+
+int glp_bf_exists(glp_prob *P);
+/* check if LP basis factorization exists */
+
+int glp_factorize(glp_prob *P);
+/* compute LP basis factorization */
+
+int glp_bf_updated(glp_prob *P);
+/* check if LP basis factorization has been updated */
+
+void glp_get_bfcp(glp_prob *P, glp_bfcp *parm);
+/* retrieve LP basis factorization control parameters */
+
+void glp_set_bfcp(glp_prob *P, const glp_bfcp *parm);
+/* change LP basis factorization control parameters */
+
+int glp_get_bhead(glp_prob *P, int k);
+/* retrieve LP basis header information */
+
+int glp_get_row_bind(glp_prob *P, int i);
+/* retrieve row index in the basis header */
+
+int glp_get_col_bind(glp_prob *P, int j);
+/* retrieve column index in the basis header */
+
+void glp_ftran(glp_prob *P, double x[]);
+/* perform forward transformation (solve system B*x = b) */
+
+void glp_btran(glp_prob *P, double x[]);
+/* perform backward transformation (solve system B'*x = b) */
+
+int glp_warm_up(glp_prob *P);
+/* "warm up" LP basis */
+
+int glp_eval_tab_row(glp_prob *P, int k, int ind[], double val[]);
+/* compute row of the simplex tableau */
+
+int glp_eval_tab_col(glp_prob *P, int k, int ind[], double val[]);
+/* compute column of the simplex tableau */
+
+int glp_transform_row(glp_prob *P, int len, int ind[], double val[]);
+/* transform explicitly specified row */
+
+int glp_transform_col(glp_prob *P, int len, int ind[], double val[]);
+/* transform explicitly specified column */
+
+int glp_prim_rtest(glp_prob *P, int len, const int ind[],
+ const double val[], int dir, double eps);
+/* perform primal ratio test */
+
+int glp_dual_rtest(glp_prob *P, int len, const int ind[],
+ const double val[], int dir, double eps);
+/* perform dual ratio test */
+
+void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1,
+ double *value2, int *var2);
+/* analyze active bound of non-basic variable */
+
+void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
+ double *value1, double *coef2, int *var2, double *value2);
+/* analyze objective coefficient at basic variable */
+
+#if 1 /* 10/XII-2017 */
+glp_prep *glp_npp_alloc_wksp(void);
+/* allocate the preprocessor workspace */
+
+void glp_npp_load_prob(glp_prep *prep, glp_prob *P, int sol,
+ int names);
+/* load original problem instance */
+
+int glp_npp_preprocess1(glp_prep *prep, int hard);
+/* perform basic LP/MIP preprocessing */
+
+void glp_npp_build_prob(glp_prep *prep, glp_prob *Q);
+/* build resultant problem instance */
+
+void glp_npp_postprocess(glp_prep *prep, glp_prob *Q);
+/* postprocess solution to resultant problem */
+
+void glp_npp_obtain_sol(glp_prep *prep, glp_prob *P);
+/* obtain solution to original problem */
+
+void glp_npp_free_wksp(glp_prep *prep);
+/* free the preprocessor workspace */
+#endif
+
+int glp_ios_reason(glp_tree *T);
+/* determine reason for calling the callback routine */
+
+glp_prob *glp_ios_get_prob(glp_tree *T);
+/* access the problem object */
+
+void glp_ios_tree_size(glp_tree *T, int *a_cnt, int *n_cnt,
+ int *t_cnt);
+/* determine size of the branch-and-bound tree */
+
+int glp_ios_curr_node(glp_tree *T);
+/* determine current active subproblem */
+
+int glp_ios_next_node(glp_tree *T, int p);
+/* determine next active subproblem */
+
+int glp_ios_prev_node(glp_tree *T, int p);
+/* determine previous active subproblem */
+
+int glp_ios_up_node(glp_tree *T, int p);
+/* determine parent subproblem */
+
+int glp_ios_node_level(glp_tree *T, int p);
+/* determine subproblem level */
+
+double glp_ios_node_bound(glp_tree *T, int p);
+/* determine subproblem local bound */
+
+int glp_ios_best_node(glp_tree *T);
+/* find active subproblem with best local bound */
+
+double glp_ios_mip_gap(glp_tree *T);
+/* compute relative MIP gap */
+
+void *glp_ios_node_data(glp_tree *T, int p);
+/* access subproblem application-specific data */
+
+void glp_ios_row_attr(glp_tree *T, int i, glp_attr *attr);
+/* retrieve additional row attributes */
+
+int glp_ios_pool_size(glp_tree *T);
+/* determine current size of the cut pool */
+
+int glp_ios_add_row(glp_tree *T,
+ const char *name, int klass, int flags, int len, const int ind[],
+ const double val[], int type, double rhs);
+/* add row (constraint) to the cut pool */
+
+void glp_ios_del_row(glp_tree *T, int i);
+/* remove row (constraint) from the cut pool */
+
+void glp_ios_clear_pool(glp_tree *T);
+/* remove all rows (constraints) from the cut pool */
+
+int glp_ios_can_branch(glp_tree *T, int j);
+/* check if can branch upon specified variable */
+
+void glp_ios_branch_upon(glp_tree *T, int j, int sel);
+/* choose variable to branch upon */
+
+void glp_ios_select_node(glp_tree *T, int p);
+/* select subproblem to continue the search */
+
+int glp_ios_heur_sol(glp_tree *T, const double x[]);
+/* provide solution found by heuristic */
+
+void glp_ios_terminate(glp_tree *T);
+/* terminate the solution process */
+
+#ifdef GLP_UNDOC
+int glp_gmi_cut(glp_prob *P, int j, int ind[], double val[], double
+ phi[]);
+/* generate Gomory's mixed integer cut (core routine) */
+
+int glp_gmi_gen(glp_prob *P, glp_prob *pool, int max_cuts);
+/* generate Gomory's mixed integer cuts */
+
+typedef struct glp_cov glp_cov;
+/* cover cur generator workspace */
+
+glp_cov *glp_cov_init(glp_prob *P);
+/* create and initialize cover cut generator */
+
+void glp_cov_gen1(glp_prob *P, glp_cov *cov, glp_prob *pool);
+/* generate locally valid simple cover cuts */
+
+void glp_cov_free(glp_cov *cov);
+/* delete cover cut generator workspace */
+
+typedef struct glp_mir glp_mir;
+/* MIR cut generator workspace */
+
+glp_mir *glp_mir_init(glp_prob *P);
+/* create and initialize MIR cut generator */
+
+int glp_mir_gen(glp_prob *P, glp_mir *mir, glp_prob *pool);
+/* generate mixed integer rounding (MIR) cuts */
+
+void glp_mir_free(glp_mir *mir);
+/* delete MIR cut generator workspace */
+
+typedef struct glp_cfg glp_cfg;
+/* conflict graph descriptor */
+
+glp_cfg *glp_cfg_init(glp_prob *P);
+/* create and initialize conflict graph */
+
+void glp_cfg_free(glp_cfg *G);
+/* delete conflict graph descriptor */
+
+int glp_clq_cut(glp_prob *P, glp_cfg *G, int ind[], double val[]);
+/* generate clique cut from conflict graph */
+#endif /* GLP_UNDOC */
+
+void glp_init_mpscp(glp_mpscp *parm);
+/* initialize MPS format control parameters */
+
+int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+ const char *fname);
+/* read problem data in MPS format */
+
+int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+ const char *fname);
+/* write problem data in MPS format */
+
+void glp_init_cpxcp(glp_cpxcp *parm);
+/* initialize CPLEX LP format control parameters */
+
+int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname);
+/* read problem data in CPLEX LP format */
+
+int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname);
+/* write problem data in CPLEX LP format */
+
+int glp_read_prob(glp_prob *P, int flags, const char *fname);
+/* read problem data in GLPK format */
+
+int glp_write_prob(glp_prob *P, int flags, const char *fname);
+/* write problem data in GLPK format */
+
+glp_tran *glp_mpl_alloc_wksp(void);
+/* allocate the MathProg translator workspace */
+
+void glp_mpl_init_rand(glp_tran *tran, int seed);
+/* initialize pseudo-random number generator */
+
+int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip);
+/* read and translate model section */
+
+int glp_mpl_read_data(glp_tran *tran, const char *fname);
+/* read and translate data section */
+
+int glp_mpl_generate(glp_tran *tran, const char *fname);
+/* generate the model */
+
+void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob);
+/* build LP/MIP problem instance from the model */
+
+int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol);
+/* postsolve the model */
+
+void glp_mpl_free_wksp(glp_tran *tran);
+/* free the MathProg translator workspace */
+
+int glp_read_cnfsat(glp_prob *P, const char *fname);
+/* read CNF-SAT problem data in DIMACS format */
+
+int glp_check_cnfsat(glp_prob *P);
+/* check for CNF-SAT problem instance */
+
+int glp_write_cnfsat(glp_prob *P, const char *fname);
+/* write CNF-SAT problem data in DIMACS format */
+
+int glp_minisat1(glp_prob *P);
+/* solve CNF-SAT problem with MiniSat solver */
+
+int glp_intfeas1(glp_prob *P, int use_bound, int obj_bound);
+/* solve integer feasibility problem */
+
+int glp_init_env(void);
+/* initialize GLPK environment */
+
+const char *glp_version(void);
+/* determine library version */
+
+const char *glp_config(const char *option);
+/* determine library configuration */
+
+int glp_free_env(void);
+/* free GLPK environment */
+
+void glp_puts(const char *s);
+/* write string on terminal */
+
+void glp_printf(const char *fmt, ...);
+/* write formatted output on terminal */
+
+void glp_vprintf(const char *fmt, va_list arg);
+/* write formatted output on terminal */
+
+int glp_term_out(int flag);
+/* enable/disable terminal output */
+
+void glp_term_hook(int (*func)(void *info, const char *s), void *info);
+/* install hook to intercept terminal output */
+
+int glp_open_tee(const char *name);
+/* start copying terminal output to text file */
+
+int glp_close_tee(void);
+/* stop copying terminal output to text file */
+
+#ifndef GLP_ERRFUNC_DEFINED
+#define GLP_ERRFUNC_DEFINED
+typedef void (*glp_errfunc)(const char *fmt, ...);
+#endif
+
+#define glp_error glp_error_(__FILE__, __LINE__)
+glp_errfunc glp_error_(const char *file, int line);
+/* display fatal error message and terminate execution */
+
+#if 1 /* 07/XI-2015 */
+int glp_at_error(void);
+/* check for error state */
+#endif
+
+#define glp_assert(expr) \
+ ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1)))
+void glp_assert_(const char *expr, const char *file, int line);
+/* check for logical condition */
+
+void glp_error_hook(void (*func)(void *info), void *info);
+/* install hook to intercept abnormal termination */
+
+#define glp_malloc(size) glp_alloc(1, size)
+/* allocate memory block (obsolete) */
+
+#define glp_calloc(n, size) glp_alloc(n, size)
+/* allocate memory block (obsolete) */
+
+void *glp_alloc(int n, int size);
+/* allocate memory block */
+
+void *glp_realloc(void *ptr, int n, int size);
+/* reallocate memory block */
+
+void glp_free(void *ptr);
+/* free (deallocate) memory block */
+
+void glp_mem_limit(int limit);
+/* set memory usage limit */
+
+void glp_mem_usage(int *count, int *cpeak, size_t *total,
+ size_t *tpeak);
+/* get memory usage information */
+
+double glp_time(void);
+/* determine current universal time */
+
+double glp_difftime(double t1, double t0);
+/* compute difference between two time values */
+
+typedef struct glp_graph glp_graph;
+typedef struct glp_vertex glp_vertex;
+typedef struct glp_arc glp_arc;
+
+struct glp_graph
+{ /* graph descriptor */
+ void *pool; /* DMP *pool; */
+ /* memory pool to store graph components */
+ char *name;
+ /* graph name (1 to 255 chars); NULL means no name is assigned
+ to the graph */
+ int nv_max;
+ /* length of the vertex list (enlarged automatically) */
+ int nv;
+ /* number of vertices in the graph, 0 <= nv <= nv_max */
+ int na;
+ /* number of arcs in the graph, na >= 0 */
+ glp_vertex **v; /* glp_vertex *v[1+nv_max]; */
+ /* v[i], 1 <= i <= nv, is a pointer to i-th vertex */
+ void *index; /* AVL *index; */
+ /* vertex index to find vertices by their names; NULL means the
+ index does not exist */
+ int v_size;
+ /* size of data associated with each vertex (0 to 256 bytes) */
+ int a_size;
+ /* size of data associated with each arc (0 to 256 bytes) */
+};
+
+struct glp_vertex
+{ /* vertex descriptor */
+ int i;
+ /* vertex ordinal number, 1 <= i <= nv */
+ char *name;
+ /* vertex name (1 to 255 chars); NULL means no name is assigned
+ to the vertex */
+ void *entry; /* AVLNODE *entry; */
+ /* pointer to corresponding entry in the vertex index; NULL means
+ that either the index does not exist or the vertex has no name
+ assigned */
+ void *data;
+ /* pointer to data associated with the vertex */
+ void *temp;
+ /* working pointer */
+ glp_arc *in;
+ /* pointer to the (unordered) list of incoming arcs */
+ glp_arc *out;
+ /* pointer to the (unordered) list of outgoing arcs */
+};
+
+struct glp_arc
+{ /* arc descriptor */
+ glp_vertex *tail;
+ /* pointer to the tail endpoint */
+ glp_vertex *head;
+ /* pointer to the head endpoint */
+ void *data;
+ /* pointer to data associated with the arc */
+ void *temp;
+ /* working pointer */
+ glp_arc *t_prev;
+ /* pointer to previous arc having the same tail endpoint */
+ glp_arc *t_next;
+ /* pointer to next arc having the same tail endpoint */
+ glp_arc *h_prev;
+ /* pointer to previous arc having the same head endpoint */
+ glp_arc *h_next;
+ /* pointer to next arc having the same head endpoint */
+};
+
+glp_graph *glp_create_graph(int v_size, int a_size);
+/* create graph */
+
+void glp_set_graph_name(glp_graph *G, const char *name);
+/* assign (change) graph name */
+
+int glp_add_vertices(glp_graph *G, int nadd);
+/* add new vertices to graph */
+
+void glp_set_vertex_name(glp_graph *G, int i, const char *name);
+/* assign (change) vertex name */
+
+glp_arc *glp_add_arc(glp_graph *G, int i, int j);
+/* add new arc to graph */
+
+void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
+/* delete vertices from graph */
+
+void glp_del_arc(glp_graph *G, glp_arc *a);
+/* delete arc from graph */
+
+void glp_erase_graph(glp_graph *G, int v_size, int a_size);
+/* erase graph content */
+
+void glp_delete_graph(glp_graph *G);
+/* delete graph */
+
+void glp_create_v_index(glp_graph *G);
+/* create vertex name index */
+
+int glp_find_vertex(glp_graph *G, const char *name);
+/* find vertex by its name */
+
+void glp_delete_v_index(glp_graph *G);
+/* delete vertex name index */
+
+int glp_read_graph(glp_graph *G, const char *fname);
+/* read graph from plain text file */
+
+int glp_write_graph(glp_graph *G, const char *fname);
+/* write graph to plain text file */
+
+void glp_mincost_lp(glp_prob *P, glp_graph *G, int names, int v_rhs,
+ int a_low, int a_cap, int a_cost);
+/* convert minimum cost flow problem to LP */
+
+int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
+ int a_cost, double *sol, int a_x, int v_pi);
+/* find minimum-cost flow with out-of-kilter algorithm */
+
+int glp_mincost_relax4(glp_graph *G, int v_rhs, int a_low, int a_cap,
+ int a_cost, int crash, double *sol, int a_x, int a_rc);
+/* find minimum-cost flow with Bertsekas-Tseng relaxation method */
+
+void glp_maxflow_lp(glp_prob *P, glp_graph *G, int names, int s,
+ int t, int a_cap);
+/* convert maximum flow problem to LP */
+
+int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
+ double *sol, int a_x, int v_cut);
+/* find maximal flow with Ford-Fulkerson algorithm */
+
+int glp_check_asnprob(glp_graph *G, int v_set);
+/* check correctness of assignment problem data */
+
+/* assignment problem formulation: */
+#define GLP_ASN_MIN 1 /* perfect matching (minimization) */
+#define GLP_ASN_MAX 2 /* perfect matching (maximization) */
+#define GLP_ASN_MMP 3 /* maximum matching */
+
+int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
+ int v_set, int a_cost);
+/* convert assignment problem to LP */
+
+int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
+ double *sol, int a_x);
+/* solve assignment problem with out-of-kilter algorithm */
+
+int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
+/* find bipartite matching of maximum cardinality */
+
+double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
+/* solve critical path problem */
+
+int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+ int a_cost, const char *fname);
+/* read min-cost flow problem data in DIMACS format */
+
+int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+ int a_cost, const char *fname);
+/* write min-cost flow problem data in DIMACS format */
+
+int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
+ const char *fname);
+/* read maximum flow problem data in DIMACS format */
+
+int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
+ const char *fname);
+/* write maximum flow problem data in DIMACS format */
+
+int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
+ *fname);
+/* read assignment problem data in DIMACS format */
+
+int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
+ *fname);
+/* write assignment problem data in DIMACS format */
+
+int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
+/* read graph in DIMACS clique/coloring format */
+
+int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
+/* write graph in DIMACS clique/coloring format */
+
+int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+ const int parm[1+15]);
+/* Klingman's network problem generator */
+
+void glp_netgen_prob(int nprob, int parm[1+15]);
+/* Klingman's standard network problem instance */
+
+int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+ const int parm[1+14]);
+/* grid-like network problem generator */
+
+int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
+ const int parm[1+5]);
+/* Goldfarb's maximum flow problem generator */
+
+int glp_weak_comp(glp_graph *G, int v_num);
+/* find all weakly connected components of graph */
+
+int glp_strong_comp(glp_graph *G, int v_num);
+/* find all strongly connected components of graph */
+
+int glp_top_sort(glp_graph *G, int v_num);
+/* topological sorting of acyclic digraph */
+
+int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set);
+/* find maximum weight clique with exact algorithm */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/cfg.c b/test/monniaux/glpk-4.65/src/intopt/cfg.c
new file mode 100644
index 00000000..ab73b2da
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/cfg.c
@@ -0,0 +1,409 @@
+/* cfg.c (conflict graph) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#include "cfg.h"
+#include "env.h"
+
+/***********************************************************************
+* cfg_create_graph - create conflict graph
+*
+* This routine creates the conflict graph, which initially is empty,
+* and returns a pointer to the graph descriptor.
+*
+* The parameter n specifies the number of *all* variables in MIP, for
+* which the conflict graph will be built.
+*
+* The parameter nv_max specifies maximal number of vertices in the
+* conflict graph. It should be the double number of binary variables
+* in corresponding MIP. */
+
+CFG *cfg_create_graph(int n, int nv_max)
+{ CFG *G;
+ xassert(n >= 0);
+ xassert(0 <= nv_max && nv_max <= n + n);
+ G = talloc(1, CFG);
+ G->n = n;
+ G->pos = talloc(1+n, int);
+ memset(&G->pos[1], 0, n * sizeof(int));
+ G->neg = talloc(1+n, int);
+ memset(&G->neg[1], 0, n * sizeof(int));
+ G->pool = dmp_create_pool();
+ G->nv_max = nv_max;
+ G->nv = 0;
+ G->ref = talloc(1+nv_max, int);
+ G->vptr = talloc(1+nv_max, CFGVLE *);
+ G->cptr = talloc(1+nv_max, CFGCLE *);
+ return G;
+}
+
+/***********************************************************************
+* cfg_add_clique - add clique to conflict graph
+*
+* This routine adds a clique to the conflict graph.
+*
+* The parameter size specifies the clique size, size >= 2. Note that
+* any edge can be considered as a clique of size 2.
+*
+* The array ind specifies vertices constituting the clique in elements
+* ind[k], 1 <= k <= size:
+*
+* ind[k] = +j means a vertex of the conflict graph that corresponds to
+* original binary variable x[j], 1 <= j <= n.
+*
+* ind[k] = -j means a vertex of the conflict graph that corresponds to
+* complement of original binary variable x[j], 1 <= j <= n.
+*
+* Note that if both vertices for x[j] and (1 - x[j]) have appeared in
+* the conflict graph, the routine automatically adds an edge incident
+* to these vertices. */
+
+static void add_edge(CFG *G, int v, int w)
+{ /* add clique of size 2 */
+ DMP *pool = G->pool;
+ int nv = G->nv;
+ CFGVLE **vptr = G->vptr;
+ CFGVLE *vle;
+ xassert(1 <= v && v <= nv);
+ xassert(1 <= w && w <= nv);
+ xassert(v != w);
+ vle = dmp_talloc(pool, CFGVLE);
+ vle->v = w;
+ vle->next = vptr[v];
+ vptr[v] = vle;
+ vle = dmp_talloc(pool, CFGVLE);
+ vle->v = v;
+ vle->next = vptr[w];
+ vptr[w] = vle;
+ return;
+}
+
+void cfg_add_clique(CFG *G, int size, const int ind[])
+{ int n = G->n;
+ int *pos = G->pos;
+ int *neg = G->neg;
+ DMP *pool = G->pool;
+ int nv_max = G->nv_max;
+ int *ref = G->ref;
+ CFGVLE **vptr = G->vptr;
+ CFGCLE **cptr = G->cptr;
+ int j, k, v;
+ xassert(2 <= size && size <= nv_max);
+ /* add new vertices to the conflict graph */
+ for (k = 1; k <= size; k++)
+ { j = ind[k];
+ if (j > 0)
+ { /* vertex corresponds to x[j] */
+ xassert(1 <= j && j <= n);
+ if (pos[j] == 0)
+ { /* no such vertex exists; add it */
+ v = pos[j] = ++(G->nv);
+ xassert(v <= nv_max);
+ ref[v] = j;
+ vptr[v] = NULL;
+ cptr[v] = NULL;
+ if (neg[j] != 0)
+ { /* now both vertices for x[j] and (1 - x[j]) exist */
+ add_edge(G, v, neg[j]);
+ }
+ }
+ }
+ else
+ { /* vertex corresponds to (1 - x[j]) */
+ j = -j;
+ xassert(1 <= j && j <= n);
+ if (neg[j] == 0)
+ { /* no such vertex exists; add it */
+ v = neg[j] = ++(G->nv);
+ xassert(v <= nv_max);
+ ref[v] = j;
+ vptr[v] = NULL;
+ cptr[v] = NULL;
+ if (pos[j] != 0)
+ { /* now both vertices for x[j] and (1 - x[j]) exist */
+ add_edge(G, v, pos[j]);
+ }
+ }
+ }
+ }
+ /* add specified clique to the conflict graph */
+ if (size == 2)
+ add_edge(G,
+ ind[1] > 0 ? pos[+ind[1]] : neg[-ind[1]],
+ ind[2] > 0 ? pos[+ind[2]] : neg[-ind[2]]);
+ else
+ { CFGVLE *vp, *vle;
+ CFGCLE *cle;
+ /* build list of clique vertices */
+ vp = NULL;
+ for (k = 1; k <= size; k++)
+ { vle = dmp_talloc(pool, CFGVLE);
+ vle->v = ind[k] > 0 ? pos[+ind[k]] : neg[-ind[k]];
+ vle->next = vp;
+ vp = vle;
+ }
+ /* attach the clique to all its vertices */
+ for (k = 1; k <= size; k++)
+ { cle = dmp_talloc(pool, CFGCLE);
+ cle->vptr = vp;
+ v = ind[k] > 0 ? pos[+ind[k]] : neg[-ind[k]];
+ cle->next = cptr[v];
+ cptr[v] = cle;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* cfg_get_adjacent - get vertices adjacent to specified vertex
+*
+* This routine stores numbers of all vertices adjacent to specified
+* vertex v of the conflict graph in locations ind[1], ..., ind[len],
+* and returns len, 1 <= len <= nv-1, where nv is the total number of
+* vertices in the conflict graph.
+*
+* Note that the conflict graph defined by this routine has neither
+* self-loops nor multiple edges. */
+
+int cfg_get_adjacent(CFG *G, int v, int ind[])
+{ int nv = G->nv;
+ int *ref = G->ref;
+ CFGVLE **vptr = G->vptr;
+ CFGCLE **cptr = G->cptr;
+ CFGVLE *vle;
+ CFGCLE *cle;
+ int k, w, len;
+ xassert(1 <= v && v <= nv);
+ len = 0;
+ /* walk thru the list of adjacent vertices */
+ for (vle = vptr[v]; vle != NULL; vle = vle->next)
+ { w = vle->v;
+ xassert(1 <= w && w <= nv);
+ xassert(w != v);
+ if (ref[w] > 0)
+ { ind[++len] = w;
+ ref[w] = -ref[w];
+ }
+ }
+ /* walk thru the list of incident cliques */
+ for (cle = cptr[v]; cle != NULL; cle = cle->next)
+ { /* walk thru the list of clique vertices */
+ for (vle = cle->vptr; vle != NULL; vle = vle->next)
+ { w = vle->v;
+ xassert(1 <= w && w <= nv);
+ if (w != v && ref[w] > 0)
+ { ind[++len] = w;
+ ref[w] = -ref[w];
+ }
+ }
+ }
+ xassert(1 <= len && len < nv);
+ /* unmark vertices included in the resultant adjacency list */
+ for (k = 1; k <= len; k++)
+ { w = ind[k];
+ ref[w] = -ref[w];
+ }
+ return len;
+}
+
+/***********************************************************************
+* cfg_expand_clique - expand specified clique to maximal clique
+*
+* Given some clique in the conflict graph this routine expands it to
+* a maximal clique by including in it new vertices.
+*
+* On entry vertex indices constituting the initial clique should be
+* stored in locations c_ind[1], ..., c_ind[c_len], where c_len is the
+* initial clique size. On exit the routine stores new vertex indices
+* to locations c_ind[c_len+1], ..., c_ind[c_len'], where c_len' is the
+* size of the maximal clique found, and returns c_len'.
+*
+* ALGORITHM
+*
+* Let G = (V, E) be a graph, C within V be a current clique to be
+* expanded, and D within V \ C be a subset of vertices adjacent to all
+* vertices from C. On every iteration the routine chooses some vertex
+* v in D, includes it into C, and removes from D the vertex v as well
+* as all vertices not adjacent to v. Initially C is empty and D = V.
+* Iterations repeat until D becomes an empty set. Obviously, the final
+* set C is a maximal clique in G.
+*
+* Now let C0 be an initial clique, and we want C0 to be a subset of
+* the final maximal clique C. To provide this condition the routine
+* starts constructing C by choosing only such vertices v in D, which
+* are in C0, until all vertices from C0 have been included in C. May
+* note that if on some iteration C0 \ C is non-empty (i.e. if not all
+* vertices from C0 have been included in C), C0 \ C is a subset of D,
+* because C0 is a clique. */
+
+static int intersection(int d_len, int d_ind[], int d_pos[], int len,
+ const int ind[])
+{ /* compute intersection D := D inter W, where W is some specified
+ * set of vertices */
+ int k, t, v, new_len;
+ /* walk thru vertices in W and mark vertices in D */
+ for (t = 1; t <= len; t++)
+ { /* v in W */
+ v = ind[t];
+ /* determine position of v in D */
+ k = d_pos[v];
+ if (k != 0)
+ { /* v in D */
+ xassert(d_ind[k] == v);
+ /* mark v to keep it in D */
+ d_ind[k] = -v;
+ }
+ }
+ /* remove all unmarked vertices from D */
+ new_len = 0;
+ for (k = 1; k <= d_len; k++)
+ { /* v in D */
+ v = d_ind[k];
+ if (v < 0)
+ { /* v is marked; keep it */
+ v = -v;
+ new_len++;
+ d_ind[new_len] = v;
+ d_pos[v] = new_len;
+ }
+ else
+ { /* v is not marked; remove it */
+ d_pos[v] = 0;
+ }
+ }
+ return new_len;
+}
+
+int cfg_expand_clique(CFG *G, int c_len, int c_ind[])
+{ int nv = G->nv;
+ int d_len, *d_ind, *d_pos, len, *ind;
+ int k, v;
+ xassert(0 <= c_len && c_len <= nv);
+ /* allocate working arrays */
+ d_ind = talloc(1+nv, int);
+ d_pos = talloc(1+nv, int);
+ ind = talloc(1+nv, int);
+ /* initialize C := 0, D := V */
+ d_len = nv;
+ for (k = 1; k <= nv; k++)
+ d_ind[k] = d_pos[k] = k;
+ /* expand C by vertices of specified initial clique C0 */
+ for (k = 1; k <= c_len; k++)
+ { /* v in C0 */
+ v = c_ind[k];
+ xassert(1 <= v && v <= nv);
+ /* since C0 is clique, v should be in D */
+ xassert(d_pos[v] != 0);
+ /* W := set of vertices adjacent to v */
+ len = cfg_get_adjacent(G, v, ind);
+ /* D := D inter W */
+ d_len = intersection(d_len, d_ind, d_pos, len, ind);
+ /* since v not in W, now v should be not in D */
+ xassert(d_pos[v] == 0);
+ }
+ /* expand C by some other vertices until D is empty */
+ while (d_len > 0)
+ { /* v in D */
+ v = d_ind[1];
+ xassert(1 <= v && v <= nv);
+ /* note that v is adjacent to all vertices in C (by design),
+ * so add v to C */
+ c_ind[++c_len] = v;
+ /* W := set of vertices adjacent to v */
+ len = cfg_get_adjacent(G, v, ind);
+ /* D := D inter W */
+ d_len = intersection(d_len, d_ind, d_pos, len, ind);
+ /* since v not in W, now v should be not in D */
+ xassert(d_pos[v] == 0);
+ }
+ /* free working arrays */
+ tfree(d_ind);
+ tfree(d_pos);
+ tfree(ind);
+ /* bring maximal clique to calling routine */
+ return c_len;
+}
+
+/***********************************************************************
+* cfg_check_clique - check clique in conflict graph
+*
+* This routine checks that vertices of the conflict graph specified
+* in locations c_ind[1], ..., c_ind[c_len] constitute a clique.
+*
+* NOTE: for testing/debugging only. */
+
+void cfg_check_clique(CFG *G, int c_len, const int c_ind[])
+{ int nv = G->nv;
+ int k, kk, v, w, len, *ind;
+ char *flag;
+ ind = talloc(1+nv, int);
+ flag = talloc(1+nv, char);
+ memset(&flag[1], 0, nv);
+ /* walk thru clique vertices */
+ xassert(c_len >= 0);
+ for (k = 1; k <= c_len; k++)
+ { /* get clique vertex v */
+ v = c_ind[k];
+ xassert(1 <= v && v <= nv);
+ /* get vertices adjacent to vertex v */
+ len = cfg_get_adjacent(G, v, ind);
+ for (kk = 1; kk <= len; kk++)
+ { w = ind[kk];
+ xassert(1 <= w && w <= nv);
+ xassert(w != v);
+ flag[w] = 1;
+ }
+ /* check that all clique vertices other than v are adjacent
+ to v */
+ for (kk = 1; kk <= c_len; kk++)
+ { w = c_ind[kk];
+ xassert(1 <= w && w <= nv);
+ if (w != v)
+ xassert(flag[w]);
+ }
+ /* reset vertex flags */
+ for (kk = 1; kk <= len; kk++)
+ flag[ind[kk]] = 0;
+ }
+ tfree(ind);
+ tfree(flag);
+ return;
+}
+
+/***********************************************************************
+* cfg_delete_graph - delete conflict graph
+*
+* This routine deletes the conflict graph by freeing all the memory
+* allocated to this program object. */
+
+void cfg_delete_graph(CFG *G)
+{ tfree(G->pos);
+ tfree(G->neg);
+ dmp_delete_pool(G->pool);
+ tfree(G->ref);
+ tfree(G->vptr);
+ tfree(G->cptr);
+ tfree(G);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/cfg.h b/test/monniaux/glpk-4.65/src/intopt/cfg.h
new file mode 100644
index 00000000..d478f6c0
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/cfg.h
@@ -0,0 +1,138 @@
+/* cfg.h (conflict graph) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#ifndef CFG_H
+#define CFG_H
+
+#include "dmp.h"
+
+/***********************************************************************
+* The structure CFG describes the conflict graph.
+*
+* Conflict graph is an undirected graph G = (V, E), where V is a set
+* of vertices, E <= V x V is a set of edges. Each vertex v in V of the
+* conflict graph corresponds to a binary variable z[v], which is
+* either an original binary variable x[j] or its complement 1 - x[j].
+* Edge (v,w) in E means that z[v] and z[w] cannot take the value 1 at
+* the same time, i.e. it defines an inequality z[v] + z[w] <= 1, which
+* is assumed to be valid for original MIP.
+*
+* Since the conflict graph may be dense, it is stored as an union of
+* its cliques rather than explicitly. */
+
+#if 0 /* 08/III-2016 */
+typedef struct CFG CFG;
+#else
+typedef struct glp_cfg CFG;
+#endif
+typedef struct CFGVLE CFGVLE;
+typedef struct CFGCLE CFGCLE;
+
+#if 0 /* 08/III-2016 */
+struct CFG
+#else
+struct glp_cfg
+#endif
+{ /* conflict graph descriptor */
+ int n;
+ /* number of *all* variables (columns) in corresponding MIP */
+ int *pos; /* int pos[1+n]; */
+ /* pos[0] is not used;
+ * pos[j] = v, 1 <= j <= n, means that vertex v corresponds to
+ * original binary variable x[j], and pos[j] = 0 means that the
+ * conflict graph has no such vertex */
+ int *neg; /* int neg[1+n]; */
+ /* neg[0] is not used;
+ * neg[j] = v, 1 <= j <= n, means that vertex v corresponds to
+ * complement of original binary variable x[j], and neg[j] = 0
+ * means that the conflict graph has no such vertex */
+ DMP *pool;
+ /* memory pool to allocate elements of the conflict graph */
+ int nv_max;
+ /* maximal number of vertices in the conflict graph */
+ int nv;
+ /* current number of vertices in the conflict graph */
+ int *ref; /* int ref[1+nv_max]; */
+ /* ref[v] = j, 1 <= v <= nv, means that vertex v corresponds
+ * either to original binary variable x[j] or to its complement,
+ * i.e. either pos[j] = v or neg[j] = v */
+ CFGVLE **vptr; /* CFGVLE *vptr[1+nv_max]; */
+ /* vptr[v], 1 <= v <= nv, is an initial pointer to the list of
+ * vertices adjacent to vertex v */
+ CFGCLE **cptr; /* CFGCLE *cptr[1+nv_max]; */
+ /* cptr[v], 1 <= v <= nv, is an initial pointer to the list of
+ * cliques that contain vertex v */
+};
+
+struct CFGVLE
+{ /* vertex list element */
+ int v;
+ /* vertex number, 1 <= v <= nv */
+ CFGVLE *next;
+ /* pointer to next vertex list element */
+};
+
+struct CFGCLE
+{ /* clique list element */
+ CFGVLE *vptr;
+ /* initial pointer to the list of clique vertices */
+ CFGCLE *next;
+ /* pointer to next clique list element */
+};
+
+#define cfg_create_graph _glp_cfg_create_graph
+CFG *cfg_create_graph(int n, int nv_max);
+/* create conflict graph */
+
+#define cfg_add_clique _glp_cfg_add_clique
+void cfg_add_clique(CFG *G, int size, const int ind[]);
+/* add clique to conflict graph */
+
+#define cfg_get_adjacent _glp_cfg_get_adjacent
+int cfg_get_adjacent(CFG *G, int v, int ind[]);
+/* get vertices adjacent to specified vertex */
+
+#define cfg_expand_clique _glp_cfg_expand_clique
+int cfg_expand_clique(CFG *G, int c_len, int c_ind[]);
+/* expand specified clique to maximal clique */
+
+#define cfg_check_clique _glp_cfg_check_clique
+void cfg_check_clique(CFG *G, int c_len, const int c_ind[]);
+/* check clique in conflict graph */
+
+#define cfg_delete_graph _glp_cfg_delete_graph
+void cfg_delete_graph(CFG *G);
+/* delete conflict graph */
+
+#define cfg_build_graph _glp_cfg_build_graph
+CFG *cfg_build_graph(void /* glp_prob */ *P);
+/* build conflict graph */
+
+#define cfg_find_clique _glp_cfg_find_clique
+int cfg_find_clique(void /* glp_prob */ *P, CFG *G, int ind[],
+ double *sum);
+/* find maximum weight clique in conflict graph */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/cfg1.c b/test/monniaux/glpk-4.65/src/intopt/cfg1.c
new file mode 100644
index 00000000..80a2e834
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/cfg1.c
@@ -0,0 +1,703 @@
+/* cfg1.c (conflict graph) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2018 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/>.
+***********************************************************************/
+
+#include "cfg.h"
+#include "env.h"
+#include "prob.h"
+#include "wclique.h"
+#include "wclique1.h"
+
+/***********************************************************************
+* cfg_build_graph - build conflict graph
+*
+* This routine builds the conflict graph. It analyzes the specified
+* problem object to discover original and implied packing inequalities
+* and adds corresponding cliques to the conflict graph.
+*
+* Packing inequality has the form:
+*
+* sum z[j] <= 1, (1)
+* j in J
+*
+* where z[j] = x[j] or z[j] = 1 - x[j], x[j] is an original binary
+* variable. Every packing inequality (1) is equivalent to a set of
+* edge inequalities:
+*
+* z[i] + z[j] <= 1 for all i, j in J, i != j, (2)
+*
+* and since every edge inequality (2) defines an edge in the conflict
+* graph, corresponding packing inequality (1) defines a clique.
+*
+* To discover packing inequalities the routine analyzes constraints
+* of the specified MIP. To simplify the analysis each constraint is
+* analyzed separately. The analysis is performed as follows.
+*
+* Let some original constraint be the following:
+*
+* L <= sum a[j] x[j] <= U. (3)
+*
+* To analyze it the routine analyzes two constraints of "not greater
+* than" type:
+*
+* sum (-a[j]) x[j] <= -L, (4)
+*
+* sum (+a[j]) x[j] <= +U, (5)
+*
+* which are relaxations of the original constraint (3). (If, however,
+* L = -oo, or U = +oo, corresponding constraint being redundant is not
+* analyzed.)
+*
+* Let a constraint of "not greater than" type be the following:
+*
+* sum a[j] x[j] + sum a[j] x[j] <= b, (6)
+* j in J j in J'
+*
+* where J is a subset of binary variables, J' is a subset of other
+* (continues and non-binary integer) variables. The constraint (6) is
+* is relaxed as follows, to eliminate non-binary variables:
+*
+* sum a[j] x[j] <= b - sum a[j] x[j] <= b', (7)
+* j in J j in J'
+*
+* b' = sup(b - sum a[j] x[j]) =
+* j in J'
+*
+* = b - inf(sum a[j] x[j]) =
+*
+* = b - sum inf(a[j] x[j]) = (8)
+*
+* = b - sum a[j] inf(x[j]) - sum a[j] sup(x[j]) =
+* a[j]>0 a[j]<0
+*
+* = b - sum a[j] l[j] - sum a[j] u[j],
+* a[j]>0 a[j]<0
+*
+* where l[j] and u[j] are, resp., lower and upper bounds of x[j].
+*
+* Then the routine transforms the relaxed constraint containing only
+* binary variables:
+*
+* sum a[j] x[j] <= b (9)
+*
+* to an equivalent 0-1 knapsack constraint as follows:
+*
+* sum a[j] x[j] + sum a[j] x[j] <= b ==>
+* a[j]>0 a[j]<0
+*
+* sum a[j] x[j] + sum a[j] (1 - x[j]) <= b ==>
+* a[j]>0 a[j]<0 (10)
+*
+* sum (+a[j]) x[j] + sum (-a[j]) x[j] <= b + sum (-a[j]) ==>
+* a[j]>0 a[j]<0 a[j]<0
+*
+* sum a'[j] z[j] <= b',
+*
+* where a'[j] = |a[j]| > 0, and
+*
+* ( x[j] if a[j] > 0
+* z[j] = <
+* ( 1 - x[j] if a[j] < 0
+*
+* is a binary variable, which is either original binary variable x[j]
+* or its complement.
+*
+* Finally, the routine analyzes the resultant 0-1 knapsack inequality:
+*
+* sum a[j] z[j] <= b, (11)
+* j in J
+*
+* where all a[j] are positive, to discover clique inequalities (1),
+* which are valid for (11) and therefore valid for (3). (It is assumed
+* that the original MIP has been preprocessed, so it is not checked,
+* for example, that b > 0 or that a[j] <= b.)
+*
+* In principle, to discover any edge inequalities valid for (11) it
+* is sufficient to check whether a[i] + a[j] > b for all i, j in J,
+* i < j. However, this way requires O(|J|^2) checks, so the routine
+* analyses (11) in the following way, which is much more efficient in
+* many practical cases.
+*
+* 1. Let a[p] and a[q] be two minimal coefficients:
+*
+* a[p] = min a[j], (12)
+*
+* a[q] = min a[j], j != p, (13)
+*
+* such that
+*
+* a[p] + a[q] > b. (14)
+*
+* This means that a[i] + a[j] > b for any i, j in J, i != j, so
+*
+* z[i] + z[j] <= 1 (15)
+*
+* are valid for (11) for any i, j in J, i != j. This case means that
+* J define a clique in the conflict graph.
+*
+* 2. Otherwise, let a[p] and [q] be two maximal coefficients:
+*
+* a[p] = max a[j], (16)
+*
+* a[q] = max a[j], j != p, (17)
+*
+* such that
+*
+* a[p] + a[q] <= b. (18)
+*
+* This means that a[i] + a[j] <= b for any i, j in J, i != j, so in
+* this case no valid edge inequalities for (11) exist.
+*
+* 3. Otherwise, let all a[j] be ordered by descending their values:
+*
+* a[1] >= a[2] >= ... >= a[p-1] >= a[p] >= a[p+1] >= ... (19)
+*
+* where p is such that
+*
+* a[p-1] + a[p] > b, (20)
+*
+* a[p] + a[p+1] <= b. (21)
+*
+* (May note that due to the former two cases in this case we always
+* have 2 <= p <= |J|-1.)
+*
+* Since a[p] and a[p-1] are two minimal coefficients in the set
+* J' = {1, ..., p}, J' define a clique in the conflict graph for the
+* same reason as in the first case. Similarly, since a[p] and a[p+1]
+* are two maximal coefficients in the set J" = {p, ..., |J|}, no edge
+* inequalities exist for all i, j in J" for the same reason as in the
+* second case. Thus, to discover other edge inequalities (15) valid
+* for (11), the routine checks if a[i] + a[j] > b for all i in J',
+* j in J", i != j. */
+
+#define is_binary(j) \
+ (P->col[j]->kind == GLP_IV && P->col[j]->type == GLP_DB && \
+ P->col[j]->lb == 0.0 && P->col[j]->ub == 1.0)
+/* check if x[j] is binary variable */
+
+struct term { int ind; double val; };
+/* term a[j] * z[j] used to sort a[j]'s */
+
+static int CDECL fcmp(const void *e1, const void *e2)
+{ /* auxiliary routine called from qsort */
+ const struct term *t1 = e1, *t2 = e2;
+ if (t1->val > t2->val)
+ return -1;
+ else if (t1->val < t2->val)
+ return +1;
+ else
+ return 0;
+}
+
+static void analyze_ineq(glp_prob *P, CFG *G, int len, int ind[],
+ double val[], double rhs, struct term t[])
+{ /* analyze inequality constraint (6) */
+ /* P is the original MIP
+ * G is the conflict graph to be built
+ * len is the number of terms in the constraint
+ * ind[1], ..., ind[len] are indices of variables x[j]
+ * val[1], ..., val[len] are constraint coefficients a[j]
+ * rhs is the right-hand side b
+ * t[1+len] is a working array */
+ int j, k, kk, p, q, type, new_len;
+ /* eliminate non-binary variables; see (7) and (8) */
+ new_len = 0;
+ for (k = 1; k <= len; k++)
+ { /* get index of variable x[j] */
+ j = ind[k];
+ if (is_binary(j))
+ { /* x[j] remains in relaxed constraint */
+ new_len++;
+ ind[new_len] = j;
+ val[new_len] = val[k];
+ }
+ else if (val[k] > 0.0)
+ { /* eliminate non-binary x[j] in case a[j] > 0 */
+ /* b := b - a[j] * l[j]; see (8) */
+ type = P->col[j]->type;
+ if (type == GLP_FR || type == GLP_UP)
+ { /* x[j] has no lower bound */
+ goto done;
+ }
+ rhs -= val[k] * P->col[j]->lb;
+ }
+ else /* val[j] < 0.0 */
+ { /* eliminate non-binary x[j] in case a[j] < 0 */
+ /* b := b - a[j] * u[j]; see (8) */
+ type = P->col[j]->type;
+ if (type == GLP_FR || type == GLP_LO)
+ { /* x[j] has no upper bound */
+ goto done;
+ }
+ rhs -= val[k] * P->col[j]->ub;
+ }
+ }
+ len = new_len;
+ /* now we have the constraint (9) */
+ if (len <= 1)
+ { /* at least two terms are needed */
+ goto done;
+ }
+ /* make all constraint coefficients positive; see (10) */
+ for (k = 1; k <= len; k++)
+ { if (val[k] < 0.0)
+ { /* a[j] < 0; substitute x[j] = 1 - x'[j], where x'[j] is
+ * a complement binary variable */
+ ind[k] = -ind[k];
+ val[k] = -val[k];
+ rhs += val[k];
+ }
+ }
+ /* now we have 0-1 knapsack inequality (11) */
+ /* increase the right-hand side a bit to avoid false checks due
+ * to rounding errors */
+ rhs += 0.001 * (1.0 + fabs(rhs));
+ /*** first case ***/
+ /* find two minimal coefficients a[p] and a[q] */
+ p = 0;
+ for (k = 1; k <= len; k++)
+ { if (p == 0 || val[p] > val[k])
+ p = k;
+ }
+ q = 0;
+ for (k = 1; k <= len; k++)
+ { if (k != p && (q == 0 || val[q] > val[k]))
+ q = k;
+ }
+ xassert(p != 0 && q != 0 && p != q);
+ /* check condition (14) */
+ if (val[p] + val[q] > rhs)
+ { /* all z[j] define a clique in the conflict graph */
+ cfg_add_clique(G, len, ind);
+ goto done;
+ }
+ /*** second case ***/
+ /* find two maximal coefficients a[p] and a[q] */
+ p = 0;
+ for (k = 1; k <= len; k++)
+ { if (p == 0 || val[p] < val[k])
+ p = k;
+ }
+ q = 0;
+ for (k = 1; k <= len; k++)
+ { if (k != p && (q == 0 || val[q] < val[k]))
+ q = k;
+ }
+ xassert(p != 0 && q != 0 && p != q);
+ /* check condition (18) */
+ if (val[p] + val[q] <= rhs)
+ { /* no valid edge inequalities exist */
+ goto done;
+ }
+ /*** third case ***/
+ xassert(len >= 3);
+ /* sort terms in descending order of coefficient values */
+ for (k = 1; k <= len; k++)
+ { t[k].ind = ind[k];
+ t[k].val = val[k];
+ }
+ qsort(&t[1], len, sizeof(struct term), fcmp);
+ for (k = 1; k <= len; k++)
+ { ind[k] = t[k].ind;
+ val[k] = t[k].val;
+ }
+ /* now a[1] >= a[2] >= ... >= a[len-1] >= a[len] */
+ /* note that a[1] + a[2] > b and a[len-1] + a[len] <= b due two
+ * the former two cases */
+ xassert(val[1] + val[2] > rhs);
+ xassert(val[len-1] + val[len] <= rhs);
+ /* find p according to conditions (20) and (21) */
+ for (p = 2; p < len; p++)
+ { if (val[p] + val[p+1] <= rhs)
+ break;
+ }
+ xassert(p < len);
+ /* z[1], ..., z[p] define a clique in the conflict graph */
+ cfg_add_clique(G, p, ind);
+ /* discover other edge inequalities */
+ for (k = 1; k <= p; k++)
+ { for (kk = p; kk <= len; kk++)
+ { if (k != kk && val[k] + val[kk] > rhs)
+ { int iii[1+2];
+ iii[1] = ind[k];
+ iii[2] = ind[kk];
+ cfg_add_clique(G, 2, iii);
+ }
+ }
+ }
+done: return;
+}
+
+CFG *cfg_build_graph(void *P_)
+{ glp_prob *P = P_;
+ int m = P->m;
+ int n = P->n;
+ CFG *G;
+ int i, k, type, len, *ind;
+ double *val;
+ struct term *t;
+ /* create the conflict graph (number of its vertices cannot be
+ * greater than double number of binary variables) */
+ G = cfg_create_graph(n, 2 * glp_get_num_bin(P));
+ /* allocate working arrays */
+ ind = talloc(1+n, int);
+ val = talloc(1+n, double);
+ t = talloc(1+n, struct term);
+ /* analyze constraints to discover edge inequalities */
+ for (i = 1; i <= m; i++)
+ { type = P->row[i]->type;
+ if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+ { /* i-th row has lower bound */
+ /* analyze inequality sum (-a[j]) * x[j] <= -lb */
+ len = glp_get_mat_row(P, i, ind, val);
+ for (k = 1; k <= len; k++)
+ val[k] = -val[k];
+ analyze_ineq(P, G, len, ind, val, -P->row[i]->lb, t);
+ }
+ if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+ { /* i-th row has upper bound */
+ /* analyze inequality sum (+a[j]) * x[j] <= +ub */
+ len = glp_get_mat_row(P, i, ind, val);
+ analyze_ineq(P, G, len, ind, val, +P->row[i]->ub, t);
+ }
+ }
+ /* free working arrays */
+ tfree(ind);
+ tfree(val);
+ tfree(t);
+ return G;
+}
+
+/***********************************************************************
+* cfg_find_clique - find maximum weight clique in conflict graph
+*
+* This routine finds a maximum weight clique in the conflict graph
+* G = (V, E), where the weight of vertex v in V is the value of
+* corresponding binary variable z (which is either an original binary
+* variable or its complement) in the optimal solution to LP relaxation
+* provided in the problem object. The goal is to find a clique in G,
+* whose weight is greater than 1, in which case corresponding packing
+* inequality is violated at the optimal point.
+*
+* On exit the routine stores vertex indices of the conflict graph
+* included in the clique found to locations ind[1], ..., ind[len], and
+* returns len, which is the clique size. The clique weight is stored
+* in location pointed to by the parameter sum. If no clique has been
+* found, the routine returns 0.
+*
+* Since the conflict graph may have a big number of vertices and be
+* quite dense, the routine uses an induced subgraph G' = (V', E'),
+* which is constructed as follows:
+*
+* 1. If the weight of some vertex v in V is zero (close to zero), it
+* is not included in V'. Obviously, including in a clique
+* zero-weight vertices does not change its weight, so if in G there
+* exist a clique of a non-zero weight, in G' exists a clique of the
+* same weight. This point is extremely important, because dropping
+* out zero-weight vertices can be done without retrieving lists of
+* adjacent vertices whose size may be very large.
+*
+* 2. Cumulative weight of vertex v in V is the sum of the weight of v
+* and weights of all vertices in V adjacent to v. Obviously, if
+* a clique includes a vertex v, the clique weight cannot be greater
+* than the cumulative weight of v. Since we are interested only in
+* cliques whose weight is greater than 1, vertices of V, whose
+* cumulative weight is not greater than 1, are not included in V'.
+*
+* May note that in many practical cases the size of the induced
+* subgraph G' is much less than the size of the original conflict
+* graph G due to many binary variables, whose optimal values are zero
+* or close to zero. For example, it may happen that |V| = 100,000 and
+* |E| = 1e9 while |V'| = 50 and |E'| = 1000. */
+
+struct csa
+{ /* common storage area */
+ glp_prob *P;
+ /* original MIP */
+ CFG *G;
+ /* original conflict graph G = (V, E), |V| = nv */
+ int *ind; /* int ind[1+nv]; */
+ /* working array */
+ /*--------------------------------------------------------------*/
+ /* induced subgraph G' = (V', E') of original conflict graph */
+ int nn;
+ /* number of vertices in V' */
+ int *vtoi; /* int vtoi[1+nv]; */
+ /* vtoi[v] = i, 1 <= v <= nv, means that vertex v in V is vertex
+ * i in V'; vtoi[v] = 0 means that vertex v is not included in
+ * the subgraph */
+ int *itov; /* int itov[1+nv]; */
+ /* itov[i] = v, 1 <= i <= nn, means that vertex i in V' is vertex
+ * v in V */
+ double *wgt; /* double wgt[1+nv]; */
+ /* wgt[i], 1 <= i <= nn, is a weight of vertex i in V', which is
+ * the value of corresponding binary variable in optimal solution
+ * to LP relaxation */
+};
+
+static void build_subgraph(struct csa *csa)
+{ /* build induced subgraph */
+ glp_prob *P = csa->P;
+ int n = P->n;
+ CFG *G = csa->G;
+ int *ind = csa->ind;
+ int *pos = G->pos;
+ int *neg = G->neg;
+ int nv = G->nv;
+ int *ref = G->ref;
+ int *vtoi = csa->vtoi;
+ int *itov = csa->itov;
+ double *wgt = csa->wgt;
+ int j, k, v, w, nn, len;
+ double z, sum;
+ /* initially induced subgraph is empty */
+ nn = 0;
+ /* walk thru vertices of original conflict graph */
+ for (v = 1; v <= nv; v++)
+ { /* determine value of binary variable z[j] that corresponds to
+ * vertex v */
+ j = ref[v];
+ xassert(1 <= j && j <= n);
+ if (pos[j] == v)
+ { /* z[j] = x[j], where x[j] is original variable */
+ z = P->col[j]->prim;
+ }
+ else if (neg[j] == v)
+ { /* z[j] = 1 - x[j], where x[j] is original variable */
+ z = 1.0 - P->col[j]->prim;
+ }
+ else
+ xassert(v != v);
+ /* if z[j] is close to zero, do not include v in the induced
+ * subgraph */
+ if (z < 0.001)
+ { vtoi[v] = 0;
+ continue;
+ }
+ /* calculate cumulative weight of vertex v */
+ sum = z;
+ /* walk thru all vertices adjacent to v */
+ len = cfg_get_adjacent(G, v, ind);
+ for (k = 1; k <= len; k++)
+ { /* there is an edge (v,w) in the conflict graph */
+ w = ind[k];
+ xassert(w != v);
+ /* add value of z[j] that corresponds to vertex w */
+ j = ref[w];
+ xassert(1 <= j && j <= n);
+ if (pos[j] == w)
+ sum += P->col[j]->prim;
+ else if (neg[j] == w)
+ sum += 1.0 - P->col[j]->prim;
+ else
+ xassert(w != w);
+ }
+ /* cumulative weight of vertex v is an upper bound of weight
+ * of any clique containing v; so if it not greater than 1, do
+ * not include v in the induced subgraph */
+ if (sum < 1.010)
+ { vtoi[v] = 0;
+ continue;
+ }
+ /* include vertex v in the induced subgraph */
+ nn++;
+ vtoi[v] = nn;
+ itov[nn] = v;
+ wgt[nn] = z;
+ }
+ /* induced subgraph has been built */
+ csa->nn = nn;
+ return;
+}
+
+static int sub_adjacent(struct csa *csa, int i, int adj[])
+{ /* retrieve vertices of induced subgraph adjacent to specified
+ * vertex */
+ CFG *G = csa->G;
+ int nv = G->nv;
+ int *ind = csa->ind;
+ int nn = csa->nn;
+ int *vtoi = csa->vtoi;
+ int *itov = csa->itov;
+ int j, k, v, w, len, len1;
+ /* determine original vertex v corresponding to vertex i */
+ xassert(1 <= i && i <= nn);
+ v = itov[i];
+ /* retrieve vertices adjacent to vertex v in original graph */
+ len1 = cfg_get_adjacent(G, v, ind);
+ /* keep only adjacent vertices which are in induced subgraph and
+ * change their numbers appropriately */
+ len = 0;
+ for (k = 1; k <= len1; k++)
+ { /* there exists edge (v, w) in original graph */
+ w = ind[k];
+ xassert(1 <= w && w <= nv && w != v);
+ j = vtoi[w];
+ if (j != 0)
+ { /* vertex w is vertex j in induced subgraph */
+ xassert(1 <= j && j <= nn && j != i);
+ adj[++len] = j;
+ }
+ }
+ return len;
+}
+
+static int find_clique(struct csa *csa, int c_ind[])
+{ /* find maximum weight clique in induced subgraph with exact
+ * Ostergard's algorithm */
+ int nn = csa->nn;
+ double *wgt = csa->wgt;
+ int i, j, k, p, q, t, ne, nb, len, *iwt, *ind;
+ unsigned char *a;
+ xassert(nn >= 2);
+ /* allocate working array */
+ ind = talloc(1+nn, int);
+ /* calculate the number of elements in lower triangle (without
+ * diagonal) of adjacency matrix of induced subgraph */
+ ne = (nn * (nn - 1)) / 2;
+ /* calculate the number of bytes needed to store lower triangle
+ * of adjacency matrix */
+ nb = (ne + (CHAR_BIT - 1)) / CHAR_BIT;
+ /* allocate lower triangle of adjacency matrix */
+ a = talloc(nb, unsigned char);
+ /* fill lower triangle of adjacency matrix */
+ memset(a, 0, nb);
+ for (p = 1; p <= nn; p++)
+ { /* retrieve vertices adjacent to vertex p */
+ len = sub_adjacent(csa, p, ind);
+ for (k = 1; k <= len; k++)
+ { /* there exists edge (p, q) in induced subgraph */
+ q = ind[k];
+ xassert(1 <= q && q <= nn && q != p);
+ /* determine row and column indices of this edge in lower
+ * triangle of adjacency matrix */
+ if (p > q)
+ i = p, j = q;
+ else /* p < q */
+ i = q, j = p;
+ /* set bit a[i,j] to 1, i > j */
+ t = ((i - 1) * (i - 2)) / 2 + (j - 1);
+ a[t / CHAR_BIT] |=
+ (unsigned char)(1 << ((CHAR_BIT - 1) - t % CHAR_BIT));
+ }
+ }
+ /* scale vertex weights by 1000 and convert them to integers as
+ * required by Ostergard's algorithm */
+ iwt = ind;
+ for (i = 1; i <= nn; i++)
+ { /* it is assumed that 0 <= wgt[i] <= 1 */
+ t = (int)(1000.0 * wgt[i] + 0.5);
+ if (t < 0)
+ t = 0;
+ else if (t > 1000)
+ t = 1000;
+ iwt[i] = t;
+ }
+ /* find maximum weight clique */
+ len = wclique(nn, iwt, a, c_ind);
+ /* free working arrays */
+ tfree(ind);
+ tfree(a);
+ /* return clique size to calling routine */
+ return len;
+}
+
+static int func(void *info, int i, int ind[])
+{ /* auxiliary routine used by routine find_clique1 */
+ struct csa *csa = info;
+ xassert(1 <= i && i <= csa->nn);
+ return sub_adjacent(csa, i, ind);
+}
+
+static int find_clique1(struct csa *csa, int c_ind[])
+{ /* find maximum weight clique in induced subgraph with greedy
+ * heuristic */
+ int nn = csa->nn;
+ double *wgt = csa->wgt;
+ int len;
+ xassert(nn >= 2);
+ len = wclique1(nn, wgt, func, csa, c_ind);
+ /* return clique size to calling routine */
+ return len;
+}
+
+int cfg_find_clique(void *P, CFG *G, int ind[], double *sum_)
+{ int nv = G->nv;
+ struct csa csa;
+ int i, k, len;
+ double sum;
+ /* initialize common storage area */
+ csa.P = P;
+ csa.G = G;
+ csa.ind = talloc(1+nv, int);
+ csa.nn = -1;
+ csa.vtoi = talloc(1+nv, int);
+ csa.itov = talloc(1+nv, int);
+ csa.wgt = talloc(1+nv, double);
+ /* build induced subgraph */
+ build_subgraph(&csa);
+#ifdef GLP_DEBUG
+ xprintf("nn = %d\n", csa.nn);
+#endif
+ /* if subgraph has less than two vertices, do nothing */
+ if (csa.nn < 2)
+ { len = 0;
+ sum = 0.0;
+ goto skip;
+ }
+ /* find maximum weight clique in induced subgraph */
+#if 1 /* FIXME */
+ if (csa.nn <= 50)
+#endif
+ { /* induced subgraph is small; use exact algorithm */
+ len = find_clique(&csa, ind);
+ }
+ else
+ { /* induced subgraph is large; use greedy heuristic */
+ len = find_clique1(&csa, ind);
+ }
+ /* do not report clique, if it has less than two vertices */
+ if (len < 2)
+ { len = 0;
+ sum = 0.0;
+ goto skip;
+ }
+ /* convert indices of clique vertices from induced subgraph to
+ * original conflict graph and compute clique weight */
+ sum = 0.0;
+ for (k = 1; k <= len; k++)
+ { i = ind[k];
+ xassert(1 <= i && i <= csa.nn);
+ sum += csa.wgt[i];
+ ind[k] = csa.itov[i];
+ }
+skip: /* free working arrays */
+ tfree(csa.ind);
+ tfree(csa.vtoi);
+ tfree(csa.itov);
+ tfree(csa.wgt);
+ /* return to calling routine */
+ *sum_ = sum;
+ return len;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/cfg2.c b/test/monniaux/glpk-4.65/src/intopt/cfg2.c
new file mode 100644
index 00000000..85c0705e
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/cfg2.c
@@ -0,0 +1,91 @@
+/* cfg2.c (conflict graph) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015-2016 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/>.
+***********************************************************************/
+
+#include "cfg.h"
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_cfg_init - create and initialize conflict graph
+*
+* SYNOPSIS
+*
+* glp_cfg *glp_cfg_init(glp_prob *P);
+*
+* DESCRIPTION
+*
+* This routine creates and initializes the conflict graph for the
+* specified problem object.
+*
+* RETURNS
+*
+* The routine returns a pointer to the conflict graph descriptor.
+* However, if the conflict graph is empty (no conflicts have been
+* found), the routine returns NULL. */
+
+glp_cfg *glp_cfg_init(glp_prob *P)
+{ glp_cfg *G;
+ int j, n1, n2;
+ xprintf("Constructing conflict graph...\n");
+ G = cfg_build_graph(P);
+ n1 = n2 = 0;
+ for (j = 1; j <= P->n; j++)
+ { if (G->pos[j])
+ n1 ++;
+ if (G->neg[j])
+ n2++;
+ }
+ if (n1 == 0 && n2 == 0)
+ { xprintf("No conflicts found\n");
+ cfg_delete_graph(G);
+ G = NULL;
+ }
+ else
+ xprintf("Conflict graph has %d + %d = %d vertices\n",
+ n1, n2, G->nv);
+ return G;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_cfg_free - delete conflict graph descriptor
+*
+* SYNOPSIS
+*
+* void glp_cfg_free(glp_cfg *G);
+*
+* DESCRIPTION
+*
+* This routine deletes the conflict graph descriptor and frees all the
+* memory allocated to it. */
+
+void glp_cfg_free(glp_cfg *G)
+{ xassert(G != NULL);
+ cfg_delete_graph(G);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/clqcut.c b/test/monniaux/glpk-4.65/src/intopt/clqcut.c
new file mode 100644
index 00000000..d3db5b39
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/clqcut.c
@@ -0,0 +1,134 @@
+/* clqcut.c (clique cut generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2008-2016 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/>.
+***********************************************************************/
+
+#include "cfg.h"
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_clq_cut - generate clique cut from conflict graph
+*
+* SYNOPSIS
+*
+* int glp_clq_cut(glp_prob *P, glp_cfg *G, int ind[], double val[]);
+*
+* DESCRIPTION
+*
+* This routine attempts to generate a clique cut.
+*
+* The cut generated by the routine is the following inequality:
+*
+* sum a[j] * x[j] <= b,
+*
+* which is expected to be violated at the current basic solution.
+*
+* If the cut has been successfully generated, the routine stores its
+* non-zero coefficients a[j] and corresponding column indices j in the
+* array locations val[1], ..., val[len] and ind[1], ..., ind[len],
+* where 1 <= len <= n is the number of non-zero coefficients. The
+* right-hand side value b is stored in val[0], and ind[0] is set to 0.
+*
+* RETURNS
+*
+* If the cut has been successfully generated, the routine returns
+* len, the number of non-zero coefficients in the cut, 1 <= len <= n.
+* Otherwise, the routine returns a non-positive value. */
+
+int glp_clq_cut(glp_prob *P, glp_cfg *G, int ind[], double val[])
+{ int n = P->n;
+ int *pos = G->pos;
+ int *neg = G->neg;
+ int nv = G->nv;
+ int *ref = G->ref;
+ int j, k, v, len;
+ double rhs, sum;
+ xassert(G->n == n);
+ /* find maximum weight clique in conflict graph */
+ len = cfg_find_clique(P, G, ind, &sum);
+#ifdef GLP_DEBUG
+ xprintf("len = %d; sum = %g\n", len, sum);
+ cfg_check_clique(G, len, ind);
+#endif
+ /* check if clique inequality is violated */
+ if (sum < 1.07)
+ return 0;
+ /* expand clique to maximal one */
+ len = cfg_expand_clique(G, len, ind);
+#ifdef GLP_DEBUG
+ xprintf("maximal clique size = %d\n", len);
+ cfg_check_clique(G, len, ind);
+#endif
+ /* construct clique cut (fixed binary variables are removed, so
+ this cut is only locally valid) */
+ rhs = 1.0;
+ for (j = 1; j <= n; j++)
+ val[j] = 0.0;
+ for (k = 1; k <= len; k++)
+ { /* v is clique vertex */
+ v = ind[k];
+ xassert(1 <= v && v <= nv);
+ /* j is number of corresponding binary variable */
+ j = ref[v];
+ xassert(1 <= j && j <= n);
+ if (pos[j] == v)
+ { /* v corresponds to x[j] */
+ if (P->col[j]->type == GLP_FX)
+ { /* x[j] is fixed */
+ rhs -= P->col[j]->prim;
+ }
+ else
+ { /* x[j] is not fixed */
+ val[j] += 1.0;
+ }
+ }
+ else if (neg[j] == v)
+ { /* v corresponds to (1 - x[j]) */
+ if (P->col[j]->type == GLP_FX)
+ { /* x[j] is fixed */
+ rhs -= (1.0 - P->col[j]->prim);
+ }
+ else
+ { /* x[j] is not fixed */
+ val[j] -= 1.0;
+ rhs -= 1.0;
+ }
+ }
+ else
+ xassert(v != v);
+ }
+ /* convert cut inequality to sparse format */
+ len = 0;
+ for (j = 1; j <= n; j++)
+ { if (val[j] != 0.0)
+ { len++;
+ ind[len] = j;
+ val[len] = val[j];
+ }
+ }
+ ind[0] = 0, val[0] = rhs;
+ return len;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/covgen.c b/test/monniaux/glpk-4.65/src/intopt/covgen.c
new file mode 100644
index 00000000..427c3aa8
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/covgen.c
@@ -0,0 +1,885 @@
+/* covgen.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2017-2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "fvs.h"
+#include "ks.h"
+#include "prob.h"
+
+struct glp_cov
+{ /* cover cut generator working area */
+ int n;
+ /* number of columns (variables) */
+ glp_prob *set;
+ /* set of globally valid 0-1 knapsack inequalities chosen from
+ * the root problem; each inequality is either original row or
+ * its relaxation (surrogate 0-1 knapsack) which is constructed
+ * by substitution of lower/upper single/variable bounds for
+ * continuous and general integer (non-binary) variables */
+};
+
+struct bnd
+{ /* simple or variable bound */
+ /* if z = 0, it is a simple bound x >= or <= b; if b = -DBL_MAX
+ * (b = +DBL_MAX), x has no lower (upper) bound; otherwise, if
+ * z != 0, it is a variable bound x >= or <= a * z + b */
+ int z;
+ /* number of binary variable or 0 */
+ double a, b;
+ /* bound parameters */
+};
+
+struct csa
+{ /* common storage area */
+ glp_prob *P;
+ /* original (root) MIP */
+ struct bnd *l; /* struct bnd l[1+P->n]; */
+ /* lower simple/variable bounds of variables */
+ struct bnd *u; /* struct bnd u[1+P->n]; */
+ /* upper simple/variable bounds of variables */
+ glp_prob *set;
+ /* see struct glp_cov above */
+};
+
+/***********************************************************************
+* init_bounds - initialize bounds of variables with simple bounds
+*
+* This routine initializes lower and upper bounds of all variables
+* with simple bounds specified in the original mip. */
+
+static void init_bounds(struct csa *csa)
+{ glp_prob *P = csa->P;
+ struct bnd *l = csa->l, *u = csa->u;
+ int j;
+ for (j = 1; j <= P->n; j++)
+ { l[j].z = u[j].z = 0;
+ l[j].a = u[j].a = 0;
+ l[j].b = glp_get_col_lb(P, j);
+ u[j].b = glp_get_col_ub(P, j);
+ }
+ return;
+}
+
+/***********************************************************************
+* check_vb - check variable bound
+*
+* This routine checks if the specified i-th row has the form
+*
+* a1 * x + a2 * z >= or <= rhs, (1)
+*
+* where x is a non-fixed continuous or general integer variable, and
+* z is a binary variable. If it is, the routine converts the row to
+* the following variable lower/upper bound (VLB/VUB) of x:
+*
+* x >= or <= a * z + b, (2)
+*
+* where a = - a2 / a1, b = rhs / a1. Note that the inequality type is
+* changed to opposite one when a1 < 0.
+*
+* If the row is identified as a variable bound, the routine returns
+* GLP_LO for VLB or GLP_UP for VUB and provides the reference numbers
+* of variables x and z and values of a and b. Otherwise, the routine
+* returns zero. */
+
+static int check_vb(struct csa *csa, int i, int *x, int *z, double *a,
+ double *b)
+{ glp_prob *P = csa->P;
+ GLPROW *row;
+ GLPAIJ *a1, *a2;
+ int type;
+ double rhs;
+ xassert(1 <= i && i <= P->m);
+ row = P->row[i];
+ /* check row type */
+ switch (row->type)
+ { case GLP_LO:
+ case GLP_UP:
+ break;
+ default:
+ return 0;
+ }
+ /* take first term of the row */
+ a1 = row->ptr;
+ if (a1 == NULL)
+ return 0;
+ /* take second term of the row */
+ a2 = a1->r_next;
+ if (a2 == NULL)
+ return 0;
+ /* there should be exactly two terms in the row */
+ if (a2->r_next != NULL)
+ return 0;
+ /* if first term is a binary variable, swap the terms */
+ if (glp_get_col_kind(P, a1->col->j) == GLP_BV)
+ { GLPAIJ *a;
+ a = a1, a1 = a2, a2 = a;
+ }
+ /* now first term should be a non-fixed continuous or general
+ * integer variable */
+ if (a1->col->type == GLP_FX)
+ return 0;
+ if (glp_get_col_kind(P, a1->col->j) == GLP_BV)
+ return 0;
+ /* and second term should be a binary variable */
+ if (glp_get_col_kind(P, a2->col->j) != GLP_BV)
+ return 0;
+ /* VLB/VUB row has been identified */
+ switch (row->type)
+ { case GLP_LO:
+ type = a1->val > 0 ? GLP_LO : GLP_UP;
+ rhs = row->lb;
+ break;
+ case GLP_UP:
+ type = a1->val > 0 ? GLP_UP : GLP_LO;
+ rhs = row->ub;
+ break;
+ default:
+ xassert(type != type);
+ }
+ *x = a1->col->j;
+ *z = a2->col->j;
+ *a = - a2->val / a1->val;
+ *b = rhs / a1->val;
+ return type;
+}
+
+/***********************************************************************
+* set_vb - set variable bound
+*
+* This routine sets lower or upper variable bound specified as
+*
+* x >= a * z + b (type = GLP_LO)
+*
+* x <= a * z + b (type = GLP_UP) */
+
+static void set_vb(struct csa *csa, int type, int x, int z, double a,
+ double b)
+{ glp_prob *P = csa->P;
+ struct bnd *l = csa->l, *u = csa->u;
+ xassert(glp_get_col_type(P, x) != GLP_FX);
+ xassert(glp_get_col_kind(P, x) != GLP_BV);
+ xassert(glp_get_col_kind(P, z) == GLP_BV);
+ xassert(a != 0);
+ switch (type)
+ { case GLP_LO:
+ /* FIXME: check existing simple lower bound? */
+ l[x].z = z, l[x].a = a, l[x].b = b;
+ break;
+ case GLP_UP:
+ /* FIXME: check existing simple upper bound? */
+ u[x].z = z, u[x].a = a, u[x].b = b;
+ break;
+ default:
+ xassert(type != type);
+ }
+ return;
+}
+
+/***********************************************************************
+* obtain_vbs - obtain and set variable bounds
+*
+* This routine walks thru all rows of the original mip, identifies
+* rows specifying variable lower/upper bounds, and sets these bounds
+* for corresponding (non-binary) variables. */
+
+static void obtain_vbs(struct csa *csa)
+{ glp_prob *P = csa->P;
+ int i, x, z, type, save;
+ double a, b;
+ for (i = 1; i <= P->m; i++)
+ { switch (P->row[i]->type)
+ { case GLP_FR:
+ break;
+ case GLP_LO:
+ case GLP_UP:
+ type = check_vb(csa, i, &x, &z, &a, &b);
+ if (type)
+ set_vb(csa, type, x, z, a, b);
+ break;
+ case GLP_DB:
+ case GLP_FX:
+ /* double-side inequality l <= ... <= u and equality
+ * ... = l = u are considered as two single inequalities
+ * ... >= l and ... <= u */
+ save = P->row[i]->type;
+ P->row[i]->type = GLP_LO;
+ type = check_vb(csa, i, &x, &z, &a, &b);
+ if (type)
+ set_vb(csa, type, x, z, a, b);
+ P->row[i]->type = GLP_UP;
+ type = check_vb(csa, i, &x, &z, &a, &b);
+ if (type)
+ set_vb(csa, type, x, z, a, b);
+ P->row[i]->type = save;
+ break;
+ default:
+ xassert(P != P);
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* add_term - add term to sparse vector
+*
+* This routine computes the following linear combination:
+*
+* v := v + a * e[j],
+*
+* where v is a sparse vector in full storage format, a is a non-zero
+* scalar, e[j] is j-th column of unity matrix. */
+
+static void add_term(FVS *v, int j, double a)
+{ xassert(1 <= j && j <= v->n);
+ xassert(a != 0);
+ if (v->vec[j] == 0)
+ { /* create j-th component */
+ v->nnz++;
+ xassert(v->nnz <= v->n);
+ v->ind[v->nnz] = j;
+ }
+ /* perform addition */
+ v->vec[j] += a;
+ if (fabs(v->vec[j]) < 1e-9 * (1 + fabs(a)))
+ { /* remove j-th component */
+ v->vec[j] = DBL_MIN;
+ }
+ return;
+}
+
+/***********************************************************************
+* build_ks - build "0-1 knapsack" inequality
+*
+* Given an inequality of "not greater" type:
+*
+* sum{j in 1..n} a[j]*x[j] <= b, (1)
+*
+* this routine attempts to transform it to equivalent or relaxed "0-1
+* knapsack" inequality that contains only binary variables.
+*
+* If x[j] is a binary variable, the term a[j]*x[j] is not changed.
+* Otherwise, if x[j] is a continuous or integer non-binary variable,
+* it is replaced by its lower (if a[j] > 0) or upper (if a[j] < 0)
+* single or variable bound. In the latter case, if x[j] is a non-fixed
+* variable, this results in a relaxation of original inequality known
+* as "surrogate knapsack". Thus, if the specified inequality is valid
+* for the original mip, the resulting inequality is also valid.
+*
+* Note that in both source and resulting inequalities coefficients
+* a[j] can have any sign.
+*
+* On entry to the routine the source inequality is specified by the
+* parameters n, ind (contains original numbers of x[j]), a, and b. The
+* parameter v is a working sparse vector whose components are assumed
+* to be zero.
+*
+* On exit the routine stores the resulting "0-1 knapsack" inequality
+* in the parameters ind, a, and b, and returns n which is the number
+* of terms in the resulting inequality. Zero content of the vector v
+* is restored before exit.
+*
+* If the resulting inequality cannot be constructed due to missing
+* lower/upper bounds of some variable, the routine returns a negative
+* value. */
+
+static int build_ks(struct csa *csa, int n, int ind[], double a[],
+ double *b, FVS *v)
+{ glp_prob *P = csa->P;
+ struct bnd *l = csa->l, *u = csa->u;
+ int j, k;
+ /* check that v = 0 */
+#ifdef GLP_DEBUG
+ fvs_check_vec(v);
+#endif
+ xassert(v->nnz == 0);
+ /* walk thru terms of original inequality */
+ for (j = 1; j <= n; j++)
+ { /* process term a[j]*x[j] */
+ k = ind[j]; /* original number of x[j] in mip */
+ if (glp_get_col_kind(P, k) == GLP_BV)
+ { /* x[j] is a binary variable */
+ /* include its term into resulting inequality */
+ add_term(v, k, a[j]);
+ }
+ else if (a[j] > 0)
+ { /* substitute x[j] by its lower bound */
+ if (l[k].b == -DBL_MAX)
+ { /* x[j] has no lower bound */
+ n = -1;
+ goto skip;
+ }
+ else if (l[k].z == 0)
+ { /* x[j] has simple lower bound */
+ *b -= a[j] * l[k].b;
+ }
+ else
+ { /* x[j] has variable lower bound (a * z + b) */
+ add_term(v, l[k].z, a[j] * l[k].a);
+ *b -= a[j] * l[k].b;
+ }
+ }
+ else /* a[j] < 0 */
+ { /* substitute x[j] by its upper bound */
+ if (u[k].b == +DBL_MAX)
+ { /* x[j] has no upper bound */
+ n = -1;
+ goto skip;
+ }
+ else if (u[k].z == 0)
+ { /* x[j] has simple upper bound */
+ *b -= a[j] * u[k].b;
+ }
+ else
+ { /* x[j] has variable upper bound (a * z + b) */
+ add_term(v, u[k].z, a[j] * u[k].a);
+ *b -= a[j] * u[k].b;
+ }
+ }
+ }
+ /* replace tiny coefficients by exact zeros (see add_term) */
+ fvs_adjust_vec(v, 2 * DBL_MIN);
+ /* copy terms of resulting inequality */
+ xassert(v->nnz <= n);
+ n = v->nnz;
+ for (j = 1; j <= n; j++)
+ { ind[j] = v->ind[j];
+ a[j] = v->vec[ind[j]];
+ }
+skip: /* restore zero content of v */
+ fvs_clear_vec(v);
+ return n;
+}
+
+/***********************************************************************
+* can_be_active - check if inequality can be active
+*
+* This routine checks if the specified "0-1 knapsack" inequality
+*
+* sum{j in 1..n} a[j]*x[j] <= b
+*
+* can be active. If so, the routine returns true, otherwise false. */
+
+static int can_be_active(int n, const double a[], double b)
+{ int j;
+ double s;
+ s = 0;
+ for (j = 1; j <= n; j++)
+ { if (a[j] > 0)
+ s += a[j];
+ }
+ return s > b + .001 * (1 + fabs(b));
+}
+
+/***********************************************************************
+* is_sos_ineq - check if inequality is packing (SOS) constraint
+*
+* This routine checks if the specified "0-1 knapsack" inequality
+*
+* sum{j in 1..n} a[j]*x[j] <= b (1)
+*
+* is equivalent to packing inequality (Padberg calls such inequalities
+* special ordered set or SOS constraints)
+*
+* sum{j in J'} x[j] - sum{j in J"} x[j] <= 1 - |J"|. (2)
+*
+* If so, the routine returns true, otherwise false.
+*
+* Note that if X is a set of feasible binary points satisfying to (2),
+* its convex hull conv(X) equals to the set of feasible points of LP
+* relaxation of (2), which is a n-dimensional simplex, so inequalities
+* (2) are useless for generating cover cuts (due to unimodularity).
+*
+* ALGORITHM
+*
+* First, we make all a[j] positive by complementing x[j] = 1 - x'[j]
+* in (1). This is performed implicitly (i.e. actually the array a is
+* not changed), but b is replaced by b - sum{j : a[j] < 0}.
+*
+* Then we find two smallest coefficients a[p] = min{j in 1..n} a[j]
+* and a[q] = min{j in 1..n : j != p} a[j]. It is obvious that if
+* a[p] + a[q] > b, then a[i] + a[j] > b for all i != j, from which it
+* follows that x[i] + x[j] <= 1 for all i != j. But the latter means
+* that the original inequality (with all a[j] > 0) is equivalent to
+* packing inequality
+*
+* sum{j in 1..n} x[j] <= 1. (3)
+*
+* Returning to original (uncomplemented) variables x'[j] = 1 - x[j]
+* we have that the original inequality is equivalent to (2), where
+* J' = {j : a[j] > 0} and J" = {j : a[j] < 0}. */
+
+static int is_sos_ineq(int n, const double a[], double b)
+{ int j, p, q;
+ xassert(n >= 2);
+ /* compute b := b - sum{j : a[j] < 0} */
+ for (j = 1; j <= n; j++)
+ { if (a[j] < 0)
+ b -= a[j];
+ }
+ /* find a[p] = min{j in 1..n} a[j] */
+ p = 1;
+ for (j = 2; j <= n; j++)
+ { if (fabs(a[p]) > fabs(a[j]))
+ p = j;
+ }
+ /* find a[q] = min{j in 1..n : j != p} a[j] */
+ q = 0;
+ for (j = 1; j <= n; j++)
+ { if (j != p)
+ { if (q == 0 || fabs(a[q]) > fabs(a[j]))
+ q = j;
+ }
+ }
+ xassert(q != 0);
+ /* check condition a[p] + a[q] > b */
+ return fabs(a[p]) + fabs(a[q]) > b + .001 * (1 + fabs(b));
+}
+
+/***********************************************************************
+* process_ineq - basic inequality processing
+*
+* This routine performs basic processing of an inequality of "not
+* greater" type
+*
+* sum{j in 1..n} a[j]*x[j] <= b
+*
+* specified by the parameters, n, ind, a, and b.
+*
+* If the inequality can be transformed to "0-1 knapsack" ineqiality
+* suitable for generating cover cuts, the routine adds it to the set
+* of "0-1 knapsack" inequalities.
+*
+* Note that the arrays ind and a are not saved on exit. */
+
+static void process_ineq(struct csa *csa, int n, int ind[], double a[],
+ double b, FVS *v)
+{ int i;
+ /* attempt to transform the specified inequality to equivalent or
+ * relaxed "0-1 knapsack" inequality */
+ n = build_ks(csa, n, ind, a, &b, v);
+ if (n <= 1)
+ { /* uninteresting inequality (in principle, such inequalities
+ * should be removed by the preprocessor) */
+ goto done;
+ }
+ if (!can_be_active(n, a, b))
+ { /* inequality is redundant (i.e. cannot be active) */
+ goto done;
+ }
+ if (is_sos_ineq(n, a, b))
+ { /* packing (SOS) inequality is useless for generating cover
+ * cuts; currently such inequalities are just ignored */
+ goto done;
+ }
+ /* add resulting "0-1 knapsack" inequality to the set */
+ i = glp_add_rows(csa->set, 1);
+ glp_set_mat_row(csa->set, i, n, ind, a);
+ glp_set_row_bnds(csa->set, i, GLP_UP, b, b);
+done: return;
+}
+
+/**********************************************************************/
+
+glp_cov *glp_cov_init(glp_prob *P)
+{ /* create and initialize cover cut generator */
+ glp_cov *cov;
+ struct csa csa;
+ int i, k, len, *ind;
+ double rhs, *val;
+ FVS fvs;
+ csa.P = P;
+ csa.l = talloc(1+P->n, struct bnd);
+ csa.u = talloc(1+P->n, struct bnd);
+ csa.set = glp_create_prob();
+ glp_add_cols(csa.set, P->n);
+ /* initialize bounds of variables with simple bounds */
+ init_bounds(&csa);
+ /* obtain and set variable bounds */
+ obtain_vbs(&csa);
+ /* allocate working arrays */
+ ind = talloc(1+P->n, int);
+ val = talloc(1+P->n, double);
+ fvs_alloc_vec(&fvs, P->n);
+ /* process all rows of the root mip */
+ for (i = 1; i <= P->m; i++)
+ { switch (P->row[i]->type)
+ { case GLP_FR:
+ break;
+ case GLP_LO:
+ /* obtain row of ">=" type */
+ len = glp_get_mat_row(P, i, ind, val);
+ rhs = P->row[i]->lb;
+ /* transforms it to row of "<=" type */
+ for (k = 1; k <= len; k++)
+ val[k] = - val[k];
+ rhs = - rhs;
+ /* process the row */
+ process_ineq(&csa, len, ind, val, rhs, &fvs);
+ break;
+ case GLP_UP:
+ /* obtain row of "<=" type */
+ len = glp_get_mat_row(P, i, ind, val);
+ rhs = P->row[i]->ub;
+ /* and process it */
+ process_ineq(&csa, len, ind, val, rhs, &fvs);
+ break;
+ case GLP_DB:
+ case GLP_FX:
+ /* double-sided inequalitiy and equality constraints are
+ * processed as two separate inequalities */
+ /* obtain row as if it were of ">=" type */
+ len = glp_get_mat_row(P, i, ind, val);
+ rhs = P->row[i]->lb;
+ /* transforms it to row of "<=" type */
+ for (k = 1; k <= len; k++)
+ val[k] = - val[k];
+ rhs = - rhs;
+ /* and process it */
+ process_ineq(&csa, len, ind, val, rhs, &fvs);
+ /* obtain the same row as if it were of "<=" type */
+ len = glp_get_mat_row(P, i, ind, val);
+ rhs = P->row[i]->ub;
+ /* and process it */
+ process_ineq(&csa, len, ind, val, rhs, &fvs);
+ break;
+ default:
+ xassert(P != P);
+ }
+ }
+ /* free working arrays */
+ tfree(ind);
+ tfree(val);
+ fvs_check_vec(&fvs);
+ fvs_free_vec(&fvs);
+ /* the set of "0-1 knapsack" inequalities has been built */
+ if (csa.set->m == 0)
+ { /* the set is empty */
+ xprintf("No 0-1 knapsack inequalities detected\n");
+ cov = NULL;
+ glp_delete_prob(csa.set);
+ }
+ else
+ { /* create the cover cut generator working area */
+ xprintf("Number of 0-1 knapsack inequalities = %d\n",
+ csa.set->m);
+ cov = talloc(1, glp_cov);
+ cov->n = P->n;
+ cov->set = csa.set;
+#if 0
+ glp_write_lp(cov->set, 0, "set.lp");
+#endif
+ }
+ tfree(csa.l);
+ tfree(csa.u);
+ return cov;
+}
+
+/***********************************************************************
+* solve_ks - solve 0-1 knapsack problem
+*
+* This routine finds (sub)optimal solution to 0-1 knapsack problem:
+*
+* maximize z = sum{j in 1..n} c[j]x[j] (1)
+*
+* s.t. sum{j in 1..n} a[j]x[j] <= b (2)
+*
+* x[j] in {0, 1} for all j in 1..n (3)
+*
+* It is assumed that the instance is non-normalized, i.e. parameters
+* a, b, and c may have any sign.
+*
+* On exit the routine stores the (sub)optimal point found in locations
+* x[1], ..., x[n] and returns the optimal objective value. However, if
+* the instance is infeasible, the routine returns INT_MIN. */
+
+static int solve_ks(int n, const int a[], int b, const int c[],
+ char x[])
+{ int z;
+ /* surprisingly, even for some small instances (n = 50-100)
+ * MT1 routine takes too much time, so it is used only for tiny
+ * instances */
+ if (n <= 16)
+#if 0
+ z = ks_enum(n, a, b, c, x);
+#else
+ z = ks_mt1(n, a, b, c, x);
+#endif
+ else
+ z = ks_greedy(n, a, b, c, x);
+ return z;
+}
+
+/***********************************************************************
+* simple_cover - find simple cover cut
+*
+* Given a 0-1 knapsack inequality (which may be globally as well as
+* locally valid)
+*
+* sum{j in 1..n} a[j]x[j] <= b, (1)
+*
+* where all x[j] are binary variables and all a[j] are positive, and
+* a fractional point x~{j in 1..n}, which is feasible to LP relaxation
+* of (1), this routine attempts to find a simple cover inequality
+*
+* sum{j in C} (1 - x[j]) >= 1, (2)
+*
+* which is valid for (1) and violated at x~.
+*
+* Actually, the routine finds a cover C, i.e. a subset of {1, ..., n}
+* such that
+*
+* sum{j in C} a[j] > b, (3)
+*
+* and which minimizes the left-hand side of (2) at x~
+*
+* zeta = sum{j in C} (1 - x~[j]). (4)
+*
+* On exit the routine stores the characteritic vector z{j in 1..n}
+* of the cover found (i.e. z[j] = 1 means j in C, and z[j] = 0 means
+* j not in C), and returns corresponding minimal value of zeta (4).
+* However, if no cover is found, the routine returns DBL_MAX.
+*
+* ALGORITHM
+*
+* The separation problem (3)-(4) is converted to 0-1 knapsack problem
+* as follows.
+*
+* First, note that the constraint (3) is equivalent to
+*
+* sum{j in 1..n} a[j]z[j] >= b + eps, (5)
+*
+* where eps > 0 is a sufficiently small number (in case of integral
+* a and b we may take eps = 1). Multiplying both sides of (5) by (-1)
+* gives
+*
+* sum{j in 1..n} (-a[j])z[j] <= - b - eps. (6)
+*
+* To make all coefficients in (6) positive, z[j] is complemented by
+* substitution z[j] = 1 - z'[j] that finally gives
+*
+* sum{j in 1..n} a[j]z'[j] <= sum{j in 1..n} a[j] - b - eps. (7)
+*
+* Minimization of zeta (4) is equivalent to maximization of
+*
+* -zeta = sum{j in 1..n} (x~[j] - 1)z[j]. (8)
+*
+* Substitution z[j] = 1 - z'[j] gives
+*
+* -zeta = sum{j in 1..n} (1 - x~[j])z'[j] - zeta0, (9)
+*
+* where zeta0 = sum{j in 1..n} (1 - x~[j]) is a constant term.
+*
+* Thus, the 0-1 knapsack problem to be solved is the following:
+*
+* maximize
+*
+* -zeta = sum{j in 1..n} (1 - x~[j])z'[j] - zeta0 (10)
+*
+* subject to
+*
+* sum{j in 1..n} a[j]z'[j] <= sum{j in 1..n} a[j] - b - eps (11)
+*
+* z'[j] in {0,1} for all j = 1,...,n (12)
+*
+* (The constant term zeta0 doesn't affect the solution, so it can be
+* dropped.) */
+
+static double simple_cover(int n, const double a[], double b, const
+ double x[], char z[])
+{ int j, *aa, bb, *cc;
+ double max_aj, min_aj, s, eps;
+ xassert(n >= 3);
+ /* allocate working arrays */
+ aa = talloc(1+n, int);
+ cc = talloc(1+n, int);
+ /* compute max{j in 1..n} a[j] and min{j in 1..n} a[j] */
+ max_aj = 0, min_aj = DBL_MAX;
+ for (j = 1; j <= n; j++)
+ { xassert(a[j] > 0);
+ if (max_aj < a[j])
+ max_aj = a[j];
+ if (min_aj > a[j])
+ min_aj = a[j];
+ }
+ /* scale and round constraint parameters to make them integral;
+ * note that we make the resulting inequality stronger than (11),
+ * so a[j]'s are rounded up while rhs is rounded down */
+ s = 0;
+ for (j = 1; j <= n; j++)
+ { s += a[j];
+ aa[j] = ceil(a[j] / max_aj * 1000);
+ }
+ bb = floor((s - b) / max_aj * 1000) - 1;
+ /* scale and round obj. coefficients to make them integral;
+ * again we make the objective function stronger than (10), so
+ * the coefficients are rounded down */
+ for (j = 1; j <= n; j++)
+ { xassert(0 <= x[j] && x[j] <= 1);
+ cc[j] = floor((1 - x[j]) * 1000);
+ }
+ /* solve separation problem */
+ if (solve_ks(n, aa, bb, cc, z) == INT_MIN)
+ { /* no cover exists */
+ s = DBL_MAX;
+ goto skip;
+ }
+ /* determine z[j] = 1 - z'[j] */
+ for (j = 1; j <= n; j++)
+ { xassert(z[j] == 0 || z[j] == 1);
+ z[j] ^= 1;
+ }
+ /* check condition (11) for original (non-scaled) parameters */
+ s = 0;
+ for (j = 1; j <= n; j++)
+ { if (z[j])
+ s += a[j];
+ }
+ eps = 0.01 * (min_aj >= 1 ? min_aj : 1);
+ if (!(s >= b + eps))
+ { /* no cover found within a precision req'd */
+ s = DBL_MAX;
+ goto skip;
+ }
+ /* compute corresponding zeta (4) for cover found */
+ s = 0;
+ for (j = 1; j <= n; j++)
+ { if (z[j])
+ s += 1 - x[j];
+ }
+skip: /* free working arrays */
+ tfree(aa);
+ tfree(cc);
+ return s;
+}
+
+/**********************************************************************/
+
+void glp_cov_gen1(glp_prob *P, glp_cov *cov, glp_prob *pool)
+{ /* generate locally valid simple cover cuts */
+ int i, k, len, new_len, *ind;
+ double *val, rhs, *x, zeta;
+ char *z;
+ xassert(P->n == cov->n && P->n == cov->set->n);
+ xassert(glp_get_status(P) == GLP_OPT);
+ /* allocate working arrays */
+ ind = talloc(1+P->n, int);
+ val = talloc(1+P->n, double);
+ x = talloc(1+P->n, double);
+ z = talloc(1+P->n, char);
+ /* walk thru 0-1 knapsack inequalities */
+ for (i = 1; i <= cov->set->m; i++)
+ { /* retrieve 0-1 knapsack inequality */
+ len = glp_get_mat_row(cov->set, i, ind, val);
+ rhs = glp_get_row_ub(cov->set, i);
+ xassert(rhs != +DBL_MAX);
+ /* FIXME: skip, if slack is too large? */
+ /* substitute and eliminate binary variables which have been
+ * fixed in the current subproblem (this makes the inequality
+ * only locally valid) */
+ new_len = 0;
+ for (k = 1; k <= len; k++)
+ { if (glp_get_col_type(P, ind[k]) == GLP_FX)
+ rhs -= val[k] * glp_get_col_prim(P, ind[k]);
+ else
+ { new_len++;
+ ind[new_len] = ind[k];
+ val[new_len] = val[k];
+ }
+ }
+ len = new_len;
+ /* we need at least 3 binary variables in the inequality */
+ if (len <= 2)
+ continue;
+ /* obtain values of binary variables from optimal solution to
+ * LP relaxation of current subproblem */
+ for (k = 1; k <= len; k++)
+ { xassert(glp_get_col_kind(P, ind[k]) == GLP_BV);
+ x[k] = glp_get_col_prim(P, ind[k]);
+ if (x[k] < 0.00001)
+ x[k] = 0;
+ else if (x[k] > 0.99999)
+ x[k] = 1;
+ /* if val[k] < 0, perform substitution x[k] = 1 - x'[k] to
+ * make all coefficients positive */
+ if (val[k] < 0)
+ { ind[k] = - ind[k]; /* x[k] is complemented */
+ val[k] = - val[k];
+ rhs += val[k];
+ x[k] = 1 - x[k];
+ }
+ }
+ /* find locally valid simple cover cut */
+ zeta = simple_cover(len, val, rhs, x, z);
+ if (zeta > 0.95)
+ { /* no violation or insufficient violation; see (2) */
+ continue;
+ }
+ /* construct cover inequality (2) for the cover found, which
+ * for original binary variables x[k] is equivalent to:
+ * sum{k in C'} x[k] + sum{k in C"} x'[k] <= |C| - 1
+ * or
+ * sum{k in C'} x[k] + sum{k in C"} (1 - x[k]) <= |C| - 1
+ * or
+ * sum{k in C'} x[k] - sum{k in C"} x[k] <= |C'| - 1
+ * since |C| - |C"| = |C'| */
+ new_len = 0;
+ rhs = -1;
+ for (k = 1; k <= len; k++)
+ { if (z[k])
+ { new_len++;
+ if (ind[k] > 0)
+ { ind[new_len] = +ind[k];
+ val[new_len] = +1;
+ rhs++;
+ }
+ else /* ind[k] < 0 */
+ { ind[new_len] = -ind[k];
+ val[new_len] = -1;
+ }
+ }
+ }
+ len = new_len;
+ /* add the cover inequality to the local cut pool */
+ k = glp_add_rows(pool, 1);
+ glp_set_mat_row(pool, k, len, ind, val);
+ glp_set_row_bnds(pool, k, GLP_UP, rhs, rhs);
+ }
+ /* free working arrays */
+ tfree(ind);
+ tfree(val);
+ tfree(x);
+ tfree(z);
+ return;
+}
+
+/**********************************************************************/
+
+void glp_cov_free(glp_cov *cov)
+{ /* delete cover cut generator workspace */
+ xassert(cov != NULL);
+ glp_delete_prob(cov->set);
+ tfree(cov);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/fpump.c b/test/monniaux/glpk-4.65/src/intopt/fpump.c
new file mode 100644
index 00000000..0bdd6d4e
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/fpump.c
@@ -0,0 +1,360 @@
+/* fpump.c (feasibility pump heuristic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+#include "rng.h"
+
+/***********************************************************************
+* NAME
+*
+* ios_feas_pump - feasibility pump heuristic
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void ios_feas_pump(glp_tree *T);
+*
+* DESCRIPTION
+*
+* The routine ios_feas_pump is a simple implementation of the Feasi-
+* bility Pump heuristic.
+*
+* REFERENCES
+*
+* M.Fischetti, F.Glover, and A.Lodi. "The feasibility pump." Math.
+* Program., Ser. A 104, pp. 91-104 (2005). */
+
+struct VAR
+{ /* binary variable */
+ int j;
+ /* ordinal number */
+ int x;
+ /* value in the rounded solution (0 or 1) */
+ double d;
+ /* sorting key */
+};
+
+static int CDECL fcmp(const void *x, const void *y)
+{ /* comparison routine */
+ const struct VAR *vx = x, *vy = y;
+ if (vx->d > vy->d)
+ return -1;
+ else if (vx->d < vy->d)
+ return +1;
+ else
+ return 0;
+}
+
+void ios_feas_pump(glp_tree *T)
+{ glp_prob *P = T->mip;
+ int n = P->n;
+ glp_prob *lp = NULL;
+ struct VAR *var = NULL;
+ RNG *rand = NULL;
+ GLPCOL *col;
+ glp_smcp parm;
+ int j, k, new_x, nfail, npass, nv, ret, stalling;
+ double dist, tol;
+ xassert(glp_get_status(P) == GLP_OPT);
+ /* this heuristic is applied only once on the root level */
+ if (!(T->curr->level == 0 && T->curr->solved == 1)) goto done;
+ /* determine number of binary variables */
+ nv = 0;
+ for (j = 1; j <= n; j++)
+ { col = P->col[j];
+ /* if x[j] is continuous, skip it */
+ if (col->kind == GLP_CV) continue;
+ /* if x[j] is fixed, skip it */
+ if (col->type == GLP_FX) continue;
+ /* x[j] is non-fixed integer */
+ xassert(col->kind == GLP_IV);
+ if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
+ { /* x[j] is binary */
+ nv++;
+ }
+ else
+ { /* x[j] is general integer */
+ if (T->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("FPUMP heuristic cannot be applied due to genera"
+ "l integer variables\n");
+ goto done;
+ }
+ }
+ /* there must be at least one binary variable */
+ if (nv == 0) goto done;
+ if (T->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Applying FPUMP heuristic...\n");
+ /* build the list of binary variables */
+ var = xcalloc(1+nv, sizeof(struct VAR));
+ k = 0;
+ for (j = 1; j <= n; j++)
+ { col = P->col[j];
+ if (col->kind == GLP_IV && col->type == GLP_DB)
+ var[++k].j = j;
+ }
+ xassert(k == nv);
+ /* create working problem object */
+ lp = glp_create_prob();
+more: /* copy the original problem object to keep it intact */
+ glp_copy_prob(lp, P, GLP_OFF);
+ /* we are interested to find an integer feasible solution, which
+ is better than the best known one */
+ if (P->mip_stat == GLP_FEAS)
+ { int *ind;
+ double *val, bnd;
+ /* add a row and make it identical to the objective row */
+ glp_add_rows(lp, 1);
+ ind = xcalloc(1+n, sizeof(int));
+ val = xcalloc(1+n, sizeof(double));
+ for (j = 1; j <= n; j++)
+ { ind[j] = j;
+ val[j] = P->col[j]->coef;
+ }
+ glp_set_mat_row(lp, lp->m, n, ind, val);
+ xfree(ind);
+ xfree(val);
+ /* introduce upper (minimization) or lower (maximization)
+ bound to the original objective function; note that this
+ additional constraint is not violated at the optimal point
+ to LP relaxation */
+#if 0 /* modified by xypron <xypron.glpk@gmx.de> */
+ if (P->dir == GLP_MIN)
+ { bnd = P->mip_obj - 0.10 * (1.0 + fabs(P->mip_obj));
+ if (bnd < P->obj_val) bnd = P->obj_val;
+ glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
+ }
+ else if (P->dir == GLP_MAX)
+ { bnd = P->mip_obj + 0.10 * (1.0 + fabs(P->mip_obj));
+ if (bnd > P->obj_val) bnd = P->obj_val;
+ glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
+ }
+ else
+ xassert(P != P);
+#else
+ bnd = 0.1 * P->obj_val + 0.9 * P->mip_obj;
+ /* xprintf("bnd = %f\n", bnd); */
+ if (P->dir == GLP_MIN)
+ glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
+ else if (P->dir == GLP_MAX)
+ glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
+ else
+ xassert(P != P);
+#endif
+ }
+ /* reset pass count */
+ npass = 0;
+ /* invalidate the rounded point */
+ for (k = 1; k <= nv; k++)
+ var[k].x = -1;
+pass: /* next pass starts here */
+ npass++;
+ if (T->parm->msg_lev >= GLP_MSG_ALL)
+ xprintf("Pass %d\n", npass);
+ /* initialize minimal distance between the basic point and the
+ rounded one obtained during this pass */
+ dist = DBL_MAX;
+ /* reset failure count (the number of succeeded iterations failed
+ to improve the distance) */
+ nfail = 0;
+ /* if it is not the first pass, perturb the last rounded point
+ rather than construct it from the basic solution */
+ if (npass > 1)
+ { double rho, temp;
+ if (rand == NULL)
+ rand = rng_create_rand();
+ for (k = 1; k <= nv; k++)
+ { j = var[k].j;
+ col = lp->col[j];
+ rho = rng_uniform(rand, -0.3, 0.7);
+ if (rho < 0.0) rho = 0.0;
+ temp = fabs((double)var[k].x - col->prim);
+ if (temp + rho > 0.5) var[k].x = 1 - var[k].x;
+ }
+ goto skip;
+ }
+loop: /* innermost loop begins here */
+ /* round basic solution (which is assumed primal feasible) */
+ stalling = 1;
+ for (k = 1; k <= nv; k++)
+ { col = lp->col[var[k].j];
+ if (col->prim < 0.5)
+ { /* rounded value is 0 */
+ new_x = 0;
+ }
+ else
+ { /* rounded value is 1 */
+ new_x = 1;
+ }
+ if (var[k].x != new_x)
+ { stalling = 0;
+ var[k].x = new_x;
+ }
+ }
+ /* if the rounded point has not changed (stalling), choose and
+ flip some its entries heuristically */
+ if (stalling)
+ { /* compute d[j] = |x[j] - round(x[j])| */
+ for (k = 1; k <= nv; k++)
+ { col = lp->col[var[k].j];
+ var[k].d = fabs(col->prim - (double)var[k].x);
+ }
+ /* sort the list of binary variables by descending d[j] */
+ qsort(&var[1], nv, sizeof(struct VAR), fcmp);
+ /* choose and flip some rounded components */
+ for (k = 1; k <= nv; k++)
+ { if (k >= 5 && var[k].d < 0.35 || k >= 10) break;
+ var[k].x = 1 - var[k].x;
+ }
+ }
+skip: /* check if the time limit has been exhausted */
+ if (T->parm->tm_lim < INT_MAX &&
+ (double)(T->parm->tm_lim - 1) <=
+ 1000.0 * xdifftime(xtime(), T->tm_beg)) goto done;
+ /* build the objective, which is the distance between the current
+ (basic) point and the rounded one */
+ lp->dir = GLP_MIN;
+ lp->c0 = 0.0;
+ for (j = 1; j <= n; j++)
+ lp->col[j]->coef = 0.0;
+ for (k = 1; k <= nv; k++)
+ { j = var[k].j;
+ if (var[k].x == 0)
+ lp->col[j]->coef = +1.0;
+ else
+ { lp->col[j]->coef = -1.0;
+ lp->c0 += 1.0;
+ }
+ }
+ /* minimize the distance with the simplex method */
+ glp_init_smcp(&parm);
+ if (T->parm->msg_lev <= GLP_MSG_ERR)
+ parm.msg_lev = T->parm->msg_lev;
+ else if (T->parm->msg_lev <= GLP_MSG_ALL)
+ { parm.msg_lev = GLP_MSG_ON;
+ parm.out_dly = 10000;
+ }
+ ret = glp_simplex(lp, &parm);
+ if (ret != 0)
+ { if (T->parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("Warning: glp_simplex returned %d\n", ret);
+ goto done;
+ }
+ ret = glp_get_status(lp);
+ if (ret != GLP_OPT)
+ { if (T->parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("Warning: glp_get_status returned %d\n", ret);
+ goto done;
+ }
+ if (T->parm->msg_lev >= GLP_MSG_DBG)
+ xprintf("delta = %g\n", lp->obj_val);
+ /* check if the basic solution is integer feasible; note that it
+ may be so even if the minimial distance is positive */
+ tol = 0.3 * T->parm->tol_int;
+ for (k = 1; k <= nv; k++)
+ { col = lp->col[var[k].j];
+ if (tol < col->prim && col->prim < 1.0 - tol) break;
+ }
+ if (k > nv)
+ { /* okay; the basic solution seems to be integer feasible */
+ double *x = xcalloc(1+n, sizeof(double));
+ for (j = 1; j <= n; j++)
+ { x[j] = lp->col[j]->prim;
+ if (P->col[j]->kind == GLP_IV) x[j] = floor(x[j] + 0.5);
+ }
+#if 1 /* modified by xypron <xypron.glpk@gmx.de> */
+ /* reset direction and right-hand side of objective */
+ lp->c0 = P->c0;
+ lp->dir = P->dir;
+ /* fix integer variables */
+ for (k = 1; k <= nv; k++)
+#if 0 /* 18/VI-2013; fixed by mao
+ * this bug causes numerical instability, because column statuses
+ * are not changed appropriately */
+ { lp->col[var[k].j]->lb = x[var[k].j];
+ lp->col[var[k].j]->ub = x[var[k].j];
+ lp->col[var[k].j]->type = GLP_FX;
+ }
+#else
+ glp_set_col_bnds(lp, var[k].j, GLP_FX, x[var[k].j], 0.);
+#endif
+ /* copy original objective function */
+ for (j = 1; j <= n; j++)
+ lp->col[j]->coef = P->col[j]->coef;
+ /* solve original LP and copy result */
+ ret = glp_simplex(lp, &parm);
+ if (ret != 0)
+ { if (T->parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("Warning: glp_simplex returned %d\n", ret);
+#if 1 /* 17/III-2016: fix memory leak */
+ xfree(x);
+#endif
+ goto done;
+ }
+ ret = glp_get_status(lp);
+ if (ret != GLP_OPT)
+ { if (T->parm->msg_lev >= GLP_MSG_ERR)
+ xprintf("Warning: glp_get_status returned %d\n", ret);
+#if 1 /* 17/III-2016: fix memory leak */
+ xfree(x);
+#endif
+ goto done;
+ }
+ for (j = 1; j <= n; j++)
+ if (P->col[j]->kind != GLP_IV) x[j] = lp->col[j]->prim;
+#endif
+ ret = glp_ios_heur_sol(T, x);
+ xfree(x);
+ if (ret == 0)
+ { /* the integer solution is accepted */
+ if (ios_is_hopeful(T, T->curr->bound))
+ { /* it is reasonable to apply the heuristic once again */
+ goto more;
+ }
+ else
+ { /* the best known integer feasible solution just found
+ is close to optimal solution to LP relaxation */
+ goto done;
+ }
+ }
+ }
+ /* the basic solution is fractional */
+ if (dist == DBL_MAX ||
+ lp->obj_val <= dist - 1e-6 * (1.0 + dist))
+ { /* the distance is reducing */
+ nfail = 0, dist = lp->obj_val;
+ }
+ else
+ { /* improving the distance failed */
+ nfail++;
+ }
+ if (nfail < 3) goto loop;
+ if (npass < 5) goto pass;
+done: /* delete working objects */
+ if (lp != NULL) glp_delete_prob(lp);
+ if (var != NULL) xfree(var);
+ if (rand != NULL) rng_delete_rand(rand);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/gmicut.c b/test/monniaux/glpk-4.65/src/intopt/gmicut.c
new file mode 100644
index 00000000..4ef0b746
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/gmicut.c
@@ -0,0 +1,284 @@
+/* gmicut.c (Gomory's mixed integer cut generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2002-2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_gmi_cut - generate Gomory's mixed integer cut (core routine)
+*
+* SYNOPSIS
+*
+* int glp_gmi_cut(glp_prob *P, int j, int ind[], double val[], double
+* phi[]);
+*
+* DESCRIPTION
+*
+* This routine attempts to generate a Gomory's mixed integer cut for
+* specified integer column (structural variable), whose primal value
+* in current basic solution is integer infeasible (fractional).
+*
+* On entry to the routine the basic solution contained in the problem
+* object P should be optimal, and the basis factorization should be
+* valid. The parameter j should specify the ordinal number of column
+* (structural variable x[j]), for which the cut should be generated,
+* 1 <= j <= n, where n is the number of columns in the problem object.
+* This column should be integer, non-fixed, and basic, and its primal
+* value should be fractional.
+*
+* The cut generated by the routine is the following inequality:
+*
+* sum a[j] * x[j] >= b,
+*
+* which is expected to be violated at the current basic solution.
+*
+* If the cut has been successfully generated, the routine stores its
+* non-zero coefficients a[j] and corresponding column indices j in the
+* array locations val[1], ..., val[len] and ind[1], ..., ind[len],
+* where 1 <= len <= n is the number of non-zero coefficients. The
+* right-hand side value b is stored in val[0], and ind[0] is set to 0.
+*
+* The working array phi should have 1+m+n locations (location phi[0]
+* is not used), where m and n is the number of rows and columns in the
+* problem object, resp.
+*
+* RETURNS
+*
+* If the cut has been successfully generated, the routine returns
+* len, the number of non-zero coefficients in the cut, 1 <= len <= n.
+*
+* Otherwise, the routine returns one of the following codes:
+*
+* -1 current basis factorization is not valid;
+*
+* -2 current basic solution is not optimal;
+*
+* -3 column ordinal number j is out of range;
+*
+* -4 variable x[j] is not of integral kind;
+*
+* -5 variable x[j] is either fixed or non-basic;
+*
+* -6 primal value of variable x[j] in basic solution is too close
+* to nearest integer;
+*
+* -7 some coefficients in the simplex table row corresponding to
+* variable x[j] are too large in magnitude;
+*
+* -8 some free (unbounded) variables have non-zero coefficients in
+* the simplex table row corresponding to variable x[j].
+*
+* ALGORITHM
+*
+* See glpk/doc/notes/gomory (in Russian). */
+
+#define f(x) ((x) - floor(x))
+/* compute fractional part of x */
+
+int glp_gmi_cut(glp_prob *P, int j,
+ int ind[/*1+n*/], double val[/*1+n*/], double phi[/*1+m+n*/])
+{ int m = P->m;
+ int n = P->n;
+ GLPROW *row;
+ GLPCOL *col;
+ GLPAIJ *aij;
+ int i, k, len, kind, stat;
+ double lb, ub, alfa, beta, ksi, phi1, rhs;
+ /* sanity checks */
+ if (!(P->m == 0 || P->valid))
+ { /* current basis factorization is not valid */
+ return -1;
+ }
+ if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
+ { /* current basic solution is not optimal */
+ return -2;
+ }
+ if (!(1 <= j && j <= n))
+ { /* column ordinal number is out of range */
+ return -3;
+ }
+ col = P->col[j];
+ if (col->kind != GLP_IV)
+ { /* x[j] is not of integral kind */
+ return -4;
+ }
+ if (col->type == GLP_FX || col->stat != GLP_BS)
+ { /* x[j] is either fixed or non-basic */
+ return -5;
+ }
+ if (fabs(col->prim - floor(col->prim + 0.5)) < 0.001)
+ { /* primal value of x[j] is too close to nearest integer */
+ return -6;
+ }
+ /* compute row of the simplex tableau, which (row) corresponds
+ * to specified basic variable xB[i] = x[j]; see (23) */
+ len = glp_eval_tab_row(P, m+j, ind, val);
+ /* determine beta[i], which a value of xB[i] in optimal solution
+ * to current LP relaxation; note that this value is the same as
+ * if it would be computed with formula (27); it is assumed that
+ * beta[i] is fractional enough */
+ beta = P->col[j]->prim;
+ /* compute cut coefficients phi and right-hand side rho, which
+ * correspond to formula (30); dense format is used, because rows
+ * of the simplex tableau are usually dense */
+ for (k = 1; k <= m+n; k++)
+ phi[k] = 0.0;
+ rhs = f(beta); /* initial value of rho; see (28), (32) */
+ for (j = 1; j <= len; j++)
+ { /* determine original number of non-basic variable xN[j] */
+ k = ind[j];
+ xassert(1 <= k && k <= m+n);
+ /* determine the kind, bounds and current status of xN[j] in
+ * optimal solution to LP relaxation */
+ if (k <= m)
+ { /* auxiliary variable */
+ row = P->row[k];
+ kind = GLP_CV;
+ lb = row->lb;
+ ub = row->ub;
+ stat = row->stat;
+ }
+ else
+ { /* structural variable */
+ col = P->col[k-m];
+ kind = col->kind;
+ lb = col->lb;
+ ub = col->ub;
+ stat = col->stat;
+ }
+ /* xN[j] cannot be basic */
+ xassert(stat != GLP_BS);
+ /* determine row coefficient ksi[i,j] at xN[j]; see (23) */
+ ksi = val[j];
+ /* if ksi[i,j] is too large in magnitude, report failure */
+ if (fabs(ksi) > 1e+05)
+ return -7;
+ /* if ksi[i,j] is too small in magnitude, skip it */
+ if (fabs(ksi) < 1e-10)
+ goto skip;
+ /* compute row coefficient alfa[i,j] at y[j]; see (26) */
+ switch (stat)
+ { case GLP_NF:
+ /* xN[j] is free (unbounded) having non-zero ksi[i,j];
+ * report failure */
+ return -8;
+ case GLP_NL:
+ /* xN[j] has active lower bound */
+ alfa = - ksi;
+ break;
+ case GLP_NU:
+ /* xN[j] has active upper bound */
+ alfa = + ksi;
+ break;
+ case GLP_NS:
+ /* xN[j] is fixed; skip it */
+ goto skip;
+ default:
+ xassert(stat != stat);
+ }
+ /* compute cut coefficient phi'[j] at y[j]; see (21), (28) */
+ switch (kind)
+ { case GLP_IV:
+ /* y[j] is integer */
+ if (fabs(alfa - floor(alfa + 0.5)) < 1e-10)
+ { /* alfa[i,j] is close to nearest integer; skip it */
+ goto skip;
+ }
+ else if (f(alfa) <= f(beta))
+ phi1 = f(alfa);
+ else
+ phi1 = (f(beta) / (1.0 - f(beta))) * (1.0 - f(alfa));
+ break;
+ case GLP_CV:
+ /* y[j] is continuous */
+ if (alfa >= 0.0)
+ phi1 = + alfa;
+ else
+ phi1 = (f(beta) / (1.0 - f(beta))) * (- alfa);
+ break;
+ default:
+ xassert(kind != kind);
+ }
+ /* compute cut coefficient phi[j] at xN[j] and update right-
+ * hand side rho; see (31), (32) */
+ switch (stat)
+ { case GLP_NL:
+ /* xN[j] has active lower bound */
+ phi[k] = + phi1;
+ rhs += phi1 * lb;
+ break;
+ case GLP_NU:
+ /* xN[j] has active upper bound */
+ phi[k] = - phi1;
+ rhs -= phi1 * ub;
+ break;
+ default:
+ xassert(stat != stat);
+ }
+skip: ;
+ }
+ /* now the cut has the form sum_k phi[k] * x[k] >= rho, where cut
+ * coefficients are stored in the array phi in dense format;
+ * x[1,...,m] are auxiliary variables, x[m+1,...,m+n] are struc-
+ * tural variables; see (30) */
+ /* eliminate auxiliary variables in order to express the cut only
+ * through structural variables; see (33) */
+ for (i = 1; i <= m; i++)
+ { if (fabs(phi[i]) < 1e-10)
+ continue;
+ /* auxiliary variable x[i] has non-zero cut coefficient */
+ row = P->row[i];
+ /* x[i] cannot be fixed variable */
+ xassert(row->type != GLP_FX);
+ /* substitute x[i] = sum_j a[i,j] * x[m+j] */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ phi[m+aij->col->j] += phi[i] * aij->val;
+ }
+ /* convert the final cut to sparse format and substitute fixed
+ * (structural) variables */
+ len = 0;
+ for (j = 1; j <= n; j++)
+ { if (fabs(phi[m+j]) < 1e-10)
+ continue;
+ /* structural variable x[m+j] has non-zero cut coefficient */
+ col = P->col[j];
+ if (col->type == GLP_FX)
+ { /* eliminate x[m+j] */
+ rhs -= phi[m+j] * col->lb;
+ }
+ else
+ { len++;
+ ind[len] = j;
+ val[len] = phi[m+j];
+ }
+ }
+ if (fabs(rhs) < 1e-12)
+ rhs = 0.0;
+ ind[0] = 0, val[0] = rhs;
+ /* the cut has been successfully generated */
+ return len;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/gmigen.c b/test/monniaux/glpk-4.65/src/intopt/gmigen.c
new file mode 100644
index 00000000..627682cb
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/gmigen.c
@@ -0,0 +1,142 @@
+/* gmigen.c (Gomory's mixed integer cuts generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2002-2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "prob.h"
+
+/***********************************************************************
+* NAME
+*
+* glp_gmi_gen - generate Gomory's mixed integer cuts
+*
+* SYNOPSIS
+*
+* int glp_gmi_gen(glp_prob *P, glp_prob *pool, int max_cuts);
+*
+* DESCRIPTION
+*
+* This routine attempts to generate Gomory's mixed integer cuts for
+* integer variables, whose primal values in current basic solution are
+* integer infeasible (fractional).
+*
+* On entry to the routine the basic solution contained in the problem
+* object P should be optimal, and the basis factorization should be
+* valid.
+*
+* The cutting plane inequalities generated by the routine are added to
+* the specified cut pool.
+*
+* The parameter max_cuts specifies the maximal number of cuts to be
+* generated. Note that the number of cuts cannot exceed the number of
+* basic variables, which is the number of rows in the problem object.
+*
+* RETURNS
+*
+* The routine returns the number of cuts that have been generated and
+* added to the cut pool. */
+
+#define f(x) ((x) - floor(x))
+/* compute fractional part of x */
+
+struct var { int j; double f; };
+
+static int CDECL fcmp(const void *p1, const void *p2)
+{ const struct var *v1 = p1, *v2 = p2;
+ if (v1->f > v2->f) return -1;
+ if (v1->f < v2->f) return +1;
+ return 0;
+}
+
+int glp_gmi_gen(glp_prob *P, glp_prob *pool, int max_cuts)
+{ int m = P->m;
+ int n = P->n;
+ GLPCOL *col;
+ struct var *var;
+ int i, j, k, t, len, nv, nnn, *ind;
+ double frac, *val, *phi;
+ /* sanity checks */
+ if (!(P->m == 0 || P->valid))
+ xerror("glp_gmi_gen: basis factorization does not exist\n");
+ if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
+ xerror("glp_gmi_gen: optimal basic solution required\n");
+ if (pool->n != n)
+ xerror("glp_gmi_gen: cut pool has wrong number of columns\n");
+ /* allocate working arrays */
+ var = xcalloc(1+n, sizeof(struct var));
+ ind = xcalloc(1+n, sizeof(int));
+ val = xcalloc(1+n, sizeof(double));
+ phi = xcalloc(1+m+n, sizeof(double));
+ /* build the list of integer structural variables, which are
+ * basic and have integer infeasible (fractional) primal values
+ * in optimal solution to specified LP */
+ nv = 0;
+ for (j = 1; j <= n; j++)
+ { col = P->col[j];
+ if (col->kind != GLP_IV)
+ continue;
+ if (col->type == GLP_FX)
+ continue;
+ if (col->stat != GLP_BS)
+ continue;
+ frac = f(col->prim);
+ if (!(0.05 <= frac && frac <= 0.95))
+ continue;
+ /* add variable to the list */
+ nv++, var[nv].j = j, var[nv].f = frac;
+ }
+ /* sort the list by descending fractionality */
+ qsort(&var[1], nv, sizeof(struct var), fcmp);
+ /* try to generate cuts by one for each variable in the list, but
+ * not more than max_cuts cuts */
+ nnn = 0;
+ for (t = 1; t <= nv; t++)
+ { len = glp_gmi_cut(P, var[t].j, ind, val, phi);
+ if (len < 1)
+ goto skip;
+ /* if the cut inequality seems to be badly scaled, reject it
+ * to avoid numerical difficulties */
+ for (k = 1; k <= len; k++)
+ { if (fabs(val[k]) < 1e-03)
+ goto skip;
+ if (fabs(val[k]) > 1e+03)
+ goto skip;
+ }
+ /* add the cut to the cut pool for further consideration */
+ i = glp_add_rows(pool, 1);
+ glp_set_row_bnds(pool, i, GLP_LO, val[0], 0);
+ glp_set_mat_row(pool, i, len, ind, val);
+ /* one cut has been generated */
+ nnn++;
+ if (nnn == max_cuts)
+ break;
+skip: ;
+ }
+ /* free working arrays */
+ xfree(var);
+ xfree(ind);
+ xfree(val);
+ xfree(phi);
+ return nnn;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/mirgen.c b/test/monniaux/glpk-4.65/src/intopt/mirgen.c
new file mode 100644
index 00000000..45a0a55d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/mirgen.c
@@ -0,0 +1,1529 @@
+/* mirgen.c (mixed integer rounding cuts generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2007-2018 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/>.
+***********************************************************************/
+
+#if 1 /* 29/II-2016 by Chris */
+/*----------------------------------------------------------------------
+Subject: Mir cut generation performance improvement
+From: Chris Matrakidis <cmatraki@gmail.com>
+To: Andrew Makhorin <mao@gnu.org>, help-glpk <help-glpk@gnu.org>
+
+Andrew,
+
+I noticed that mir cut generation takes considerable time on some large
+problems (like rocII-4-11 from miplib). The attached patch makes two
+improvements that considerably improve performance in such instances:
+1. A lot of time was spent on generating a temporary vector in function
+aggregate_row. It is a lot faster to reuse an existing vector.
+2. A search for an element in the same function was done in row order,
+where using the elements in the order they are in the column is more
+efficient. This changes the generated cuts in some cases, but seems
+neutral overall (0.3% less cuts in a test set of 64 miplib instances).
+
+Best Regards,
+
+Chris Matrakidis
+----------------------------------------------------------------------*/
+#endif
+
+#include "env.h"
+#include "prob.h"
+#include "spv.h"
+
+#define MIR_DEBUG 0
+
+#define MAXAGGR 5
+/* maximal number of rows that can be aggregated */
+
+struct glp_mir
+{ /* MIR cut generator working area */
+ /*--------------------------------------------------------------*/
+ /* global information valid for the root subproblem */
+ int m;
+ /* number of rows (in the root subproblem) */
+ int n;
+ /* number of columns */
+ char *skip; /* char skip[1+m]; */
+ /* skip[i], 1 <= i <= m, is a flag that means that row i should
+ not be used because (1) it is not suitable, or (2) because it
+ has been used in the aggregated constraint */
+ char *isint; /* char isint[1+m+n]; */
+ /* isint[k], 1 <= k <= m+n, is a flag that means that variable
+ x[k] is integer (otherwise, continuous) */
+ double *lb; /* double lb[1+m+n]; */
+ /* lb[k], 1 <= k <= m+n, is lower bound of x[k]; -DBL_MAX means
+ that x[k] has no lower bound */
+ int *vlb; /* int vlb[1+m+n]; */
+ /* vlb[k] = k', 1 <= k <= m+n, is the number of integer variable,
+ which defines variable lower bound x[k] >= lb[k] * x[k']; zero
+ means that x[k] has simple lower bound */
+ double *ub; /* double ub[1+m+n]; */
+ /* ub[k], 1 <= k <= m+n, is upper bound of x[k]; +DBL_MAX means
+ that x[k] has no upper bound */
+ int *vub; /* int vub[1+m+n]; */
+ /* vub[k] = k', 1 <= k <= m+n, is the number of integer variable,
+ which defines variable upper bound x[k] <= ub[k] * x[k']; zero
+ means that x[k] has simple upper bound */
+ /*--------------------------------------------------------------*/
+ /* current (fractional) point to be separated */
+ double *x; /* double x[1+m+n]; */
+ /* x[k] is current value of auxiliary (1 <= k <= m) or structural
+ (m+1 <= k <= m+n) variable */
+ /*--------------------------------------------------------------*/
+ /* aggregated constraint sum a[k] * x[k] = b, which is a linear
+ combination of original constraints transformed to equalities
+ by introducing auxiliary variables */
+ int agg_cnt;
+ /* number of rows (original constraints) used to build aggregated
+ constraint, 1 <= agg_cnt <= MAXAGGR */
+ int *agg_row; /* int agg_row[1+MAXAGGR]; */
+ /* agg_row[k], 1 <= k <= agg_cnt, is the row number used to build
+ aggregated constraint */
+ SPV *agg_vec; /* SPV agg_vec[1:m+n]; */
+ /* sparse vector of aggregated constraint coefficients, a[k] */
+ double agg_rhs;
+ /* right-hand side of the aggregated constraint, b */
+ /*--------------------------------------------------------------*/
+ /* bound substitution flags for modified constraint */
+ char *subst; /* char subst[1+m+n]; */
+ /* subst[k], 1 <= k <= m+n, is a bound substitution flag used for
+ variable x[k]:
+ '?' - x[k] is missing in modified constraint
+ 'L' - x[k] = (lower bound) + x'[k]
+ 'U' - x[k] = (upper bound) - x'[k] */
+ /*--------------------------------------------------------------*/
+ /* modified constraint sum a'[k] * x'[k] = b', where x'[k] >= 0,
+ derived from aggregated constraint by substituting bounds;
+ note that due to substitution of variable bounds there may be
+ additional terms in the modified constraint */
+ SPV *mod_vec; /* SPV mod_vec[1:m+n]; */
+ /* sparse vector of modified constraint coefficients, a'[k] */
+ double mod_rhs;
+ /* right-hand side of the modified constraint, b' */
+ /*--------------------------------------------------------------*/
+ /* cutting plane sum alpha[k] * x[k] <= beta */
+ SPV *cut_vec; /* SPV cut_vec[1:m+n]; */
+ /* sparse vector of cutting plane coefficients, alpha[k] */
+ double cut_rhs;
+ /* right-hand size of the cutting plane, beta */
+};
+
+/***********************************************************************
+* NAME
+*
+* glp_mir_init - create and initialize MIR cut generator
+*
+* SYNOPSIS
+*
+* glp_mir *glp_mir_init(glp_prob *P);
+*
+* DESCRIPTION
+*
+* This routine creates and initializes the MIR cut generator for the
+* specified problem object.
+*
+* RETURNS
+*
+* The routine returns a pointer to the MIR cut generator workspace. */
+
+static void set_row_attrib(glp_prob *mip, glp_mir *mir)
+{ /* set global row attributes */
+ int m = mir->m;
+ int k;
+ for (k = 1; k <= m; k++)
+ { GLPROW *row = mip->row[k];
+ mir->skip[k] = 0;
+ mir->isint[k] = 0;
+ switch (row->type)
+ { case GLP_FR:
+ mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
+ case GLP_LO:
+ mir->lb[k] = row->lb, mir->ub[k] = +DBL_MAX; break;
+ case GLP_UP:
+ mir->lb[k] = -DBL_MAX, mir->ub[k] = row->ub; break;
+ case GLP_DB:
+ mir->lb[k] = row->lb, mir->ub[k] = row->ub; break;
+ case GLP_FX:
+ mir->lb[k] = mir->ub[k] = row->lb; break;
+ default:
+ xassert(row != row);
+ }
+ mir->vlb[k] = mir->vub[k] = 0;
+ }
+ return;
+}
+
+static void set_col_attrib(glp_prob *mip, glp_mir *mir)
+{ /* set global column attributes */
+ int m = mir->m;
+ int n = mir->n;
+ int k;
+ for (k = m+1; k <= m+n; k++)
+ { GLPCOL *col = mip->col[k-m];
+ switch (col->kind)
+ { case GLP_CV:
+ mir->isint[k] = 0; break;
+ case GLP_IV:
+ mir->isint[k] = 1; break;
+ default:
+ xassert(col != col);
+ }
+ switch (col->type)
+ { case GLP_FR:
+ mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
+ case GLP_LO:
+ mir->lb[k] = col->lb, mir->ub[k] = +DBL_MAX; break;
+ case GLP_UP:
+ mir->lb[k] = -DBL_MAX, mir->ub[k] = col->ub; break;
+ case GLP_DB:
+ mir->lb[k] = col->lb, mir->ub[k] = col->ub; break;
+ case GLP_FX:
+ mir->lb[k] = mir->ub[k] = col->lb; break;
+ default:
+ xassert(col != col);
+ }
+ mir->vlb[k] = mir->vub[k] = 0;
+ }
+ return;
+}
+
+static void set_var_bounds(glp_prob *mip, glp_mir *mir)
+{ /* set variable bounds */
+ int m = mir->m;
+ GLPAIJ *aij;
+ int i, k1, k2;
+ double a1, a2;
+ for (i = 1; i <= m; i++)
+ { /* we need the row to be '>= 0' or '<= 0' */
+ if (!(mir->lb[i] == 0.0 && mir->ub[i] == +DBL_MAX ||
+ mir->lb[i] == -DBL_MAX && mir->ub[i] == 0.0)) continue;
+ /* take first term */
+ aij = mip->row[i]->ptr;
+ if (aij == NULL) continue;
+ k1 = m + aij->col->j, a1 = aij->val;
+ /* take second term */
+ aij = aij->r_next;
+ if (aij == NULL) continue;
+ k2 = m + aij->col->j, a2 = aij->val;
+ /* there must be only two terms */
+ if (aij->r_next != NULL) continue;
+ /* interchange terms, if needed */
+ if (!mir->isint[k1] && mir->isint[k2])
+ ;
+ else if (mir->isint[k1] && !mir->isint[k2])
+ { k2 = k1, a2 = a1;
+ k1 = m + aij->col->j, a1 = aij->val;
+ }
+ else
+ { /* both terms are either continuous or integer */
+ continue;
+ }
+ /* x[k2] should be double-bounded */
+ if (mir->lb[k2] == -DBL_MAX || mir->ub[k2] == +DBL_MAX ||
+ mir->lb[k2] == mir->ub[k2]) continue;
+ /* change signs, if necessary */
+ if (mir->ub[i] == 0.0) a1 = - a1, a2 = - a2;
+ /* now the row has the form a1 * x1 + a2 * x2 >= 0, where x1
+ is continuous, x2 is integer */
+ if (a1 > 0.0)
+ { /* x1 >= - (a2 / a1) * x2 */
+ if (mir->vlb[k1] == 0)
+ { /* set variable lower bound for x1 */
+ mir->lb[k1] = - a2 / a1;
+ mir->vlb[k1] = k2;
+ /* the row should not be used */
+ mir->skip[i] = 1;
+ }
+ }
+ else /* a1 < 0.0 */
+ { /* x1 <= - (a2 / a1) * x2 */
+ if (mir->vub[k1] == 0)
+ { /* set variable upper bound for x1 */
+ mir->ub[k1] = - a2 / a1;
+ mir->vub[k1] = k2;
+ /* the row should not be used */
+ mir->skip[i] = 1;
+ }
+ }
+ }
+ return;
+}
+
+static void mark_useless_rows(glp_prob *mip, glp_mir *mir)
+{ /* mark rows which should not be used */
+ int m = mir->m;
+ GLPAIJ *aij;
+ int i, k, nv;
+ for (i = 1; i <= m; i++)
+ { /* free rows should not be used */
+ if (mir->lb[i] == -DBL_MAX && mir->ub[i] == +DBL_MAX)
+ { mir->skip[i] = 1;
+ continue;
+ }
+ nv = 0;
+ for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ { k = m + aij->col->j;
+ /* rows with free variables should not be used */
+ if (mir->lb[k] == -DBL_MAX && mir->ub[k] == +DBL_MAX)
+ { mir->skip[i] = 1;
+ break;
+ }
+ /* rows with integer variables having infinite (lower or
+ upper) bound should not be used */
+ if (mir->isint[k] && mir->lb[k] == -DBL_MAX ||
+ mir->isint[k] && mir->ub[k] == +DBL_MAX)
+ { mir->skip[i] = 1;
+ break;
+ }
+ /* count non-fixed variables */
+ if (!(mir->vlb[k] == 0 && mir->vub[k] == 0 &&
+ mir->lb[k] == mir->ub[k])) nv++;
+ }
+ /* rows with all variables fixed should not be used */
+ if (nv == 0)
+ { mir->skip[i] = 1;
+ continue;
+ }
+ }
+ return;
+}
+
+glp_mir *glp_mir_init(glp_prob *mip)
+{ /* create and initialize MIR cut generator */
+ int m = mip->m;
+ int n = mip->n;
+ glp_mir *mir;
+#if MIR_DEBUG
+ xprintf("ios_mir_init: warning: debug mode enabled\n");
+#endif
+ /* allocate working area */
+ mir = xmalloc(sizeof(glp_mir));
+ mir->m = m;
+ mir->n = n;
+ mir->skip = xcalloc(1+m, sizeof(char));
+ mir->isint = xcalloc(1+m+n, sizeof(char));
+ mir->lb = xcalloc(1+m+n, sizeof(double));
+ mir->vlb = xcalloc(1+m+n, sizeof(int));
+ mir->ub = xcalloc(1+m+n, sizeof(double));
+ mir->vub = xcalloc(1+m+n, sizeof(int));
+ mir->x = xcalloc(1+m+n, sizeof(double));
+ mir->agg_row = xcalloc(1+MAXAGGR, sizeof(int));
+ mir->agg_vec = spv_create_vec(m+n);
+ mir->subst = xcalloc(1+m+n, sizeof(char));
+ mir->mod_vec = spv_create_vec(m+n);
+ mir->cut_vec = spv_create_vec(m+n);
+ /* set global row attributes */
+ set_row_attrib(mip, mir);
+ /* set global column attributes */
+ set_col_attrib(mip, mir);
+ /* set variable bounds */
+ set_var_bounds(mip, mir);
+ /* mark rows which should not be used */
+ mark_useless_rows(mip, mir);
+ return mir;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_mir_gen - generate mixed integer rounding (MIR) cuts
+*
+* SYNOPSIS
+*
+* int glp_mir_gen(glp_prob *P, glp_mir *mir, glp_prob *pool);
+*
+* DESCRIPTION
+*
+* This routine attempts to generate mixed integer rounding (MIR) cuts
+* for current basic solution to the specified problem object.
+*
+* The cutting plane inequalities generated by the routine are added to
+* the specified cut pool.
+*
+* RETURNS
+*
+* The routine returns the number of cuts that have been generated and
+* added to the cut pool. */
+
+static void get_current_point(glp_prob *mip, glp_mir *mir)
+{ /* obtain current point */
+ int m = mir->m;
+ int n = mir->n;
+ int k;
+ for (k = 1; k <= m; k++)
+ mir->x[k] = mip->row[k]->prim;
+ for (k = m+1; k <= m+n; k++)
+ mir->x[k] = mip->col[k-m]->prim;
+ return;
+}
+
+#if MIR_DEBUG
+static void check_current_point(glp_mir *mir)
+{ /* check current point */
+ int m = mir->m;
+ int n = mir->n;
+ int k, kk;
+ double lb, ub, eps;
+ for (k = 1; k <= m+n; k++)
+ { /* determine lower bound */
+ lb = mir->lb[k];
+ kk = mir->vlb[k];
+ if (kk != 0)
+ { xassert(lb != -DBL_MAX);
+ xassert(!mir->isint[k]);
+ xassert(mir->isint[kk]);
+ lb *= mir->x[kk];
+ }
+ /* check lower bound */
+ if (lb != -DBL_MAX)
+ { eps = 1e-6 * (1.0 + fabs(lb));
+ xassert(mir->x[k] >= lb - eps);
+ }
+ /* determine upper bound */
+ ub = mir->ub[k];
+ kk = mir->vub[k];
+ if (kk != 0)
+ { xassert(ub != +DBL_MAX);
+ xassert(!mir->isint[k]);
+ xassert(mir->isint[kk]);
+ ub *= mir->x[kk];
+ }
+ /* check upper bound */
+ if (ub != +DBL_MAX)
+ { eps = 1e-6 * (1.0 + fabs(ub));
+ xassert(mir->x[k] <= ub + eps);
+ }
+ }
+ return;
+}
+#endif
+
+static void initial_agg_row(glp_prob *mip, glp_mir *mir, int i)
+{ /* use original i-th row as initial aggregated constraint */
+ int m = mir->m;
+ GLPAIJ *aij;
+ xassert(1 <= i && i <= m);
+ xassert(!mir->skip[i]);
+ /* mark i-th row in order not to use it in the same aggregated
+ constraint */
+ mir->skip[i] = 2;
+ mir->agg_cnt = 1;
+ mir->agg_row[1] = i;
+ /* use x[i] - sum a[i,j] * x[m+j] = 0, where x[i] is auxiliary
+ variable of row i, x[m+j] are structural variables */
+ spv_clear_vec(mir->agg_vec);
+ spv_set_vj(mir->agg_vec, i, 1.0);
+ for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
+ spv_set_vj(mir->agg_vec, m + aij->col->j, - aij->val);
+ mir->agg_rhs = 0.0;
+#if MIR_DEBUG
+ spv_check_vec(mir->agg_vec);
+#endif
+ return;
+}
+
+#if MIR_DEBUG
+static void check_agg_row(glp_mir *mir)
+{ /* check aggregated constraint */
+ int m = mir->m;
+ int n = mir->n;
+ int j, k;
+ double r, big;
+ /* compute the residual r = sum a[k] * x[k] - b and determine
+ big = max(1, |a[k]|, |b|) */
+ r = 0.0, big = 1.0;
+ for (j = 1; j <= mir->agg_vec->nnz; j++)
+ { k = mir->agg_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ r += mir->agg_vec->val[j] * mir->x[k];
+ if (big < fabs(mir->agg_vec->val[j]))
+ big = fabs(mir->agg_vec->val[j]);
+ }
+ r -= mir->agg_rhs;
+ if (big < fabs(mir->agg_rhs))
+ big = fabs(mir->agg_rhs);
+ /* the residual must be close to zero */
+ xassert(fabs(r) <= 1e-6 * big);
+ return;
+}
+#endif
+
+static void subst_fixed_vars(glp_mir *mir)
+{ /* substitute fixed variables into aggregated constraint */
+ int m = mir->m;
+ int n = mir->n;
+ int j, k;
+ for (j = 1; j <= mir->agg_vec->nnz; j++)
+ { k = mir->agg_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (mir->vlb[k] == 0 && mir->vub[k] == 0 &&
+ mir->lb[k] == mir->ub[k])
+ { /* x[k] is fixed */
+ mir->agg_rhs -= mir->agg_vec->val[j] * mir->lb[k];
+ mir->agg_vec->val[j] = 0.0;
+ }
+ }
+ /* remove terms corresponding to fixed variables */
+ spv_clean_vec(mir->agg_vec, DBL_EPSILON);
+#if MIR_DEBUG
+ spv_check_vec(mir->agg_vec);
+#endif
+ return;
+}
+
+static void bound_subst_heur(glp_mir *mir)
+{ /* bound substitution heuristic */
+ int m = mir->m;
+ int n = mir->n;
+ int j, k, kk;
+ double d1, d2;
+ for (j = 1; j <= mir->agg_vec->nnz; j++)
+ { k = mir->agg_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (mir->isint[k]) continue; /* skip integer variable */
+ /* compute distance from x[k] to its lower bound */
+ kk = mir->vlb[k];
+ if (kk == 0)
+ { if (mir->lb[k] == -DBL_MAX)
+ d1 = DBL_MAX;
+ else
+ d1 = mir->x[k] - mir->lb[k];
+ }
+ else
+ { xassert(1 <= kk && kk <= m+n);
+ xassert(mir->isint[kk]);
+ xassert(mir->lb[k] != -DBL_MAX);
+ d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
+ }
+ /* compute distance from x[k] to its upper bound */
+ kk = mir->vub[k];
+ if (kk == 0)
+ { if (mir->vub[k] == +DBL_MAX)
+ d2 = DBL_MAX;
+ else
+ d2 = mir->ub[k] - mir->x[k];
+ }
+ else
+ { xassert(1 <= kk && kk <= m+n);
+ xassert(mir->isint[kk]);
+ xassert(mir->ub[k] != +DBL_MAX);
+ d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
+ }
+ /* x[k] cannot be free */
+ xassert(d1 != DBL_MAX || d2 != DBL_MAX);
+ /* choose the bound which is closer to x[k] */
+ xassert(mir->subst[k] == '?');
+ if (d1 <= d2)
+ mir->subst[k] = 'L';
+ else
+ mir->subst[k] = 'U';
+ }
+ return;
+}
+
+static void build_mod_row(glp_mir *mir)
+{ /* substitute bounds and build modified constraint */
+ int m = mir->m;
+ int n = mir->n;
+ int j, jj, k, kk;
+ /* initially modified constraint is aggregated constraint */
+ spv_copy_vec(mir->mod_vec, mir->agg_vec);
+ mir->mod_rhs = mir->agg_rhs;
+#if MIR_DEBUG
+ spv_check_vec(mir->mod_vec);
+#endif
+ /* substitute bounds for continuous variables; note that due to
+ substitution of variable bounds additional terms may appear in
+ modified constraint */
+ for (j = mir->mod_vec->nnz; j >= 1; j--)
+ { k = mir->mod_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (mir->isint[k]) continue; /* skip integer variable */
+ if (mir->subst[k] == 'L')
+ { /* x[k] = (lower bound) + x'[k] */
+ xassert(mir->lb[k] != -DBL_MAX);
+ kk = mir->vlb[k];
+ if (kk == 0)
+ { /* x[k] = lb[k] + x'[k] */
+ mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
+ }
+ else
+ { /* x[k] = lb[k] * x[kk] + x'[k] */
+ xassert(mir->isint[kk]);
+ jj = mir->mod_vec->pos[kk];
+ if (jj == 0)
+ { spv_set_vj(mir->mod_vec, kk, 1.0);
+ jj = mir->mod_vec->pos[kk];
+ mir->mod_vec->val[jj] = 0.0;
+ }
+ mir->mod_vec->val[jj] +=
+ mir->mod_vec->val[j] * mir->lb[k];
+ }
+ }
+ else if (mir->subst[k] == 'U')
+ { /* x[k] = (upper bound) - x'[k] */
+ xassert(mir->ub[k] != +DBL_MAX);
+ kk = mir->vub[k];
+ if (kk == 0)
+ { /* x[k] = ub[k] - x'[k] */
+ mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
+ }
+ else
+ { /* x[k] = ub[k] * x[kk] - x'[k] */
+ xassert(mir->isint[kk]);
+ jj = mir->mod_vec->pos[kk];
+ if (jj == 0)
+ { spv_set_vj(mir->mod_vec, kk, 1.0);
+ jj = mir->mod_vec->pos[kk];
+ mir->mod_vec->val[jj] = 0.0;
+ }
+ mir->mod_vec->val[jj] +=
+ mir->mod_vec->val[j] * mir->ub[k];
+ }
+ mir->mod_vec->val[j] = - mir->mod_vec->val[j];
+ }
+ else
+ xassert(k != k);
+ }
+#if MIR_DEBUG
+ spv_check_vec(mir->mod_vec);
+#endif
+ /* substitute bounds for integer variables */
+ for (j = 1; j <= mir->mod_vec->nnz; j++)
+ { k = mir->mod_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (!mir->isint[k]) continue; /* skip continuous variable */
+ xassert(mir->subst[k] == '?');
+ xassert(mir->vlb[k] == 0 && mir->vub[k] == 0);
+ xassert(mir->lb[k] != -DBL_MAX && mir->ub[k] != +DBL_MAX);
+ if (fabs(mir->lb[k]) <= fabs(mir->ub[k]))
+ { /* x[k] = lb[k] + x'[k] */
+ mir->subst[k] = 'L';
+ mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
+ }
+ else
+ { /* x[k] = ub[k] - x'[k] */
+ mir->subst[k] = 'U';
+ mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
+ mir->mod_vec->val[j] = - mir->mod_vec->val[j];
+ }
+ }
+#if MIR_DEBUG
+ spv_check_vec(mir->mod_vec);
+#endif
+ return;
+}
+
+#if MIR_DEBUG
+static void check_mod_row(glp_mir *mir)
+{ /* check modified constraint */
+ int m = mir->m;
+ int n = mir->n;
+ int j, k, kk;
+ double r, big, x;
+ /* compute the residual r = sum a'[k] * x'[k] - b' and determine
+ big = max(1, |a[k]|, |b|) */
+ r = 0.0, big = 1.0;
+ for (j = 1; j <= mir->mod_vec->nnz; j++)
+ { k = mir->mod_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (mir->subst[k] == 'L')
+ { /* x'[k] = x[k] - (lower bound) */
+ xassert(mir->lb[k] != -DBL_MAX);
+ kk = mir->vlb[k];
+ if (kk == 0)
+ x = mir->x[k] - mir->lb[k];
+ else
+ x = mir->x[k] - mir->lb[k] * mir->x[kk];
+ }
+ else if (mir->subst[k] == 'U')
+ { /* x'[k] = (upper bound) - x[k] */
+ xassert(mir->ub[k] != +DBL_MAX);
+ kk = mir->vub[k];
+ if (kk == 0)
+ x = mir->ub[k] - mir->x[k];
+ else
+ x = mir->ub[k] * mir->x[kk] - mir->x[k];
+ }
+ else
+ xassert(k != k);
+ r += mir->mod_vec->val[j] * x;
+ if (big < fabs(mir->mod_vec->val[j]))
+ big = fabs(mir->mod_vec->val[j]);
+ }
+ r -= mir->mod_rhs;
+ if (big < fabs(mir->mod_rhs))
+ big = fabs(mir->mod_rhs);
+ /* the residual must be close to zero */
+ xassert(fabs(r) <= 1e-6 * big);
+ return;
+}
+#endif
+
+/***********************************************************************
+* mir_ineq - construct MIR inequality
+*
+* Given the single constraint mixed integer set
+*
+* |N|
+* X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s},
+* + + j in N
+*
+* this routine constructs the mixed integer rounding (MIR) inequality
+*
+* sum alpha[j] * x[j] <= beta + gamma * s,
+* j in N
+*
+* which is valid for X.
+*
+* If the MIR inequality has been successfully constructed, the routine
+* returns zero. Otherwise, if b is close to nearest integer, there may
+* be numeric difficulties due to big coefficients; so in this case the
+* routine returns non-zero. */
+
+static int mir_ineq(const int n, const double a[], const double b,
+ double alpha[], double *beta, double *gamma)
+{ int j;
+ double f, t;
+ if (fabs(b - floor(b + .5)) < 0.01)
+ return 1;
+ f = b - floor(b);
+ for (j = 1; j <= n; j++)
+ { t = (a[j] - floor(a[j])) - f;
+ if (t <= 0.0)
+ alpha[j] = floor(a[j]);
+ else
+ alpha[j] = floor(a[j]) + t / (1.0 - f);
+ }
+ *beta = floor(b);
+ *gamma = 1.0 / (1.0 - f);
+ return 0;
+}
+
+/***********************************************************************
+* cmir_ineq - construct c-MIR inequality
+*
+* Given the mixed knapsack set
+*
+* MK |N|
+* X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s,
+* + + j in N
+*
+* x[j] <= u[j]},
+*
+* a subset C of variables to be complemented, and a divisor delta > 0,
+* this routine constructs the complemented MIR (c-MIR) inequality
+*
+* sum alpha[j] * x[j] <= beta + gamma * s,
+* j in N
+* MK
+* which is valid for X .
+*
+* If the c-MIR inequality has been successfully constructed, the
+* routine returns zero. Otherwise, if there is a risk of numerical
+* difficulties due to big coefficients (see comments to the routine
+* mir_ineq), the routine cmir_ineq returns non-zero. */
+
+static int cmir_ineq(const int n, const double a[], const double b,
+ const double u[], const char cset[], const double delta,
+ double alpha[], double *beta, double *gamma)
+{ int j;
+ double *aa, bb;
+ aa = alpha, bb = b;
+ for (j = 1; j <= n; j++)
+ { aa[j] = a[j] / delta;
+ if (cset[j])
+ aa[j] = - aa[j], bb -= a[j] * u[j];
+ }
+ bb /= delta;
+ if (mir_ineq(n, aa, bb, alpha, beta, gamma)) return 1;
+ for (j = 1; j <= n; j++)
+ { if (cset[j])
+ alpha[j] = - alpha[j], *beta += alpha[j] * u[j];
+ }
+ *gamma /= delta;
+ return 0;
+}
+
+/***********************************************************************
+* cmir_sep - c-MIR separation heuristic
+*
+* Given the mixed knapsack set
+*
+* MK |N|
+* X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s,
+* + + j in N
+*
+* x[j] <= u[j]}
+*
+* * *
+* and a fractional point (x , s ), this routine tries to construct
+* c-MIR inequality
+*
+* sum alpha[j] * x[j] <= beta + gamma * s,
+* j in N
+* MK
+* which is valid for X and has (desirably maximal) violation at the
+* fractional point given. This is attained by choosing an appropriate
+* set C of variables to be complemented and a divisor delta > 0, which
+* together define corresponding c-MIR inequality.
+*
+* If a violated c-MIR inequality has been successfully constructed,
+* the routine returns its violation:
+*
+* * *
+* sum alpha[j] * x [j] - beta - gamma * s ,
+* j in N
+*
+* which is positive. In case of failure the routine returns zero. */
+
+struct vset { int j; double v; };
+
+static int CDECL cmir_cmp(const void *p1, const void *p2)
+{ const struct vset *v1 = p1, *v2 = p2;
+ if (v1->v < v2->v) return -1;
+ if (v1->v > v2->v) return +1;
+ return 0;
+}
+
+static double cmir_sep(const int n, const double a[], const double b,
+ const double u[], const double x[], const double s,
+ double alpha[], double *beta, double *gamma)
+{ int fail, j, k, nv, v;
+ double delta, eps, d_try[1+3], r, r_best;
+ char *cset;
+ struct vset *vset;
+ /* allocate working arrays */
+ cset = xcalloc(1+n, sizeof(char));
+ vset = xcalloc(1+n, sizeof(struct vset));
+ /* choose initial C */
+ for (j = 1; j <= n; j++)
+ cset[j] = (char)(x[j] >= 0.5 * u[j]);
+ /* choose initial delta */
+ r_best = delta = 0.0;
+ for (j = 1; j <= n; j++)
+ { xassert(a[j] != 0.0);
+ /* if x[j] is close to its bounds, skip it */
+ eps = 1e-9 * (1.0 + fabs(u[j]));
+ if (x[j] < eps || x[j] > u[j] - eps) continue;
+ /* try delta = |a[j]| to construct c-MIR inequality */
+ fail = cmir_ineq(n, a, b, u, cset, fabs(a[j]), alpha, beta,
+ gamma);
+ if (fail) continue;
+ /* compute violation */
+ r = - (*beta) - (*gamma) * s;
+ for (k = 1; k <= n; k++) r += alpha[k] * x[k];
+ if (r_best < r) r_best = r, delta = fabs(a[j]);
+ }
+ if (r_best < 0.001) r_best = 0.0;
+ if (r_best == 0.0) goto done;
+ xassert(delta > 0.0);
+ /* try to increase violation by dividing delta by 2, 4, and 8,
+ respectively */
+ d_try[1] = delta / 2.0;
+ d_try[2] = delta / 4.0;
+ d_try[3] = delta / 8.0;
+ for (j = 1; j <= 3; j++)
+ { /* construct c-MIR inequality */
+ fail = cmir_ineq(n, a, b, u, cset, d_try[j], alpha, beta,
+ gamma);
+ if (fail) continue;
+ /* compute violation */
+ r = - (*beta) - (*gamma) * s;
+ for (k = 1; k <= n; k++) r += alpha[k] * x[k];
+ if (r_best < r) r_best = r, delta = d_try[j];
+ }
+ /* build subset of variables lying strictly between their bounds
+ and order it by nondecreasing values of |x[j] - u[j]/2| */
+ nv = 0;
+ for (j = 1; j <= n; j++)
+ { /* if x[j] is close to its bounds, skip it */
+ eps = 1e-9 * (1.0 + fabs(u[j]));
+ if (x[j] < eps || x[j] > u[j] - eps) continue;
+ /* add x[j] to the subset */
+ nv++;
+ vset[nv].j = j;
+ vset[nv].v = fabs(x[j] - 0.5 * u[j]);
+ }
+ qsort(&vset[1], nv, sizeof(struct vset), cmir_cmp);
+ /* try to increase violation by successively complementing each
+ variable in the subset */
+ for (v = 1; v <= nv; v++)
+ { j = vset[v].j;
+ /* replace x[j] by its complement or vice versa */
+ cset[j] = (char)!cset[j];
+ /* construct c-MIR inequality */
+ fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
+ /* restore the variable */
+ cset[j] = (char)!cset[j];
+ /* do not replace the variable in case of failure */
+ if (fail) continue;
+ /* compute violation */
+ r = - (*beta) - (*gamma) * s;
+ for (k = 1; k <= n; k++) r += alpha[k] * x[k];
+ if (r_best < r) r_best = r, cset[j] = (char)!cset[j];
+ }
+ /* construct the best c-MIR inequality chosen */
+ fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
+ xassert(!fail);
+done: /* free working arrays */
+ xfree(cset);
+ xfree(vset);
+ /* return to the calling routine */
+ return r_best;
+}
+
+static double generate(glp_mir *mir)
+{ /* try to generate violated c-MIR cut for modified constraint */
+ int m = mir->m;
+ int n = mir->n;
+ int j, k, kk, nint;
+ double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma;
+ spv_copy_vec(mir->cut_vec, mir->mod_vec);
+ mir->cut_rhs = mir->mod_rhs;
+ /* remove small terms, which can appear due to substitution of
+ variable bounds */
+ spv_clean_vec(mir->cut_vec, DBL_EPSILON);
+#if MIR_DEBUG
+ spv_check_vec(mir->cut_vec);
+#endif
+ /* remove positive continuous terms to obtain MK relaxation */
+ for (j = 1; j <= mir->cut_vec->nnz; j++)
+ { k = mir->cut_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (!mir->isint[k] && mir->cut_vec->val[j] > 0.0)
+ mir->cut_vec->val[j] = 0.0;
+ }
+ spv_clean_vec(mir->cut_vec, 0.0);
+#if MIR_DEBUG
+ spv_check_vec(mir->cut_vec);
+#endif
+ /* move integer terms to the beginning of the sparse vector and
+ determine the number of integer variables */
+ nint = 0;
+ for (j = 1; j <= mir->cut_vec->nnz; j++)
+ { k = mir->cut_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (mir->isint[k])
+ { double temp;
+ nint++;
+ /* interchange elements [nint] and [j] */
+ kk = mir->cut_vec->ind[nint];
+ mir->cut_vec->pos[k] = nint;
+ mir->cut_vec->pos[kk] = j;
+ mir->cut_vec->ind[nint] = k;
+ mir->cut_vec->ind[j] = kk;
+ temp = mir->cut_vec->val[nint];
+ mir->cut_vec->val[nint] = mir->cut_vec->val[j];
+ mir->cut_vec->val[j] = temp;
+ }
+ }
+#if MIR_DEBUG
+ spv_check_vec(mir->cut_vec);
+#endif
+ /* if there is no integer variable, nothing to generate */
+ if (nint == 0) goto done;
+ /* allocate working arrays */
+ u = xcalloc(1+nint, sizeof(double));
+ x = xcalloc(1+nint, sizeof(double));
+ alpha = xcalloc(1+nint, sizeof(double));
+ /* determine u and x */
+ for (j = 1; j <= nint; j++)
+ { k = mir->cut_vec->ind[j];
+ xassert(m+1 <= k && k <= m+n);
+ xassert(mir->isint[k]);
+ u[j] = mir->ub[k] - mir->lb[k];
+ xassert(u[j] >= 1.0);
+ if (mir->subst[k] == 'L')
+ x[j] = mir->x[k] - mir->lb[k];
+ else if (mir->subst[k] == 'U')
+ x[j] = mir->ub[k] - mir->x[k];
+ else
+ xassert(k != k);
+#if 0 /* 06/III-2016; notorious bug reported many times */
+ xassert(x[j] >= -0.001);
+#else
+ if (x[j] < -0.001)
+ { xprintf("glp_mir_gen: warning: x[%d] = %g\n", j, x[j]);
+ r_best = 0.0;
+ goto skip;
+ }
+#endif
+ if (x[j] < 0.0) x[j] = 0.0;
+ }
+ /* compute s = - sum of continuous terms */
+ s = 0.0;
+ for (j = nint+1; j <= mir->cut_vec->nnz; j++)
+ { double x;
+ k = mir->cut_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ /* must be continuous */
+ xassert(!mir->isint[k]);
+ if (mir->subst[k] == 'L')
+ { xassert(mir->lb[k] != -DBL_MAX);
+ kk = mir->vlb[k];
+ if (kk == 0)
+ x = mir->x[k] - mir->lb[k];
+ else
+ x = mir->x[k] - mir->lb[k] * mir->x[kk];
+ }
+ else if (mir->subst[k] == 'U')
+ { xassert(mir->ub[k] != +DBL_MAX);
+ kk = mir->vub[k];
+ if (kk == 0)
+ x = mir->ub[k] - mir->x[k];
+ else
+ x = mir->ub[k] * mir->x[kk] - mir->x[k];
+ }
+ else
+ xassert(k != k);
+#if 0 /* 06/III-2016; notorious bug reported many times */
+ xassert(x >= -0.001);
+#else
+ if (x < -0.001)
+ { xprintf("glp_mir_gen: warning: x = %g\n", x);
+ r_best = 0.0;
+ goto skip;
+ }
+#endif
+ if (x < 0.0) x = 0.0;
+ s -= mir->cut_vec->val[j] * x;
+ }
+ xassert(s >= 0.0);
+ /* apply heuristic to obtain most violated c-MIR inequality */
+ b = mir->cut_rhs;
+ r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha,
+ &beta, &gamma);
+ if (r_best == 0.0) goto skip;
+ xassert(r_best > 0.0);
+ /* convert to raw cut */
+ /* sum alpha[j] * x[j] <= beta + gamma * s */
+ for (j = 1; j <= nint; j++)
+ mir->cut_vec->val[j] = alpha[j];
+ for (j = nint+1; j <= mir->cut_vec->nnz; j++)
+ { k = mir->cut_vec->ind[j];
+ if (k <= m+n) mir->cut_vec->val[j] *= gamma;
+ }
+ mir->cut_rhs = beta;
+#if MIR_DEBUG
+ spv_check_vec(mir->cut_vec);
+#endif
+skip: /* free working arrays */
+ xfree(u);
+ xfree(x);
+ xfree(alpha);
+done: return r_best;
+}
+
+#if MIR_DEBUG
+static void check_raw_cut(glp_mir *mir, double r_best)
+{ /* check raw cut before back bound substitution */
+ int m = mir->m;
+ int n = mir->n;
+ int j, k, kk;
+ double r, big, x;
+ /* compute the residual r = sum a[k] * x[k] - b and determine
+ big = max(1, |a[k]|, |b|) */
+ r = 0.0, big = 1.0;
+ for (j = 1; j <= mir->cut_vec->nnz; j++)
+ { k = mir->cut_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (mir->subst[k] == 'L')
+ { xassert(mir->lb[k] != -DBL_MAX);
+ kk = mir->vlb[k];
+ if (kk == 0)
+ x = mir->x[k] - mir->lb[k];
+ else
+ x = mir->x[k] - mir->lb[k] * mir->x[kk];
+ }
+ else if (mir->subst[k] == 'U')
+ { xassert(mir->ub[k] != +DBL_MAX);
+ kk = mir->vub[k];
+ if (kk == 0)
+ x = mir->ub[k] - mir->x[k];
+ else
+ x = mir->ub[k] * mir->x[kk] - mir->x[k];
+ }
+ else
+ xassert(k != k);
+ r += mir->cut_vec->val[j] * x;
+ if (big < fabs(mir->cut_vec->val[j]))
+ big = fabs(mir->cut_vec->val[j]);
+ }
+ r -= mir->cut_rhs;
+ if (big < fabs(mir->cut_rhs))
+ big = fabs(mir->cut_rhs);
+ /* the residual must be close to r_best */
+ xassert(fabs(r - r_best) <= 1e-6 * big);
+ return;
+}
+#endif
+
+static void back_subst(glp_mir *mir)
+{ /* back substitution of original bounds */
+ int m = mir->m;
+ int n = mir->n;
+ int j, jj, k, kk;
+ /* at first, restore bounds of integer variables (because on
+ restoring variable bounds of continuous variables we need
+ original, not shifted, bounds of integer variables) */
+ for (j = 1; j <= mir->cut_vec->nnz; j++)
+ { k = mir->cut_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (!mir->isint[k]) continue; /* skip continuous */
+ if (mir->subst[k] == 'L')
+ { /* x'[k] = x[k] - lb[k] */
+ xassert(mir->lb[k] != -DBL_MAX);
+ xassert(mir->vlb[k] == 0);
+ mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
+ }
+ else if (mir->subst[k] == 'U')
+ { /* x'[k] = ub[k] - x[k] */
+ xassert(mir->ub[k] != +DBL_MAX);
+ xassert(mir->vub[k] == 0);
+ mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
+ mir->cut_vec->val[j] = - mir->cut_vec->val[j];
+ }
+ else
+ xassert(k != k);
+ }
+ /* now restore bounds of continuous variables */
+ for (j = 1; j <= mir->cut_vec->nnz; j++)
+ { k = mir->cut_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (mir->isint[k]) continue; /* skip integer */
+ if (mir->subst[k] == 'L')
+ { /* x'[k] = x[k] - (lower bound) */
+ xassert(mir->lb[k] != -DBL_MAX);
+ kk = mir->vlb[k];
+ if (kk == 0)
+ { /* x'[k] = x[k] - lb[k] */
+ mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
+ }
+ else
+ { /* x'[k] = x[k] - lb[k] * x[kk] */
+ jj = mir->cut_vec->pos[kk];
+#if 0
+ xassert(jj != 0);
+#else
+ if (jj == 0)
+ { spv_set_vj(mir->cut_vec, kk, 1.0);
+ jj = mir->cut_vec->pos[kk];
+ xassert(jj != 0);
+ mir->cut_vec->val[jj] = 0.0;
+ }
+#endif
+ mir->cut_vec->val[jj] -= mir->cut_vec->val[j] *
+ mir->lb[k];
+ }
+ }
+ else if (mir->subst[k] == 'U')
+ { /* x'[k] = (upper bound) - x[k] */
+ xassert(mir->ub[k] != +DBL_MAX);
+ kk = mir->vub[k];
+ if (kk == 0)
+ { /* x'[k] = ub[k] - x[k] */
+ mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
+ }
+ else
+ { /* x'[k] = ub[k] * x[kk] - x[k] */
+ jj = mir->cut_vec->pos[kk];
+ if (jj == 0)
+ { spv_set_vj(mir->cut_vec, kk, 1.0);
+ jj = mir->cut_vec->pos[kk];
+ xassert(jj != 0);
+ mir->cut_vec->val[jj] = 0.0;
+ }
+ mir->cut_vec->val[jj] += mir->cut_vec->val[j] *
+ mir->ub[k];
+ }
+ mir->cut_vec->val[j] = - mir->cut_vec->val[j];
+ }
+ else
+ xassert(k != k);
+ }
+#if MIR_DEBUG
+ spv_check_vec(mir->cut_vec);
+#endif
+ return;
+}
+
+#if MIR_DEBUG
+static void check_cut_row(glp_mir *mir, double r_best)
+{ /* check the cut after back bound substitution or elimination of
+ auxiliary variables */
+ int m = mir->m;
+ int n = mir->n;
+ int j, k;
+ double r, big;
+ /* compute the residual r = sum a[k] * x[k] - b and determine
+ big = max(1, |a[k]|, |b|) */
+ r = 0.0, big = 1.0;
+ for (j = 1; j <= mir->cut_vec->nnz; j++)
+ { k = mir->cut_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ r += mir->cut_vec->val[j] * mir->x[k];
+ if (big < fabs(mir->cut_vec->val[j]))
+ big = fabs(mir->cut_vec->val[j]);
+ }
+ r -= mir->cut_rhs;
+ if (big < fabs(mir->cut_rhs))
+ big = fabs(mir->cut_rhs);
+ /* the residual must be close to r_best */
+ xassert(fabs(r - r_best) <= 1e-6 * big);
+ return;
+}
+#endif
+
+static void subst_aux_vars(glp_prob *mip, glp_mir *mir)
+{ /* final substitution to eliminate auxiliary variables */
+ int m = mir->m;
+ int n = mir->n;
+ GLPAIJ *aij;
+ int j, k, kk, jj;
+ for (j = mir->cut_vec->nnz; j >= 1; j--)
+ { k = mir->cut_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (k > m) continue; /* skip structurals */
+ for (aij = mip->row[k]->ptr; aij != NULL; aij = aij->r_next)
+ { kk = m + aij->col->j; /* structural */
+ jj = mir->cut_vec->pos[kk];
+ if (jj == 0)
+ { spv_set_vj(mir->cut_vec, kk, 1.0);
+ jj = mir->cut_vec->pos[kk];
+ mir->cut_vec->val[jj] = 0.0;
+ }
+ mir->cut_vec->val[jj] += mir->cut_vec->val[j] * aij->val;
+ }
+ mir->cut_vec->val[j] = 0.0;
+ }
+ spv_clean_vec(mir->cut_vec, 0.0);
+ return;
+}
+
+static void add_cut(glp_mir *mir, glp_prob *pool)
+{ /* add constructed cut inequality to the cut pool */
+ int m = mir->m;
+ int n = mir->n;
+ int j, k, len;
+ int *ind = xcalloc(1+n, sizeof(int));
+ double *val = xcalloc(1+n, sizeof(double));
+ len = 0;
+ for (j = mir->cut_vec->nnz; j >= 1; j--)
+ { k = mir->cut_vec->ind[j];
+ xassert(m+1 <= k && k <= m+n);
+ len++, ind[len] = k - m, val[len] = mir->cut_vec->val[j];
+ }
+#if 0
+#if 0
+ ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP,
+ mir->cut_rhs);
+#else
+ glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP,
+ mir->cut_rhs);
+#endif
+#else
+ { int i;
+ i = glp_add_rows(pool, 1);
+ glp_set_row_bnds(pool, i, GLP_UP, 0, mir->cut_rhs);
+ glp_set_mat_row(pool, i, len, ind, val);
+ }
+#endif
+ xfree(ind);
+ xfree(val);
+ return;
+}
+
+#if 0 /* 29/II-2016 by Chris */
+static int aggregate_row(glp_prob *mip, glp_mir *mir)
+#else
+static int aggregate_row(glp_prob *mip, glp_mir *mir, SPV *v)
+#endif
+{ /* try to aggregate another row */
+ int m = mir->m;
+ int n = mir->n;
+ GLPAIJ *aij;
+#if 0 /* 29/II-2016 by Chris */
+ SPV *v;
+#endif
+ int ii, j, jj, k, kk, kappa = 0, ret = 0;
+ double d1, d2, d, d_max = 0.0;
+ /* choose appropriate structural variable in the aggregated row
+ to be substituted */
+ for (j = 1; j <= mir->agg_vec->nnz; j++)
+ { k = mir->agg_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ if (k <= m) continue; /* skip auxiliary var */
+ if (mir->isint[k]) continue; /* skip integer var */
+ if (fabs(mir->agg_vec->val[j]) < 0.001) continue;
+ /* compute distance from x[k] to its lower bound */
+ kk = mir->vlb[k];
+ if (kk == 0)
+ { if (mir->lb[k] == -DBL_MAX)
+ d1 = DBL_MAX;
+ else
+ d1 = mir->x[k] - mir->lb[k];
+ }
+ else
+ { xassert(1 <= kk && kk <= m+n);
+ xassert(mir->isint[kk]);
+ xassert(mir->lb[k] != -DBL_MAX);
+ d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
+ }
+ /* compute distance from x[k] to its upper bound */
+ kk = mir->vub[k];
+ if (kk == 0)
+ { if (mir->vub[k] == +DBL_MAX)
+ d2 = DBL_MAX;
+ else
+ d2 = mir->ub[k] - mir->x[k];
+ }
+ else
+ { xassert(1 <= kk && kk <= m+n);
+ xassert(mir->isint[kk]);
+ xassert(mir->ub[k] != +DBL_MAX);
+ d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
+ }
+ /* x[k] cannot be free */
+ xassert(d1 != DBL_MAX || d2 != DBL_MAX);
+ /* d = min(d1, d2) */
+ d = (d1 <= d2 ? d1 : d2);
+ xassert(d != DBL_MAX);
+ /* should not be close to corresponding bound */
+ if (d < 0.001) continue;
+ if (d_max < d) d_max = d, kappa = k;
+ }
+ if (kappa == 0)
+ { /* nothing chosen */
+ ret = 1;
+ goto done;
+ }
+ /* x[kappa] has been chosen */
+ xassert(m+1 <= kappa && kappa <= m+n);
+ xassert(!mir->isint[kappa]);
+ /* find another row, which have not been used yet, to eliminate
+ x[kappa] from the aggregated row */
+#if 0 /* 29/II-2016 by Chris */
+ for (ii = 1; ii <= m; ii++)
+ { if (mir->skip[ii]) continue;
+ for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
+ if (aij->col->j == kappa - m) break;
+ if (aij != NULL && fabs(aij->val) >= 0.001) break;
+#else
+ ii = 0;
+ for (aij = mip->col[kappa - m]->ptr; aij != NULL;
+ aij = aij->c_next)
+ { if (aij->row->i > m) continue;
+ if (mir->skip[aij->row->i]) continue;
+ if (fabs(aij->val) >= 0.001)
+ { ii = aij->row->i;
+ break;
+ }
+#endif
+ }
+#if 0 /* 29/II-2016 by Chris */
+ if (ii > m)
+#else
+ if (ii == 0)
+#endif
+ { /* nothing found */
+ ret = 2;
+ goto done;
+ }
+ /* row ii has been found; include it in the aggregated list */
+ mir->agg_cnt++;
+ xassert(mir->agg_cnt <= MAXAGGR);
+ mir->agg_row[mir->agg_cnt] = ii;
+ mir->skip[ii] = 2;
+ /* v := new row */
+#if 0 /* 29/II-2016 by Chris */
+ v = ios_create_vec(m+n);
+#else
+ spv_clear_vec(v);
+#endif
+ spv_set_vj(v, ii, 1.0);
+ for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
+ spv_set_vj(v, m + aij->col->j, - aij->val);
+#if MIR_DEBUG
+ spv_check_vec(v);
+#endif
+ /* perform gaussian elimination to remove x[kappa] */
+ j = mir->agg_vec->pos[kappa];
+ xassert(j != 0);
+ jj = v->pos[kappa];
+ xassert(jj != 0);
+ spv_linear_comb(mir->agg_vec,
+ - mir->agg_vec->val[j] / v->val[jj], v);
+#if 0 /* 29/II-2016 by Chris */
+ ios_delete_vec(v);
+#endif
+ spv_set_vj(mir->agg_vec, kappa, 0.0);
+#if MIR_DEBUG
+ spv_check_vec(mir->agg_vec);
+#endif
+done: return ret;
+}
+
+int glp_mir_gen(glp_prob *mip, glp_mir *mir, glp_prob *pool)
+{ /* main routine to generate MIR cuts */
+ int m = mir->m;
+ int n = mir->n;
+ int i, nnn = 0;
+ double r_best;
+#if 1 /* 29/II-2016 by Chris */
+ SPV *work;
+#endif
+ xassert(mip->m >= m);
+ xassert(mip->n == n);
+ /* obtain current point */
+ get_current_point(mip, mir);
+#if MIR_DEBUG
+ /* check current point */
+ check_current_point(mir);
+#endif
+ /* reset bound substitution flags */
+ memset(&mir->subst[1], '?', m+n);
+#if 1 /* 29/II-2016 by Chris */
+ work = spv_create_vec(m+n);
+#endif
+ /* try to generate a set of violated MIR cuts */
+ for (i = 1; i <= m; i++)
+ { if (mir->skip[i]) continue;
+ /* use original i-th row as initial aggregated constraint */
+ initial_agg_row(mip, mir, i);
+loop: ;
+#if MIR_DEBUG
+ /* check aggregated row */
+ check_agg_row(mir);
+#endif
+ /* substitute fixed variables into aggregated constraint */
+ subst_fixed_vars(mir);
+#if MIR_DEBUG
+ /* check aggregated row */
+ check_agg_row(mir);
+#endif
+#if MIR_DEBUG
+ /* check bound substitution flags */
+ { int k;
+ for (k = 1; k <= m+n; k++)
+ xassert(mir->subst[k] == '?');
+ }
+#endif
+ /* apply bound substitution heuristic */
+ bound_subst_heur(mir);
+ /* substitute bounds and build modified constraint */
+ build_mod_row(mir);
+#if MIR_DEBUG
+ /* check modified row */
+ check_mod_row(mir);
+#endif
+ /* try to generate violated c-MIR cut for modified row */
+ r_best = generate(mir);
+ if (r_best > 0.0)
+ { /* success */
+#if MIR_DEBUG
+ /* check raw cut before back bound substitution */
+ check_raw_cut(mir, r_best);
+#endif
+ /* back substitution of original bounds */
+ back_subst(mir);
+#if MIR_DEBUG
+ /* check the cut after back bound substitution */
+ check_cut_row(mir, r_best);
+#endif
+ /* final substitution to eliminate auxiliary variables */
+ subst_aux_vars(mip, mir);
+#if MIR_DEBUG
+ /* check the cut after elimination of auxiliaries */
+ check_cut_row(mir, r_best);
+#endif
+ /* add constructed cut inequality to the cut pool */
+ add_cut(mir, pool), nnn++;
+ }
+ /* reset bound substitution flags */
+ { int j, k;
+ for (j = 1; j <= mir->mod_vec->nnz; j++)
+ { k = mir->mod_vec->ind[j];
+ xassert(1 <= k && k <= m+n);
+ xassert(mir->subst[k] != '?');
+ mir->subst[k] = '?';
+ }
+ }
+ if (r_best == 0.0)
+ { /* failure */
+ if (mir->agg_cnt < MAXAGGR)
+ { /* try to aggregate another row */
+#if 0 /* 29/II-2016 by Chris */
+ if (aggregate_row(mip, mir) == 0) goto loop;
+#else
+ if (aggregate_row(mip, mir, work) == 0) goto loop;
+#endif
+ }
+ }
+ /* unmark rows used in the aggregated constraint */
+ { int k, ii;
+ for (k = 1; k <= mir->agg_cnt; k++)
+ { ii = mir->agg_row[k];
+ xassert(1 <= ii && ii <= m);
+ xassert(mir->skip[ii] == 2);
+ mir->skip[ii] = 0;
+ }
+ }
+ }
+#if 1 /* 29/II-2016 by Chris */
+ spv_delete_vec(work);
+#endif
+ return nnn;
+}
+
+/***********************************************************************
+* NAME
+*
+* glp_mir_free - delete MIR cut generator workspace
+*
+* SYNOPSIS
+*
+* void glp_mir_free(glp_mir *mir);
+*
+* DESCRIPTION
+*
+* This routine deletes the MIR cut generator workspace and frees all
+* the memory allocated to it. */
+
+void glp_mir_free(glp_mir *mir)
+{ xfree(mir->skip);
+ xfree(mir->isint);
+ xfree(mir->lb);
+ xfree(mir->vlb);
+ xfree(mir->ub);
+ xfree(mir->vub);
+ xfree(mir->x);
+ xfree(mir->agg_row);
+ spv_delete_vec(mir->agg_vec);
+ xfree(mir->subst);
+ spv_delete_vec(mir->mod_vec);
+ spv_delete_vec(mir->cut_vec);
+ xfree(mir);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/spv.c b/test/monniaux/glpk-4.65/src/intopt/spv.c
new file mode 100644
index 00000000..502f3cd0
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/spv.c
@@ -0,0 +1,303 @@
+/* spv.c (operations on sparse vectors) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2007-2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "spv.h"
+
+/***********************************************************************
+* NAME
+*
+* spv_create_vec - create sparse vector
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* SPV *spv_create_vec(int n);
+*
+* DESCRIPTION
+*
+* The routine spv_create_vec creates a sparse vector of dimension n,
+* which initially is a null vector.
+*
+* RETURNS
+*
+* The routine returns a pointer to the vector created. */
+
+SPV *spv_create_vec(int n)
+{ SPV *v;
+ xassert(n >= 0);
+ v = xmalloc(sizeof(SPV));
+ v->n = n;
+ v->nnz = 0;
+ v->pos = xcalloc(1+n, sizeof(int));
+ memset(&v->pos[1], 0, n * sizeof(int));
+ v->ind = xcalloc(1+n, sizeof(int));
+ v->val = xcalloc(1+n, sizeof(double));
+ return v;
+}
+
+/***********************************************************************
+* NAME
+*
+* spv_check_vec - check that sparse vector has correct representation
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void spv_check_vec(SPV *v);
+*
+* DESCRIPTION
+*
+* The routine spv_check_vec checks that a sparse vector specified by
+* the parameter v has correct representation.
+*
+* NOTE
+*
+* Complexity of this operation is O(n). */
+
+void spv_check_vec(SPV *v)
+{ int j, k, nnz;
+ xassert(v->n >= 0);
+ nnz = 0;
+ for (j = v->n; j >= 1; j--)
+ { k = v->pos[j];
+ xassert(0 <= k && k <= v->nnz);
+ if (k != 0)
+ { xassert(v->ind[k] == j);
+ nnz++;
+ }
+ }
+ xassert(v->nnz == nnz);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* spv_get_vj - retrieve component of sparse vector
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* double spv_get_vj(SPV *v, int j);
+*
+* RETURNS
+*
+* The routine spv_get_vj returns j-th component of a sparse vector
+* specified by the parameter v. */
+
+double spv_get_vj(SPV *v, int j)
+{ int k;
+ xassert(1 <= j && j <= v->n);
+ k = v->pos[j];
+ xassert(0 <= k && k <= v->nnz);
+ return (k == 0 ? 0.0 : v->val[k]);
+}
+
+/***********************************************************************
+* NAME
+*
+* spv_set_vj - set/change component of sparse vector
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void spv_set_vj(SPV *v, int j, double val);
+*
+* DESCRIPTION
+*
+* The routine spv_set_vj assigns val to j-th component of a sparse
+* vector specified by the parameter v. */
+
+void spv_set_vj(SPV *v, int j, double val)
+{ int k;
+ xassert(1 <= j && j <= v->n);
+ k = v->pos[j];
+ if (val == 0.0)
+ { if (k != 0)
+ { /* remove j-th component */
+ v->pos[j] = 0;
+ if (k < v->nnz)
+ { v->pos[v->ind[v->nnz]] = k;
+ v->ind[k] = v->ind[v->nnz];
+ v->val[k] = v->val[v->nnz];
+ }
+ v->nnz--;
+ }
+ }
+ else
+ { if (k == 0)
+ { /* create j-th component */
+ k = ++(v->nnz);
+ v->pos[j] = k;
+ v->ind[k] = j;
+ }
+ v->val[k] = val;
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* spv_clear_vec - set all components of sparse vector to zero
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void spv_clear_vec(SPV *v);
+*
+* DESCRIPTION
+*
+* The routine spv_clear_vec sets all components of a sparse vector
+* specified by the parameter v to zero. */
+
+void spv_clear_vec(SPV *v)
+{ int k;
+ for (k = 1; k <= v->nnz; k++)
+ v->pos[v->ind[k]] = 0;
+ v->nnz = 0;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* spv_clean_vec - remove zero or small components from sparse vector
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void spv_clean_vec(SPV *v, double eps);
+*
+* DESCRIPTION
+*
+* The routine spv_clean_vec removes zero components and components
+* whose magnitude is less than eps from a sparse vector specified by
+* the parameter v. If eps is 0.0, only zero components are removed. */
+
+void spv_clean_vec(SPV *v, double eps)
+{ int k, nnz;
+ nnz = 0;
+ for (k = 1; k <= v->nnz; k++)
+ { if (fabs(v->val[k]) == 0.0 || fabs(v->val[k]) < eps)
+ { /* remove component */
+ v->pos[v->ind[k]] = 0;
+ }
+ else
+ { /* keep component */
+ nnz++;
+ v->pos[v->ind[k]] = nnz;
+ v->ind[nnz] = v->ind[k];
+ v->val[nnz] = v->val[k];
+ }
+ }
+ v->nnz = nnz;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* spv_copy_vec - copy sparse vector (x := y)
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void spv_copy_vec(SPV *x, SPV *y);
+*
+* DESCRIPTION
+*
+* The routine spv_copy_vec copies a sparse vector specified by the
+* parameter y to a sparse vector specified by the parameter x. */
+
+void spv_copy_vec(SPV *x, SPV *y)
+{ int j;
+ xassert(x != y);
+ xassert(x->n == y->n);
+ spv_clear_vec(x);
+ x->nnz = y->nnz;
+ memcpy(&x->ind[1], &y->ind[1], x->nnz * sizeof(int));
+ memcpy(&x->val[1], &y->val[1], x->nnz * sizeof(double));
+ for (j = 1; j <= x->nnz; j++)
+ x->pos[x->ind[j]] = j;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* spv_linear_comb - compute linear combination (x := x + a * y)
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void spv_linear_comb(SPV *x, double a, SPV *y);
+*
+* DESCRIPTION
+*
+* The routine spv_linear_comb computes the linear combination
+*
+* x := x + a * y,
+*
+* where x and y are sparse vectors, a is a scalar. */
+
+void spv_linear_comb(SPV *x, double a, SPV *y)
+{ int j, k;
+ double xj, yj;
+ xassert(x != y);
+ xassert(x->n == y->n);
+ for (k = 1; k <= y->nnz; k++)
+ { j = y->ind[k];
+ xj = spv_get_vj(x, j);
+ yj = y->val[k];
+ spv_set_vj(x, j, xj + a * yj);
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* spv_delete_vec - delete sparse vector
+*
+* SYNOPSIS
+*
+* #include "glpios.h"
+* void spv_delete_vec(SPV *v);
+*
+* DESCRIPTION
+*
+* The routine spv_delete_vec deletes a sparse vector specified by the
+* parameter v freeing all the memory allocated to this object. */
+
+void spv_delete_vec(SPV *v)
+{ /* delete sparse vector */
+ xfree(v->pos);
+ xfree(v->ind);
+ xfree(v->val);
+ xfree(v);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/intopt/spv.h b/test/monniaux/glpk-4.65/src/intopt/spv.h
new file mode 100644
index 00000000..d7d4699f
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/intopt/spv.h
@@ -0,0 +1,83 @@
+/* spv.h (operations on sparse vectors) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2007-2017 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/>.
+***********************************************************************/
+
+#ifndef SPV_H
+#define SPV_H
+
+typedef struct SPV SPV;
+
+struct SPV
+{ /* sparse vector v = (v[j]) */
+ int n;
+ /* dimension, n >= 0 */
+ int nnz;
+ /* number of non-zero components, 0 <= nnz <= n */
+ int *pos; /* int pos[1+n]; */
+ /* pos[j] = k, 1 <= j <= n, is position of (non-zero) v[j] in the
+ * arrays ind and val, where 1 <= k <= nnz; pos[j] = 0 means that
+ * v[j] is structural zero */
+ int *ind; /* int ind[1+n]; */
+ /* ind[k] = j, 1 <= k <= nnz, is index of v[j] */
+ double *val; /* double val[1+n]; */
+ /* val[k], 1 <= k <= nnz, is a numeric value of v[j] */
+};
+
+#define spv_create_vec _glp_spv_create_vec
+SPV *spv_create_vec(int n);
+/* create sparse vector */
+
+#define spv_check_vec _glp_spv_check_vec
+void spv_check_vec(SPV *v);
+/* check that sparse vector has correct representation */
+
+#define spv_get_vj _glp_spv_get_vj
+double spv_get_vj(SPV *v, int j);
+/* retrieve component of sparse vector */
+
+#define spv_set_vj _glp_spv_set_vj
+void spv_set_vj(SPV *v, int j, double val);
+/* set/change component of sparse vector */
+
+#define spv_clear_vec _glp_spv_clear_vec
+void spv_clear_vec(SPV *v);
+/* set all components of sparse vector to zero */
+
+#define spv_clean_vec _glp_spv_clean_vec
+void spv_clean_vec(SPV *v, double eps);
+/* remove zero or small components from sparse vector */
+
+#define spv_copy_vec _glp_spv_copy_vec
+void spv_copy_vec(SPV *x, SPV *y);
+/* copy sparse vector (x := y) */
+
+#define spv_linear_comb _glp_spv_linear_comb
+void spv_linear_comb(SPV *x, double a, SPV *y);
+/* compute linear combination (x := x + a * y) */
+
+#define spv_delete_vec _glp_spv_delete_vec
+void spv_delete_vec(SPV *v);
+/* delete sparse vector */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/minisat/LICENSE b/test/monniaux/glpk-4.65/src/minisat/LICENSE
new file mode 100644
index 00000000..8a6b9f36
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/minisat/LICENSE
@@ -0,0 +1,20 @@
+MiniSat -- Copyright (c) 2005, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/test/monniaux/glpk-4.65/src/minisat/README b/test/monniaux/glpk-4.65/src/minisat/README
new file mode 100644
index 00000000..c183c7d6
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/minisat/README
@@ -0,0 +1,22 @@
+NOTE: Files in this subdirectory are NOT part of the GLPK package, but
+ are used with GLPK.
+
+ The original code was modified according to GLPK requirements by
+ Andrew Makhorin <mao@gnu.org>.
+************************************************************************
+MiniSat-C v1.14.1
+========================================
+
+* Fixed some serious bugs.
+* Tweaked to be Visual Studio friendly (by Alan Mishchenko).
+ This disabled reading of gzipped DIMACS files and signal handling,
+ but none of these features are essential (and easy to re-enable, if
+ wanted).
+
+MiniSat-C v1.14
+========================================
+
+Ok, we get it. You hate C++. You hate templates. We agree; C++ is a
+seriously messed up language. Although we are more pragmatic about the
+quirks and maldesigns in C++, we sympathize with you. So here is a
+pure C version of MiniSat, put together by Niklas Sorensson.
diff --git a/test/monniaux/glpk-4.65/src/minisat/minisat.c b/test/monniaux/glpk-4.65/src/minisat/minisat.c
new file mode 100644
index 00000000..2432d650
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/minisat/minisat.c
@@ -0,0 +1,1315 @@
+/* minisat.c */
+
+/* Modified by Andrew Makhorin <mao@gnu.org>, August 2011 */
+/* May 2017: Changes were made to provide 64-bit portability; thanks to
+ * Chris Matrakidis <cmatraki@gmail.com> for patch */
+
+/***********************************************************************
+* MiniSat -- Copyright (c) 2005, Niklas Sorensson
+* http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation files
+* (the "Software"), to deal in the Software without restriction,
+* including without limitation the rights to use, copy, modify, merge,
+* publish, distribute, sublicense, and/or sell copies of the Software,
+* and to permit persons to whom the Software is furnished to do so,
+* subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+***********************************************************************/
+/* Modified to compile with MS Visual Studio 6.0 by Alan Mishchenko */
+
+#include "env.h"
+#include "minisat.h"
+
+#if 1 /* by mao */
+static void *ymalloc(int size)
+{ void *ptr;
+ xassert(size > 0);
+ ptr = malloc(size);
+ if (ptr == NULL)
+ xerror("MiniSat: no memory available\n");
+ return ptr;
+}
+
+static void *yrealloc(void *ptr, int size)
+{ xassert(size > 0);
+ if (ptr == NULL)
+ ptr = malloc(size);
+ else
+ ptr = realloc(ptr, size);
+ if (ptr == NULL)
+ xerror("MiniSat: no memory available\n");
+ return ptr;
+}
+
+static void yfree(void *ptr)
+{ xassert(ptr != NULL);
+ free(ptr);
+ return;
+}
+
+#define assert xassert
+#define printf xprintf
+#define fflush(f) /* nop */
+#define malloc ymalloc
+#define realloc yrealloc
+#define free yfree
+#define inline /* empty */
+#endif
+
+/*====================================================================*/
+/* Debug: */
+
+#if 0
+#define VERBOSEDEBUG 1
+#endif
+
+/* For derivation output (verbosity level 2) */
+#define L_IND "%-*d"
+#define L_ind solver_dlevel(s)*3+3,solver_dlevel(s)
+#define L_LIT "%sx%d"
+#define L_lit(p) lit_sign(p)?"~":"", (lit_var(p))
+
+#if 0 /* by mao */
+/* Just like 'assert()' but expression will be evaluated in the release
+ version as well. */
+static inline void check(int expr) { assert(expr); }
+#endif
+
+#if 0 /* by mao */
+static void printlits(lit* begin, lit* end)
+{
+ int i;
+ for (i = 0; i < end - begin; i++)
+ printf(L_LIT" ",L_lit(begin[i]));
+}
+#endif
+
+/*====================================================================*/
+/* Random numbers: */
+
+/* Returns a random float 0 <= x < 1. Seed must never be 0. */
+static inline double drand(double* seed) {
+ int q;
+ *seed *= 1389796;
+ q = (int)(*seed / 2147483647);
+ *seed -= (double)q * 2147483647;
+ return *seed / 2147483647; }
+
+/* Returns a random integer 0 <= x < size. Seed must never be 0. */
+static inline int irand(double* seed, int size) {
+ return (int)(drand(seed) * size); }
+
+/*====================================================================*/
+/* Predeclarations: */
+
+static void sort(void** array, int size,
+ int(*comp)(const void *, const void *));
+
+/*====================================================================*/
+/* Clause datatype + minor functions: */
+
+#if 0 /* by mao; see minisat.h */
+struct clause_t
+{
+ int size_learnt;
+ lit lits[0];
+};
+#endif
+
+#define clause_size(c) ((c)->size_learnt >> 1)
+
+#define clause_begin(c) ((c)->lits)
+
+#define clause_learnt(c) ((c)->size_learnt & 1)
+
+#define clause_activity(c) \
+ (*((float*)&(c)->lits[(c)->size_learnt>>1]))
+
+#define clause_setactivity(c, a) \
+ (void)(*((float*)&(c)->lits[(c)->size_learnt>>1]) = (a))
+
+/*====================================================================*/
+/* Encode literals in clause pointers: */
+
+#if 0 /* 8/I-2017 by cmatraki (64-bit portability) */
+#define clause_from_lit(l) \
+ (clause*)((unsigned long)(l) + (unsigned long)(l) + 1)
+
+#define clause_is_lit(c) \
+ ((unsigned long)(c) & 1)
+
+#define clause_read_lit(c) \
+ (lit)((unsigned long)(c) >> 1)
+#else
+#define clause_from_lit(l) \
+ (clause*)((size_t)(l) + (size_t)(l) + 1)
+
+#define clause_is_lit(c) \
+ ((size_t)(c) & 1)
+
+#define clause_read_lit(c) \
+ (lit)((size_t)(c) >> 1)
+#endif
+
+/*====================================================================*/
+/* Simple helpers: */
+
+#define solver_dlevel(s) \
+ (int)veci_size(&(s)->trail_lim)
+
+#define solver_read_wlist(s, l) \
+ (vecp *)(&(s)->wlists[l])
+
+static inline void vecp_remove(vecp* v, void* e)
+{
+ void** ws = vecp_begin(v);
+ int j = 0;
+
+ for (; ws[j] != e ; j++);
+ assert(j < vecp_size(v));
+ for (; j < vecp_size(v)-1; j++) ws[j] = ws[j+1];
+ vecp_resize(v,vecp_size(v)-1);
+}
+
+/*====================================================================*/
+/* Variable order functions: */
+
+static inline void order_update(solver* s, int v)
+{ /* updateorder */
+ int* orderpos = s->orderpos;
+ double* activity = s->activity;
+ int* heap = veci_begin(&s->order);
+ int i = orderpos[v];
+ int x = heap[i];
+ int parent = (i - 1) / 2;
+
+ assert(s->orderpos[v] != -1);
+
+ while (i != 0 && activity[x] > activity[heap[parent]]){
+ heap[i] = heap[parent];
+ orderpos[heap[i]] = i;
+ i = parent;
+ parent = (i - 1) / 2;
+ }
+ heap[i] = x;
+ orderpos[x] = i;
+}
+
+#define order_assigned(s, v) /* nop */
+
+static inline void order_unassigned(solver* s, int v)
+{ /* undoorder */
+ int* orderpos = s->orderpos;
+ if (orderpos[v] == -1){
+ orderpos[v] = veci_size(&s->order);
+ veci_push(&s->order,v);
+ order_update(s,v);
+ }
+}
+
+static int order_select(solver* s, float random_var_freq)
+{ /* selectvar */
+ int* heap;
+ double* activity;
+ int* orderpos;
+
+ lbool* values = s->assigns;
+
+ /* Random decision: */
+ if (drand(&s->random_seed) < random_var_freq){
+ int next = irand(&s->random_seed,s->size);
+ assert(next >= 0 && next < s->size);
+ if (values[next] == l_Undef)
+ return next;
+ }
+
+ /* Activity based decision: */
+
+ heap = veci_begin(&s->order);
+ activity = s->activity;
+ orderpos = s->orderpos;
+
+ while (veci_size(&s->order) > 0){
+ int next = heap[0];
+ int size = veci_size(&s->order)-1;
+ int x = heap[size];
+
+ veci_resize(&s->order,size);
+
+ orderpos[next] = -1;
+
+ if (size > 0){
+ double act = activity[x];
+
+ int i = 0;
+ int child = 1;
+
+ while (child < size){
+ if (child+1 < size
+ && activity[heap[child]] < activity[heap[child+1]])
+ child++;
+
+ assert(child < size);
+
+ if (act >= activity[heap[child]])
+ break;
+
+ heap[i] = heap[child];
+ orderpos[heap[i]] = i;
+ i = child;
+ child = 2 * child + 1;
+ }
+ heap[i] = x;
+ orderpos[heap[i]] = i;
+ }
+
+ if (values[next] == l_Undef)
+ return next;
+ }
+
+ return var_Undef;
+}
+
+/*====================================================================*/
+/* Activity functions: */
+
+static inline void act_var_rescale(solver* s) {
+ double* activity = s->activity;
+ int i;
+ for (i = 0; i < s->size; i++)
+ activity[i] *= 1e-100;
+ s->var_inc *= 1e-100;
+}
+
+static inline void act_var_bump(solver* s, int v) {
+ double* activity = s->activity;
+ if ((activity[v] += s->var_inc) > 1e100)
+ act_var_rescale(s);
+
+ /* printf("bump %d %f\n", v-1, activity[v]); */
+
+ if (s->orderpos[v] != -1)
+ order_update(s,v);
+
+}
+
+static inline void act_var_decay(solver* s)
+ { s->var_inc *= s->var_decay; }
+
+static inline void act_clause_rescale(solver* s) {
+ clause** cs = (clause**)vecp_begin(&s->learnts);
+ int i;
+ for (i = 0; i < vecp_size(&s->learnts); i++){
+ float a = clause_activity(cs[i]);
+ clause_setactivity(cs[i], a * (float)1e-20);
+ }
+ s->cla_inc *= (float)1e-20;
+}
+
+static inline void act_clause_bump(solver* s, clause *c) {
+ float a = clause_activity(c) + s->cla_inc;
+ clause_setactivity(c,a);
+ if (a > 1e20) act_clause_rescale(s);
+}
+
+static inline void act_clause_decay(solver* s)
+ { s->cla_inc *= s->cla_decay; }
+
+/*====================================================================*/
+/* Clause functions: */
+
+/* pre: size > 1 && no variable occurs twice
+ */
+static clause* clause_new(solver* s, lit* begin, lit* end, int learnt)
+{
+ int size;
+ clause* c;
+ int i;
+
+ assert(end - begin > 1);
+ assert(learnt >= 0 && learnt < 2);
+ size = end - begin;
+ c = (clause*)malloc(sizeof(clause)
+ + sizeof(lit) * size + learnt * sizeof(float));
+ c->size_learnt = (size << 1) | learnt;
+#if 1 /* by mao & cmatraki; non-portable check that is a fundamental \
+ * assumption of minisat code: bit 0 is used as a flag (zero \
+ * for pointer, one for shifted int) so allocated memory should \
+ * be at least 16-bit aligned */
+ assert(((size_t)c & 1) == 0);
+#endif
+
+ for (i = 0; i < size; i++)
+ c->lits[i] = begin[i];
+
+ if (learnt)
+ *((float*)&c->lits[size]) = 0.0;
+
+ assert(begin[0] >= 0);
+ assert(begin[0] < s->size*2);
+ assert(begin[1] >= 0);
+ assert(begin[1] < s->size*2);
+
+ assert(lit_neg(begin[0]) < s->size*2);
+ assert(lit_neg(begin[1]) < s->size*2);
+
+ /* vecp_push(solver_read_wlist(s,lit_neg(begin[0])),(void*)c); */
+ /* vecp_push(solver_read_wlist(s,lit_neg(begin[1])),(void*)c); */
+
+ vecp_push(solver_read_wlist(s,lit_neg(begin[0])),
+ (void*)(size > 2 ? c : clause_from_lit(begin[1])));
+ vecp_push(solver_read_wlist(s,lit_neg(begin[1])),
+ (void*)(size > 2 ? c : clause_from_lit(begin[0])));
+
+ return c;
+}
+
+static void clause_remove(solver* s, clause* c)
+{
+ lit* lits = clause_begin(c);
+ assert(lit_neg(lits[0]) < s->size*2);
+ assert(lit_neg(lits[1]) < s->size*2);
+
+ /* vecp_remove(solver_read_wlist(s,lit_neg(lits[0])),(void*)c); */
+ /* vecp_remove(solver_read_wlist(s,lit_neg(lits[1])),(void*)c); */
+
+ assert(lits[0] < s->size*2);
+ vecp_remove(solver_read_wlist(s,lit_neg(lits[0])),
+ (void*)(clause_size(c) > 2 ? c : clause_from_lit(lits[1])));
+ vecp_remove(solver_read_wlist(s,lit_neg(lits[1])),
+ (void*)(clause_size(c) > 2 ? c : clause_from_lit(lits[0])));
+
+ if (clause_learnt(c)){
+ s->stats.learnts--;
+ s->stats.learnts_literals -= clause_size(c);
+ }else{
+ s->stats.clauses--;
+ s->stats.clauses_literals -= clause_size(c);
+ }
+
+ free(c);
+}
+
+static lbool clause_simplify(solver* s, clause* c)
+{
+ lit* lits = clause_begin(c);
+ lbool* values = s->assigns;
+ int i;
+
+ assert(solver_dlevel(s) == 0);
+
+ for (i = 0; i < clause_size(c); i++){
+ lbool sig = !lit_sign(lits[i]); sig += sig - 1;
+ if (values[lit_var(lits[i])] == sig)
+ return l_True;
+ }
+ return l_False;
+}
+
+/*====================================================================*/
+/* Minor (solver) functions: */
+
+void solver_setnvars(solver* s,int n)
+{
+ int var;
+
+ if (s->cap < n){
+
+ while (s->cap < n) s->cap = s->cap*2+1;
+
+ s->wlists = (vecp*) realloc(s->wlists,
+ sizeof(vecp)*s->cap*2);
+ s->activity = (double*) realloc(s->activity,
+ sizeof(double)*s->cap);
+ s->assigns = (lbool*) realloc(s->assigns,
+ sizeof(lbool)*s->cap);
+ s->orderpos = (int*) realloc(s->orderpos,
+ sizeof(int)*s->cap);
+ s->reasons = (clause**)realloc(s->reasons,
+ sizeof(clause*)*s->cap);
+ s->levels = (int*) realloc(s->levels,
+ sizeof(int)*s->cap);
+ s->tags = (lbool*) realloc(s->tags,
+ sizeof(lbool)*s->cap);
+ s->trail = (lit*) realloc(s->trail,
+ sizeof(lit)*s->cap);
+ }
+
+ for (var = s->size; var < n; var++){
+ vecp_new(&s->wlists[2*var]);
+ vecp_new(&s->wlists[2*var+1]);
+ s->activity [var] = 0;
+ s->assigns [var] = l_Undef;
+ s->orderpos [var] = veci_size(&s->order);
+ s->reasons [var] = (clause*)0;
+ s->levels [var] = 0;
+ s->tags [var] = l_Undef;
+
+ /* does not hold because variables enqueued at top level will
+ not be reinserted in the heap
+ assert(veci_size(&s->order) == var);
+ */
+ veci_push(&s->order,var);
+ order_update(s, var);
+ }
+
+ s->size = n > s->size ? n : s->size;
+}
+
+static inline bool enqueue(solver* s, lit l, clause* from)
+{
+ lbool* values = s->assigns;
+ int v = lit_var(l);
+ lbool val = values[v];
+ lbool sig;
+#ifdef VERBOSEDEBUG
+ printf(L_IND"enqueue("L_LIT")\n", L_ind, L_lit(l));
+#endif
+
+ /* lbool */ sig = !lit_sign(l); sig += sig - 1;
+ if (val != l_Undef){
+ return val == sig;
+ }else{
+ /* New fact -- store it. */
+ int* levels;
+ clause** reasons;
+#ifdef VERBOSEDEBUG
+ printf(L_IND"bind("L_LIT")\n", L_ind, L_lit(l));
+#endif
+ /* int* */ levels = s->levels;
+ /* clause** */ reasons = s->reasons;
+
+ values [v] = sig;
+ levels [v] = solver_dlevel(s);
+ reasons[v] = from;
+ s->trail[s->qtail++] = l;
+
+ order_assigned(s, v);
+ return true;
+ }
+}
+
+static inline void assume(solver* s, lit l){
+ assert(s->qtail == s->qhead);
+ assert(s->assigns[lit_var(l)] == l_Undef);
+#ifdef VERBOSEDEBUG
+ printf(L_IND"assume("L_LIT")\n", L_ind, L_lit(l));
+#endif
+ veci_push(&s->trail_lim,s->qtail);
+ enqueue(s,l,(clause*)0);
+}
+
+static inline void solver_canceluntil(solver* s, int level) {
+ lit* trail;
+ lbool* values;
+ clause** reasons;
+ int bound;
+ int c;
+
+ if (solver_dlevel(s) <= level)
+ return;
+
+ trail = s->trail;
+ values = s->assigns;
+ reasons = s->reasons;
+ bound = (veci_begin(&s->trail_lim))[level];
+
+ for (c = s->qtail-1; c >= bound; c--) {
+ int x = lit_var(trail[c]);
+ values [x] = l_Undef;
+ reasons[x] = (clause*)0;
+ }
+
+ for (c = s->qhead-1; c >= bound; c--)
+ order_unassigned(s,lit_var(trail[c]));
+
+ s->qhead = s->qtail = bound;
+ veci_resize(&s->trail_lim,level);
+}
+
+static void solver_record(solver* s, veci* cls)
+{
+ lit* begin = veci_begin(cls);
+ lit* end = begin + veci_size(cls);
+ clause* c = (veci_size(cls) > 1) ? clause_new(s,begin,end,1)
+ : (clause*)0;
+ enqueue(s,*begin,c);
+
+ assert(veci_size(cls) > 0);
+
+ if (c != 0) {
+ vecp_push(&s->learnts,c);
+ act_clause_bump(s,c);
+ s->stats.learnts++;
+ s->stats.learnts_literals += veci_size(cls);
+ }
+}
+
+static double solver_progress(solver* s)
+{
+ lbool* values = s->assigns;
+ int* levels = s->levels;
+ int i;
+
+ double progress = 0;
+ double F = 1.0 / s->size;
+ for (i = 0; i < s->size; i++)
+ if (values[i] != l_Undef)
+ progress += pow(F, levels[i]);
+ return progress / s->size;
+}
+
+/*====================================================================*/
+/* Major methods: */
+
+static bool solver_lit_removable(solver* s, lit l, int minl)
+{
+ lbool* tags = s->tags;
+ clause** reasons = s->reasons;
+ int* levels = s->levels;
+ int top = veci_size(&s->tagged);
+
+ assert(lit_var(l) >= 0 && lit_var(l) < s->size);
+ assert(reasons[lit_var(l)] != 0);
+ veci_resize(&s->stack,0);
+ veci_push(&s->stack,lit_var(l));
+
+ while (veci_size(&s->stack) > 0){
+ clause* c;
+ int v = veci_begin(&s->stack)[veci_size(&s->stack)-1];
+ assert(v >= 0 && v < s->size);
+ veci_resize(&s->stack,veci_size(&s->stack)-1);
+ assert(reasons[v] != 0);
+ c = reasons[v];
+
+ if (clause_is_lit(c)){
+ int v = lit_var(clause_read_lit(c));
+ if (tags[v] == l_Undef && levels[v] != 0){
+ if (reasons[v] != 0
+ && ((1 << (levels[v] & 31)) & minl)){
+ veci_push(&s->stack,v);
+ tags[v] = l_True;
+ veci_push(&s->tagged,v);
+ }else{
+ int* tagged = veci_begin(&s->tagged);
+ int j;
+ for (j = top; j < veci_size(&s->tagged); j++)
+ tags[tagged[j]] = l_Undef;
+ veci_resize(&s->tagged,top);
+ return false;
+ }
+ }
+ }else{
+ lit* lits = clause_begin(c);
+ int i, j;
+
+ for (i = 1; i < clause_size(c); i++){
+ int v = lit_var(lits[i]);
+ if (tags[v] == l_Undef && levels[v] != 0){
+ if (reasons[v] != 0
+ && ((1 << (levels[v] & 31)) & minl)){
+
+ veci_push(&s->stack,lit_var(lits[i]));
+ tags[v] = l_True;
+ veci_push(&s->tagged,v);
+ }else{
+ int* tagged = veci_begin(&s->tagged);
+ for (j = top; j < veci_size(&s->tagged); j++)
+ tags[tagged[j]] = l_Undef;
+ veci_resize(&s->tagged,top);
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static void solver_analyze(solver* s, clause* c, veci* learnt)
+{
+ lit* trail = s->trail;
+ lbool* tags = s->tags;
+ clause** reasons = s->reasons;
+ int* levels = s->levels;
+ int cnt = 0;
+ lit p = lit_Undef;
+ int ind = s->qtail-1;
+ lit* lits;
+ int i, j, minl;
+ int* tagged;
+
+ veci_push(learnt,lit_Undef);
+
+ do{
+ assert(c != 0);
+
+ if (clause_is_lit(c)){
+ lit q = clause_read_lit(c);
+ assert(lit_var(q) >= 0 && lit_var(q) < s->size);
+ if (tags[lit_var(q)] == l_Undef && levels[lit_var(q)] > 0){
+ tags[lit_var(q)] = l_True;
+ veci_push(&s->tagged,lit_var(q));
+ act_var_bump(s,lit_var(q));
+ if (levels[lit_var(q)] == solver_dlevel(s))
+ cnt++;
+ else
+ veci_push(learnt,q);
+ }
+ }else{
+
+ if (clause_learnt(c))
+ act_clause_bump(s,c);
+
+ lits = clause_begin(c);
+ /* printlits(lits,lits+clause_size(c)); printf("\n"); */
+ for (j = (p == lit_Undef ? 0 : 1); j < clause_size(c); j++){
+ lit q = lits[j];
+ assert(lit_var(q) >= 0 && lit_var(q) < s->size);
+ if (tags[lit_var(q)] == l_Undef
+ && levels[lit_var(q)] > 0){
+ tags[lit_var(q)] = l_True;
+ veci_push(&s->tagged,lit_var(q));
+ act_var_bump(s,lit_var(q));
+ if (levels[lit_var(q)] == solver_dlevel(s))
+ cnt++;
+ else
+ veci_push(learnt,q);
+ }
+ }
+ }
+
+ while (tags[lit_var(trail[ind--])] == l_Undef);
+
+ p = trail[ind+1];
+ c = reasons[lit_var(p)];
+ cnt--;
+
+ }while (cnt > 0);
+
+ *veci_begin(learnt) = lit_neg(p);
+
+ lits = veci_begin(learnt);
+ minl = 0;
+ for (i = 1; i < veci_size(learnt); i++){
+ int lev = levels[lit_var(lits[i])];
+ minl |= 1 << (lev & 31);
+ }
+
+ /* simplify (full) */
+ for (i = j = 1; i < veci_size(learnt); i++){
+ if (reasons[lit_var(lits[i])] == 0
+ || !solver_lit_removable(s,lits[i],minl))
+ lits[j++] = lits[i];
+ }
+
+ /* update size of learnt + statistics */
+ s->stats.max_literals += veci_size(learnt);
+ veci_resize(learnt,j);
+ s->stats.tot_literals += j;
+
+ /* clear tags */
+ tagged = veci_begin(&s->tagged);
+ for (i = 0; i < veci_size(&s->tagged); i++)
+ tags[tagged[i]] = l_Undef;
+ veci_resize(&s->tagged,0);
+
+#ifdef DEBUG
+ for (i = 0; i < s->size; i++)
+ assert(tags[i] == l_Undef);
+#endif
+
+#ifdef VERBOSEDEBUG
+ printf(L_IND"Learnt {", L_ind);
+ for (i = 0; i < veci_size(learnt); i++)
+ printf(" "L_LIT, L_lit(lits[i]));
+#endif
+ if (veci_size(learnt) > 1){
+ int max_i = 1;
+ int max = levels[lit_var(lits[1])];
+ lit tmp;
+
+ for (i = 2; i < veci_size(learnt); i++)
+ if (levels[lit_var(lits[i])] > max){
+ max = levels[lit_var(lits[i])];
+ max_i = i;
+ }
+
+ tmp = lits[1];
+ lits[1] = lits[max_i];
+ lits[max_i] = tmp;
+ }
+#ifdef VERBOSEDEBUG
+ {
+ int lev = veci_size(learnt) > 1 ? levels[lit_var(lits[1])] : 0;
+ printf(" } at level %d\n", lev);
+ }
+#endif
+}
+
+clause* solver_propagate(solver* s)
+{
+ lbool* values = s->assigns;
+ clause* confl = (clause*)0;
+ lit* lits;
+
+ /* printf("solver_propagate\n"); */
+ while (confl == 0 && s->qtail - s->qhead > 0){
+ lit p = s->trail[s->qhead++];
+ vecp* ws = solver_read_wlist(s,p);
+ clause **begin = (clause**)vecp_begin(ws);
+ clause **end = begin + vecp_size(ws);
+ clause **i, **j;
+
+ s->stats.propagations++;
+ s->simpdb_props--;
+
+ /* printf("checking lit %d: "L_LIT"\n", veci_size(ws),
+ L_lit(p)); */
+ for (i = j = begin; i < end; ){
+ if (clause_is_lit(*i)){
+ *j++ = *i;
+ if (!enqueue(s,clause_read_lit(*i),clause_from_lit(p))){
+ confl = s->binary;
+ (clause_begin(confl))[1] = lit_neg(p);
+ (clause_begin(confl))[0] = clause_read_lit(*i++);
+
+ /* Copy the remaining watches: */
+ while (i < end)
+ *j++ = *i++;
+ }
+ }else{
+ lit false_lit;
+ lbool sig;
+
+ lits = clause_begin(*i);
+
+ /* Make sure the false literal is data[1]: */
+ false_lit = lit_neg(p);
+ if (lits[0] == false_lit){
+ lits[0] = lits[1];
+ lits[1] = false_lit;
+ }
+ assert(lits[1] == false_lit);
+ /* printf("checking clause: ");
+ printlits(lits, lits+clause_size(*i));
+ printf("\n"); */
+
+ /* If 0th watch is true, then clause is already
+ satisfied. */
+ sig = !lit_sign(lits[0]); sig += sig - 1;
+ if (values[lit_var(lits[0])] == sig){
+ *j++ = *i;
+ }else{
+ /* Look for new watch: */
+ lit* stop = lits + clause_size(*i);
+ lit* k;
+ for (k = lits + 2; k < stop; k++){
+ lbool sig = lit_sign(*k); sig += sig - 1;
+ if (values[lit_var(*k)] != sig){
+ lits[1] = *k;
+ *k = false_lit;
+ vecp_push(solver_read_wlist(s,
+ lit_neg(lits[1])),*i);
+ goto next; }
+ }
+
+ *j++ = *i;
+ /* Clause is unit under assignment: */
+ if (!enqueue(s,lits[0], *i)){
+ confl = *i++;
+ /* Copy the remaining watches: */
+ while (i < end)
+ *j++ = *i++;
+ }
+ }
+ }
+ next:
+ i++;
+ }
+
+ s->stats.inspects += j - (clause**)vecp_begin(ws);
+ vecp_resize(ws,j - (clause**)vecp_begin(ws));
+ }
+
+ return confl;
+}
+
+static inline int clause_cmp (const void* x, const void* y) {
+ return clause_size((clause*)x) > 2
+ && (clause_size((clause*)y) == 2
+ || clause_activity((clause*)x)
+ < clause_activity((clause*)y)) ? -1 : 1; }
+
+void solver_reducedb(solver* s)
+{
+ int i, j;
+ double extra_lim = s->cla_inc / vecp_size(&s->learnts);
+ /* Remove any clause below this activity */
+ clause** learnts = (clause**)vecp_begin(&s->learnts);
+ clause** reasons = s->reasons;
+
+ sort(vecp_begin(&s->learnts), vecp_size(&s->learnts), clause_cmp);
+
+ for (i = j = 0; i < vecp_size(&s->learnts) / 2; i++){
+ if (clause_size(learnts[i]) > 2
+ && reasons[lit_var(*clause_begin(learnts[i]))]
+ != learnts[i])
+ clause_remove(s,learnts[i]);
+ else
+ learnts[j++] = learnts[i];
+ }
+ for (; i < vecp_size(&s->learnts); i++){
+ if (clause_size(learnts[i]) > 2
+ && reasons[lit_var(*clause_begin(learnts[i]))]
+ != learnts[i]
+ && clause_activity(learnts[i]) < extra_lim)
+ clause_remove(s,learnts[i]);
+ else
+ learnts[j++] = learnts[i];
+ }
+
+ /* printf("reducedb deleted %d\n", vecp_size(&s->learnts) - j); */
+
+ vecp_resize(&s->learnts,j);
+}
+
+static lbool solver_search(solver* s, int nof_conflicts,
+ int nof_learnts)
+{
+ int* levels = s->levels;
+ double var_decay = 0.95;
+ double clause_decay = 0.999;
+ double random_var_freq = 0.02;
+
+ int conflictC = 0;
+ veci learnt_clause;
+
+ assert(s->root_level == solver_dlevel(s));
+
+ s->stats.starts++;
+ s->var_decay = (float)(1 / var_decay );
+ s->cla_decay = (float)(1 / clause_decay);
+ veci_resize(&s->model,0);
+ veci_new(&learnt_clause);
+
+ for (;;){
+ clause* confl = solver_propagate(s);
+ if (confl != 0){
+ /* CONFLICT */
+ int blevel;
+
+#ifdef VERBOSEDEBUG
+ printf(L_IND"**CONFLICT**\n", L_ind);
+#endif
+ s->stats.conflicts++; conflictC++;
+ if (solver_dlevel(s) == s->root_level){
+ veci_delete(&learnt_clause);
+ return l_False;
+ }
+
+ veci_resize(&learnt_clause,0);
+ solver_analyze(s, confl, &learnt_clause);
+ blevel = veci_size(&learnt_clause) > 1
+ ? levels[lit_var(veci_begin(&learnt_clause)[1])]
+ : s->root_level;
+ blevel = s->root_level > blevel ? s->root_level : blevel;
+ solver_canceluntil(s,blevel);
+ solver_record(s,&learnt_clause);
+ act_var_decay(s);
+ act_clause_decay(s);
+
+ }else{
+ /* NO CONFLICT */
+ int next;
+
+ if (nof_conflicts >= 0 && conflictC >= nof_conflicts){
+ /* Reached bound on number of conflicts: */
+ s->progress_estimate = solver_progress(s);
+ solver_canceluntil(s,s->root_level);
+ veci_delete(&learnt_clause);
+ return l_Undef; }
+
+ if (solver_dlevel(s) == 0)
+ /* Simplify the set of problem clauses: */
+ solver_simplify(s);
+
+ if (nof_learnts >= 0
+ && vecp_size(&s->learnts) - s->qtail >= nof_learnts)
+ /* Reduce the set of learnt clauses: */
+ solver_reducedb(s);
+
+ /* New variable decision: */
+ s->stats.decisions++;
+ next = order_select(s,(float)random_var_freq);
+
+ if (next == var_Undef){
+ /* Model found: */
+ lbool* values = s->assigns;
+ int i;
+ for (i = 0; i < s->size; i++)
+ veci_push(&s->model,(int)values[i]);
+ solver_canceluntil(s,s->root_level);
+ veci_delete(&learnt_clause);
+
+ /*
+ veci apa; veci_new(&apa);
+ for (i = 0; i < s->size; i++)
+ veci_push(&apa,(int)(s->model.ptr[i] == l_True
+ ? toLit(i) : lit_neg(toLit(i))));
+ printf("model: ");
+ printlits((lit*)apa.ptr,
+ (lit*)apa.ptr + veci_size(&apa)); printf("\n");
+ veci_delete(&apa);
+ */
+
+ return l_True;
+ }
+
+ assume(s,lit_neg(toLit(next)));
+ }
+ }
+
+#if 0 /* by mao; unreachable code */
+ return l_Undef; /* cannot happen */
+#endif
+}
+
+/*====================================================================*/
+/* External solver functions: */
+
+solver* solver_new(void)
+{
+ solver* s = (solver*)malloc(sizeof(solver));
+
+ /* initialize vectors */
+ vecp_new(&s->clauses);
+ vecp_new(&s->learnts);
+ veci_new(&s->order);
+ veci_new(&s->trail_lim);
+ veci_new(&s->tagged);
+ veci_new(&s->stack);
+ veci_new(&s->model);
+
+ /* initialize arrays */
+ s->wlists = 0;
+ s->activity = 0;
+ s->assigns = 0;
+ s->orderpos = 0;
+ s->reasons = 0;
+ s->levels = 0;
+ s->tags = 0;
+ s->trail = 0;
+
+ /* initialize other vars */
+ s->size = 0;
+ s->cap = 0;
+ s->qhead = 0;
+ s->qtail = 0;
+ s->cla_inc = 1;
+ s->cla_decay = 1;
+ s->var_inc = 1;
+ s->var_decay = 1;
+ s->root_level = 0;
+ s->simpdb_assigns = 0;
+ s->simpdb_props = 0;
+ s->random_seed = 91648253;
+ s->progress_estimate = 0;
+ s->binary = (clause*)malloc(sizeof(clause)
+ + sizeof(lit)*2);
+ s->binary->size_learnt = (2 << 1);
+ s->verbosity = 0;
+
+ s->stats.starts = 0;
+ s->stats.decisions = 0;
+ s->stats.propagations = 0;
+ s->stats.inspects = 0;
+ s->stats.conflicts = 0;
+ s->stats.clauses = 0;
+ s->stats.clauses_literals = 0;
+ s->stats.learnts = 0;
+ s->stats.learnts_literals = 0;
+ s->stats.max_literals = 0;
+ s->stats.tot_literals = 0;
+
+ return s;
+}
+
+void solver_delete(solver* s)
+{
+ int i;
+ for (i = 0; i < vecp_size(&s->clauses); i++)
+ free(vecp_begin(&s->clauses)[i]);
+
+ for (i = 0; i < vecp_size(&s->learnts); i++)
+ free(vecp_begin(&s->learnts)[i]);
+
+ /* delete vectors */
+ vecp_delete(&s->clauses);
+ vecp_delete(&s->learnts);
+ veci_delete(&s->order);
+ veci_delete(&s->trail_lim);
+ veci_delete(&s->tagged);
+ veci_delete(&s->stack);
+ veci_delete(&s->model);
+ free(s->binary);
+
+ /* delete arrays */
+ if (s->wlists != 0){
+ int i;
+ for (i = 0; i < s->size*2; i++)
+ vecp_delete(&s->wlists[i]);
+
+ /* if one is different from null, all are */
+ free(s->wlists);
+ free(s->activity );
+ free(s->assigns );
+ free(s->orderpos );
+ free(s->reasons );
+ free(s->levels );
+ free(s->trail );
+ free(s->tags );
+ }
+
+ free(s);
+}
+
+bool solver_addclause(solver* s, lit* begin, lit* end)
+{
+ lit *i,*j;
+ int maxvar;
+ lbool* values;
+ lit last;
+
+ if (begin == end) return false;
+
+ /* printlits(begin,end); printf("\n"); */
+ /* insertion sort */
+ maxvar = lit_var(*begin);
+ for (i = begin + 1; i < end; i++){
+ lit l = *i;
+ maxvar = lit_var(l) > maxvar ? lit_var(l) : maxvar;
+ for (j = i; j > begin && *(j-1) > l; j--)
+ *j = *(j-1);
+ *j = l;
+ }
+ solver_setnvars(s,maxvar+1);
+
+ /* printlits(begin,end); printf("\n"); */
+ values = s->assigns;
+
+ /* delete duplicates */
+ last = lit_Undef;
+ for (i = j = begin; i < end; i++){
+ /* printf("lit: "L_LIT", value = %d\n", L_lit(*i),
+ (lit_sign(*i) ? -values[lit_var(*i)] : values[lit_var(*i)])); */
+ lbool sig = !lit_sign(*i); sig += sig - 1;
+ if (*i == lit_neg(last) || sig == values[lit_var(*i)])
+ return true; /* tautology */
+ else if (*i != last && values[lit_var(*i)] == l_Undef)
+ last = *j++ = *i;
+ }
+
+ /* printf("final: "); printlits(begin,j); printf("\n"); */
+
+ if (j == begin) /* empty clause */
+ return false;
+ else if (j - begin == 1) /* unit clause */
+ return enqueue(s,*begin,(clause*)0);
+
+ /* create new clause */
+ vecp_push(&s->clauses,clause_new(s,begin,j,0));
+
+ s->stats.clauses++;
+ s->stats.clauses_literals += j - begin;
+
+ return true;
+}
+
+bool solver_simplify(solver* s)
+{
+ clause** reasons;
+ int type;
+
+ assert(solver_dlevel(s) == 0);
+
+ if (solver_propagate(s) != 0)
+ return false;
+
+ if (s->qhead == s->simpdb_assigns || s->simpdb_props > 0)
+ return true;
+
+ reasons = s->reasons;
+ for (type = 0; type < 2; type++){
+ vecp* cs = type ? &s->learnts : &s->clauses;
+ clause** cls = (clause**)vecp_begin(cs);
+
+ int i, j;
+ for (j = i = 0; i < vecp_size(cs); i++){
+ if (reasons[lit_var(*clause_begin(cls[i]))] != cls[i] &&
+ clause_simplify(s,cls[i]) == l_True)
+ clause_remove(s,cls[i]);
+ else
+ cls[j++] = cls[i];
+ }
+ vecp_resize(cs,j);
+ }
+
+ s->simpdb_assigns = s->qhead;
+ /* (shouldn't depend on 'stats' really, but it will do for now) */
+ s->simpdb_props = (int)(s->stats.clauses_literals
+ + s->stats.learnts_literals);
+
+ return true;
+}
+
+bool solver_solve(solver* s, lit* begin, lit* end)
+{
+ double nof_conflicts = 100;
+ double nof_learnts = solver_nclauses(s) / 3;
+ lbool status = l_Undef;
+ lbool* values = s->assigns;
+ lit* i;
+
+ /* printf("solve: "); printlits(begin, end); printf("\n"); */
+ for (i = begin; i < end; i++){
+ switch (lit_sign(*i) ? -values[lit_var(*i)]
+ : values[lit_var(*i)]){
+ case 1: /* l_True: */
+ break;
+ case 0: /* l_Undef */
+ assume(s, *i);
+ if (solver_propagate(s) == NULL)
+ break;
+ /* falltrough */
+ case -1: /* l_False */
+ solver_canceluntil(s, 0);
+ return false;
+ }
+ }
+
+ s->root_level = solver_dlevel(s);
+
+ if (s->verbosity >= 1){
+ printf("==================================[MINISAT]============"
+ "=======================\n");
+ printf("| Conflicts | ORIGINAL | LEARNT "
+ " | Progress |\n");
+ printf("| | Clauses Literals | Limit Clauses Litera"
+ "ls Lit/Cl | |\n");
+ printf("======================================================="
+ "=======================\n");
+ }
+
+ while (status == l_Undef){
+ double Ratio = (s->stats.learnts == 0)? 0.0 :
+ s->stats.learnts_literals / (double)s->stats.learnts;
+
+ if (s->verbosity >= 1){
+ printf("| %9.0f | %7.0f %8.0f | %7.0f %7.0f %8.0f %7.1f | %"
+ "6.3f %% |\n",
+ (double)s->stats.conflicts,
+ (double)s->stats.clauses,
+ (double)s->stats.clauses_literals,
+ (double)nof_learnts,
+ (double)s->stats.learnts,
+ (double)s->stats.learnts_literals,
+ Ratio,
+ s->progress_estimate*100);
+ fflush(stdout);
+ }
+ status = solver_search(s,(int)nof_conflicts, (int)nof_learnts);
+ nof_conflicts *= 1.5;
+ nof_learnts *= 1.1;
+ }
+ if (s->verbosity >= 1)
+ printf("======================================================="
+ "=======================\n");
+
+ solver_canceluntil(s,0);
+ return status != l_False;
+}
+
+int solver_nvars(solver* s)
+{
+ return s->size;
+}
+
+int solver_nclauses(solver* s)
+{
+ return vecp_size(&s->clauses);
+}
+
+int solver_nconflicts(solver* s)
+{
+ return (int)s->stats.conflicts;
+}
+
+/*====================================================================*/
+/* Sorting functions (sigh): */
+
+static inline void selectionsort(void** array, int size,
+ int(*comp)(const void *, const void *))
+{
+ int i, j, best_i;
+ void* tmp;
+
+ for (i = 0; i < size-1; i++){
+ best_i = i;
+ for (j = i+1; j < size; j++){
+ if (comp(array[j], array[best_i]) < 0)
+ best_i = j;
+ }
+ tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp;
+ }
+}
+
+static void sortrnd(void** array, int size,
+ int(*comp)(const void *, const void *),
+ double* seed)
+{
+ if (size <= 15)
+ selectionsort(array, size, comp);
+
+ else{
+ void* pivot = array[irand(seed, size)];
+ void* tmp;
+ int i = -1;
+ int j = size;
+
+ for(;;){
+ do i++; while(comp(array[i], pivot)<0);
+ do j--; while(comp(pivot, array[j])<0);
+
+ if (i >= j) break;
+
+ tmp = array[i]; array[i] = array[j]; array[j] = tmp;
+ }
+
+ sortrnd(array , i , comp, seed);
+ sortrnd(&array[i], size-i, comp, seed);
+ }
+}
+
+static void sort(void** array, int size,
+ int(*comp)(const void *, const void *))
+{
+ double seed = 91648253;
+ sortrnd(array,size,comp,&seed);
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/minisat/minisat.h b/test/monniaux/glpk-4.65/src/minisat/minisat.h
new file mode 100644
index 00000000..2733e8d6
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/minisat/minisat.h
@@ -0,0 +1,230 @@
+/* minisat.h */
+
+/* Modified by Andrew Makhorin <mao@gnu.org>, August 2011 */
+
+/***********************************************************************
+* MiniSat -- Copyright (c) 2005, Niklas Sorensson
+* http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation files
+* (the "Software"), to deal in the Software without restriction,
+* including without limitation the rights to use, copy, modify, merge,
+* publish, distribute, sublicense, and/or sell copies of the Software,
+* and to permit persons to whom the Software is furnished to do so,
+* subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+***********************************************************************/
+/* Modified to compile with MS Visual Studio 6.0 by Alan Mishchenko */
+
+#ifndef MINISAT_H
+#define MINISAT_H
+
+/*====================================================================*/
+/* Simple types: */
+
+typedef int bool;
+
+#define true 1
+#define false 0
+
+typedef int lit;
+#if 0 /* by mao */
+typedef char lbool;
+#else
+typedef int lbool;
+#endif
+
+#define var_Undef (int)(-1)
+#define lit_Undef (lit)(-2)
+
+#define l_Undef (lbool)0
+#define l_True (lbool)1
+#define l_False (lbool)(-1)
+
+#define toLit(v) (lit)((v) + (v))
+#define lit_neg(l) (lit)((l) ^ 1)
+#define lit_var(l) (int)((l) >> 1)
+#define lit_sign(l) (int)((l) & 1)
+
+/*====================================================================*/
+/* Vectors: */
+
+/* vector of 32-bit intergers (added for 64-bit portability) */
+typedef struct /* veci_t */ {
+ int size;
+ int cap;
+ int* ptr;
+} veci;
+
+#define veci_new(v) \
+{ (v)->size = 0; \
+ (v)->cap = 4; \
+ (v)->ptr = (int*)malloc(sizeof(int)*(v)->cap); \
+}
+
+#define veci_delete(v) free((v)->ptr)
+
+#define veci_begin(v) ((v)->ptr)
+
+#define veci_size(v) ((v)->size)
+
+#define veci_resize(v, k) (void)((v)->size = (k))
+/* only safe to shrink !! */
+
+#define veci_push(v, e) \
+{ if ((v)->size == (v)->cap) \
+ { int newsize = (v)->cap * 2+1; \
+ (v)->ptr = (int*)realloc((v)->ptr,sizeof(int)*newsize); \
+ (v)->cap = newsize; \
+ } \
+ (v)->ptr[(v)->size++] = (e); \
+}
+
+/* vector of 32- or 64-bit pointers */
+typedef struct /* vecp_t */ {
+ int size;
+ int cap;
+ void** ptr;
+} vecp;
+
+#define vecp_new(v) \
+{ (v)->size = 0; \
+ (v)->cap = 4; \
+ (v)->ptr = (void**)malloc(sizeof(void*)*(v)->cap); \
+}
+
+#define vecp_delete(v) free((v)->ptr)
+
+#define vecp_begin(v) ((v)->ptr)
+
+#define vecp_size(v) ((v)->size)
+
+#define vecp_resize(v, k) (void)((v)->size = (k))
+/* only safe to shrink !! */
+
+#define vecp_push(v, e) \
+{ if ((v)->size == (v)->cap) \
+ { int newsize = (v)->cap * 2+1; \
+ (v)->ptr = (void**)realloc((v)->ptr,sizeof(void*)*newsize); \
+ (v)->cap = newsize; \
+ } \
+ (v)->ptr[(v)->size++] = (e); \
+}
+
+/*====================================================================*/
+/* Solver representation: */
+
+typedef struct /* clause_t */
+{
+ int size_learnt;
+ lit lits[1];
+} clause;
+
+typedef struct /* stats_t */
+{
+ double starts, decisions, propagations, inspects, conflicts;
+ double clauses, clauses_literals, learnts, learnts_literals,
+ max_literals, tot_literals;
+} stats;
+
+typedef struct /* solver_t */
+{
+ int size; /* nof variables */
+ int cap; /* size of varmaps */
+ int qhead; /* Head index of queue. */
+ int qtail; /* Tail index of queue. */
+
+ /* clauses */
+ vecp clauses; /* List of problem constraints.
+ (contains: clause*) */
+ vecp learnts; /* List of learnt clauses.
+ (contains: clause*) */
+
+ /* activities */
+ double var_inc; /* Amount to bump next variable with. */
+ double var_decay; /* INVERSE decay factor for variable
+ activity: stores 1/decay. */
+ float cla_inc; /* Amount to bump next clause with. */
+ float cla_decay; /* INVERSE decay factor for clause
+ activity: stores 1/decay. */
+
+ vecp* wlists;
+ double* activity; /* A heuristic measurement of the activity
+ of a variable. */
+ lbool* assigns; /* Current values of variables. */
+ int* orderpos; /* Index in variable order. */
+ clause** reasons;
+ int* levels;
+ lit* trail;
+
+ clause* binary; /* A temporary binary clause */
+ lbool* tags;
+ veci tagged; /* (contains: var) */
+ veci stack; /* (contains: var) */
+
+ veci order; /* Variable order. (heap) (contains: var) */
+ veci trail_lim; /* Separator indices for different decision
+ levels in 'trail'. (contains: int) */
+ veci model; /* If problem is solved, this vector
+ contains the model (contains: lbool). */
+
+ int root_level; /* Level of first proper decision. */
+ int simpdb_assigns;/* Number of top-level assignments at last
+ 'simplifyDB()'. */
+ int simpdb_props; /* Number of propagations before next
+ 'simplifyDB()'. */
+ double random_seed;
+ double progress_estimate;
+ int verbosity; /* Verbosity level.
+ 0=silent,
+ 1=some progress report,
+ 2=everything */
+
+ stats stats;
+} solver;
+
+/*====================================================================*/
+/* Public interface: */
+
+#if 1 /* by mao; to keep namespace clean */
+#define solver_new _glp_minisat_new
+#define solver_delete _glp_minisat_delete
+#define solver_addclause _glp_minisat_addclause
+#define solver_simplify _glp_minisat_simplify
+#define solver_solve _glp_minisat_solve
+#define solver_nvars _glp_minisat_nvars
+#define solver_nclauses _glp_minisat_nclauses
+#define solver_nconflicts _glp_minisat_nconflicts
+#define solver_setnvars _glp_minisat_setnvars
+#define solver_propagate _glp_minisat_propagate
+#define solver_reducedb _glp_minisat_reducedb
+#endif
+
+solver* solver_new(void);
+void solver_delete(solver* s);
+
+bool solver_addclause(solver* s, lit* begin, lit* end);
+bool solver_simplify(solver* s);
+bool solver_solve(solver* s, lit* begin, lit* end);
+
+int solver_nvars(solver* s);
+int solver_nclauses(solver* s);
+int solver_nconflicts(solver* s);
+
+void solver_setnvars(solver* s,int n);
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/avl.c b/test/monniaux/glpk-4.65/src/misc/avl.c
new file mode 100644
index 00000000..c97cf13a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/avl.c
@@ -0,0 +1,405 @@
+/* avl.c (binary search tree) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "avl.h"
+#include "dmp.h"
+#include "env.h"
+
+struct AVL
+{ /* AVL tree (Adelson-Velsky & Landis binary search tree) */
+ DMP *pool;
+ /* memory pool for allocating nodes */
+ AVLNODE *root;
+ /* pointer to the root node */
+ int (*fcmp)(void *info, const void *key1, const void *key2);
+ /* application-defined key comparison routine */
+ void *info;
+ /* transit pointer passed to the routine fcmp */
+ int size;
+ /* the tree size (the total number of nodes) */
+ int height;
+ /* the tree height */
+};
+
+struct AVLNODE
+{ /* node of AVL tree */
+ const void *key;
+ /* pointer to the node key (data structure for representing keys
+ is supplied by the application) */
+ int rank;
+ /* node rank = relative position of the node in its own subtree =
+ the number of nodes in the left subtree plus one */
+ int type;
+ /* reserved for the application specific information */
+ void *link;
+ /* reserved for the application specific information */
+ AVLNODE *up;
+ /* pointer to the parent node */
+ short int flag;
+ /* node flag:
+ 0 - this node is the left child of its parent (or this node is
+ the root of the tree and has no parent)
+ 1 - this node is the right child of its parent */
+ short int bal;
+ /* node balance = the difference between heights of the right and
+ left subtrees:
+ -1 - the left subtree is higher than the right one;
+ 0 - the left and right subtrees have the same height;
+ +1 - the left subtree is lower than the right one */
+ AVLNODE *left;
+ /* pointer to the root of the left subtree */
+ AVLNODE *right;
+ /* pointer to the root of the right subtree */
+};
+
+AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
+ const void *key2), void *info)
+{ /* create AVL tree */
+ AVL *tree;
+ tree = xmalloc(sizeof(AVL));
+ tree->pool = dmp_create_pool();
+ tree->root = NULL;
+ tree->fcmp = fcmp;
+ tree->info = info;
+ tree->size = 0;
+ tree->height = 0;
+ return tree;
+}
+
+int avl_strcmp(void *info, const void *key1, const void *key2)
+{ /* compare character string keys */
+ xassert(info == info);
+ return strcmp(key1, key2);
+}
+
+static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node);
+
+AVLNODE *avl_insert_node(AVL *tree, const void *key)
+{ /* insert new node into AVL tree */
+ AVLNODE *p, *q, *r;
+ short int flag;
+ /* find an appropriate point for insertion */
+ p = NULL; q = tree->root;
+ while (q != NULL)
+ { p = q;
+ if (tree->fcmp(tree->info, key, p->key) <= 0)
+ { flag = 0;
+ q = p->left;
+ p->rank++;
+ }
+ else
+ { flag = 1;
+ q = p->right;
+ }
+ }
+ /* create new node and insert it into the tree */
+ r = dmp_get_atom(tree->pool, sizeof(AVLNODE));
+ r->key = key; r->type = 0; r->link = NULL;
+ r->rank = 1; r->up = p;
+ r->flag = (short int)(p == NULL ? 0 : flag);
+ r->bal = 0; r->left = NULL; r->right = NULL;
+ tree->size++;
+ if (p == NULL)
+ tree->root = r;
+ else
+ if (flag == 0) p->left = r; else p->right = r;
+ /* go upstairs to the root and correct all subtrees affected by
+ insertion */
+ while (p != NULL)
+ { if (flag == 0)
+ { /* the height of the left subtree of [p] is increased */
+ if (p->bal > 0)
+ { p->bal = 0;
+ break;
+ }
+ if (p->bal < 0)
+ { rotate_subtree(tree, p);
+ break;
+ }
+ p->bal = -1; flag = p->flag; p = p->up;
+ }
+ else
+ { /* the height of the right subtree of [p] is increased */
+ if (p->bal < 0)
+ { p->bal = 0;
+ break;
+ }
+ if (p->bal > 0)
+ { rotate_subtree(tree, p);
+ break;
+ }
+ p->bal = +1; flag = p->flag; p = p->up;
+ }
+ }
+ /* if the root has been reached, the height of the entire tree is
+ increased */
+ if (p == NULL) tree->height++;
+ return r;
+}
+
+void avl_set_node_type(AVLNODE *node, int type)
+{ /* assign the type field of specified node */
+ node->type = type;
+ return;
+}
+
+void avl_set_node_link(AVLNODE *node, void *link)
+{ /* assign the link field of specified node */
+ node->link = link;
+ return;
+}
+
+AVLNODE *avl_find_node(AVL *tree, const void *key)
+{ /* find node in AVL tree */
+ AVLNODE *p;
+ int c;
+ p = tree->root;
+ while (p != NULL)
+ { c = tree->fcmp(tree->info, key, p->key);
+ if (c == 0) break;
+ p = (c < 0 ? p->left : p->right);
+ }
+ return p;
+}
+
+int avl_get_node_type(AVLNODE *node)
+{ /* retrieve the type field of specified node */
+ return node->type;
+}
+
+void *avl_get_node_link(AVLNODE *node)
+{ /* retrieve the link field of specified node */
+ return node->link;
+}
+
+static AVLNODE *find_next_node(AVL *tree, AVLNODE *node)
+{ /* find next node in AVL tree */
+ AVLNODE *p, *q;
+ if (tree->root == NULL) return NULL;
+ p = node;
+ q = (p == NULL ? tree->root : p->right);
+ if (q == NULL)
+ { /* go upstairs from the left subtree */
+ for (;;)
+ { q = p->up;
+ if (q == NULL) break;
+ if (p->flag == 0) break;
+ p = q;
+ }
+ }
+ else
+ { /* go downstairs into the right subtree */
+ for (;;)
+ { p = q->left;
+ if (p == NULL) break;
+ q = p;
+ }
+ }
+ return q;
+}
+
+void avl_delete_node(AVL *tree, AVLNODE *node)
+{ /* delete specified node from AVL tree */
+ AVLNODE *f, *p, *q, *r, *s, *x, *y;
+ short int flag;
+ p = node;
+ /* if both subtrees of the specified node are non-empty, the node
+ should be interchanged with the next one, at least one subtree
+ of which is always empty */
+ if (p->left == NULL || p->right == NULL) goto skip;
+ f = p->up; q = p->left;
+ r = find_next_node(tree, p); s = r->right;
+ if (p->right == r)
+ { if (f == NULL)
+ tree->root = r;
+ else
+ if (p->flag == 0) f->left = r; else f->right = r;
+ r->rank = p->rank; r->up = f;
+ r->flag = p->flag; r->bal = p->bal;
+ r->left = q; r->right = p;
+ q->up = r;
+ p->rank = 1; p->up = r; p->flag = 1;
+ p->bal = (short int)(s == NULL ? 0 : +1);
+ p->left = NULL; p->right = s;
+ if (s != NULL) s->up = p;
+ }
+ else
+ { x = p->right; y = r->up;
+ if (f == NULL)
+ tree->root = r;
+ else
+ if (p->flag == 0) f->left = r; else f->right = r;
+ r->rank = p->rank; r->up = f;
+ r->flag = p->flag; r->bal = p->bal;
+ r->left = q; r->right = x;
+ q->up = r; x->up = r; y->left = p;
+ p->rank = 1; p->up = y; p->flag = 0;
+ p->bal = (short int)(s == NULL ? 0 : +1);
+ p->left = NULL; p->right = s;
+ if (s != NULL) s->up = p;
+ }
+skip: /* now the specified node [p] has at least one empty subtree;
+ go upstairs to the root and adjust the rank field of all nodes
+ affected by deletion */
+ q = p; f = q->up;
+ while (f != NULL)
+ { if (q->flag == 0) f->rank--;
+ q = f; f = q->up;
+ }
+ /* delete the specified node from the tree */
+ f = p->up; flag = p->flag;
+ q = p->left != NULL ? p->left : p->right;
+ if (f == NULL)
+ tree->root = q;
+ else
+ if (flag == 0) f->left = q; else f->right = q;
+ if (q != NULL) q->up = f, q->flag = flag;
+ tree->size--;
+ /* go upstairs to the root and correct all subtrees affected by
+ deletion */
+ while (f != NULL)
+ { if (flag == 0)
+ { /* the height of the left subtree of [f] is decreased */
+ if (f->bal == 0)
+ { f->bal = +1;
+ break;
+ }
+ if (f->bal < 0)
+ f->bal = 0;
+ else
+ { f = rotate_subtree(tree, f);
+ if (f->bal < 0) break;
+ }
+ flag = f->flag; f = f->up;
+ }
+ else
+ { /* the height of the right subtree of [f] is decreased */
+ if (f->bal == 0)
+ { f->bal = -1;
+ break;
+ }
+ if (f->bal > 0)
+ f->bal = 0;
+ else
+ { f = rotate_subtree(tree, f);
+ if (f->bal > 0) break;
+ }
+ flag = f->flag; f = f->up;
+ }
+ }
+ /* if the root has been reached, the height of the entire tree is
+ decreased */
+ if (f == NULL) tree->height--;
+ /* returns the deleted node to the memory pool */
+ dmp_free_atom(tree->pool, p, sizeof(AVLNODE));
+ return;
+}
+
+static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node)
+{ /* restore balance of AVL subtree */
+ AVLNODE *f, *p, *q, *r, *x, *y;
+ xassert(node != NULL);
+ p = node;
+ if (p->bal < 0)
+ { /* perform negative (left) rotation */
+ f = p->up; q = p->left; r = q->right;
+ if (q->bal <= 0)
+ { /* perform single negative rotation */
+ if (f == NULL)
+ tree->root = q;
+ else
+ if (p->flag == 0) f->left = q; else f->right = q;
+ p->rank -= q->rank;
+ q->up = f; q->flag = p->flag; q->bal++; q->right = p;
+ p->up = q; p->flag = 1;
+ p->bal = (short int)(-q->bal); p->left = r;
+ if (r != NULL) r->up = p, r->flag = 0;
+ node = q;
+ }
+ else
+ { /* perform double negative rotation */
+ x = r->left; y = r->right;
+ if (f == NULL)
+ tree->root = r;
+ else
+ if (p->flag == 0) f->left = r; else f->right = r;
+ p->rank -= (q->rank + r->rank);
+ r->rank += q->rank;
+ p->bal = (short int)(r->bal >= 0 ? 0 : +1);
+ q->bal = (short int)(r->bal <= 0 ? 0 : -1);
+ r->up = f; r->flag = p->flag; r->bal = 0;
+ r->left = q; r->right = p;
+ p->up = r; p->flag = 1; p->left = y;
+ q->up = r; q->flag = 0; q->right = x;
+ if (x != NULL) x->up = q, x->flag = 1;
+ if (y != NULL) y->up = p, y->flag = 0;
+ node = r;
+ }
+ }
+ else
+ { /* perform positive (right) rotation */
+ f = p->up; q = p->right; r = q->left;
+ if (q->bal >= 0)
+ { /* perform single positive rotation */
+ if (f == NULL)
+ tree->root = q;
+ else
+ if (p->flag == 0) f->left = q; else f->right = q;
+ q->rank += p->rank;
+ q->up = f; q->flag = p->flag; q->bal--; q->left = p;
+ p->up = q; p->flag = 0;
+ p->bal = (short int)(-q->bal); p->right = r;
+ if (r != NULL) r->up = p, r->flag = 1;
+ node = q;
+ }
+ else
+ { /* perform double positive rotation */
+ x = r->left; y = r->right;
+ if (f == NULL)
+ tree->root = r;
+ else
+ if (p->flag == 0) f->left = r; else f->right = r;
+ q->rank -= r->rank;
+ r->rank += p->rank;
+ p->bal = (short int)(r->bal <= 0 ? 0 : -1);
+ q->bal = (short int)(r->bal >= 0 ? 0 : +1);
+ r->up = f; r->flag = p->flag; r->bal = 0;
+ r->left = p; r->right = q;
+ p->up = r; p->flag = 0; p->right = x;
+ q->up = r; q->flag = 1; q->left = y;
+ if (x != NULL) x->up = p, x->flag = 1;
+ if (y != NULL) y->up = q, y->flag = 0;
+ node = r;
+ }
+ }
+ return node;
+}
+
+void avl_delete_tree(AVL *tree)
+{ /* delete AVL tree */
+ dmp_delete_pool(tree->pool);
+ xfree(tree);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/avl.h b/test/monniaux/glpk-4.65/src/misc/avl.h
new file mode 100644
index 00000000..b0aaef61
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/avl.h
@@ -0,0 +1,73 @@
+/* avl.h (binary search tree) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#ifndef AVL_H
+#define AVL_H
+
+typedef struct AVL AVL;
+typedef struct AVLNODE AVLNODE;
+
+#define avl_create_tree _glp_avl_create_tree
+AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
+ const void *key2), void *info);
+/* create AVL tree */
+
+#define avl_strcmp _glp_avl_strcmp
+int avl_strcmp(void *info, const void *key1, const void *key2);
+/* compare character string keys */
+
+#define avl_insert_node _glp_avl_insert_node
+AVLNODE *avl_insert_node(AVL *tree, const void *key);
+/* insert new node into AVL tree */
+
+#define avl_set_node_type _glp_avl_set_node_type
+void avl_set_node_type(AVLNODE *node, int type);
+/* assign the type field of specified node */
+
+#define avl_set_node_link _glp_avl_set_node_link
+void avl_set_node_link(AVLNODE *node, void *link);
+/* assign the link field of specified node */
+
+#define avl_find_node _glp_avl_find_node
+AVLNODE *avl_find_node(AVL *tree, const void *key);
+/* find node in AVL tree */
+
+#define avl_get_node_type _glp_avl_get_node_type
+int avl_get_node_type(AVLNODE *node);
+/* retrieve the type field of specified node */
+
+#define avl_get_node_link _glp_avl_get_node_link
+void *avl_get_node_link(AVLNODE *node);
+/* retrieve the link field of specified node */
+
+#define avl_delete_node _glp_avl_delete_node
+void avl_delete_node(AVL *tree, AVLNODE *node);
+/* delete specified node from AVL tree */
+
+#define avl_delete_tree _glp_avl_delete_tree
+void avl_delete_tree(AVL *tree);
+/* delete AVL tree */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/bignum.c b/test/monniaux/glpk-4.65/src/misc/bignum.c
new file mode 100644
index 00000000..540dd9fd
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/bignum.c
@@ -0,0 +1,286 @@
+/* bignum.c (bignum arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2006-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "bignum.h"
+
+/***********************************************************************
+* Two routines below are intended to multiply and divide unsigned
+* integer numbers of arbitrary precision.
+*
+* The routines assume that an unsigned integer number is represented in
+* the positional numeral system with the base 2^16 = 65536, i.e. each
+* "digit" of the number is in the range [0, 65535] and represented as
+* a 16-bit value of the unsigned short type. In other words, a number x
+* has the following representation:
+*
+* n-1
+* x = sum d[j] * 65536^j,
+* j=0
+*
+* where n is the number of places (positions), and d[j] is j-th "digit"
+* of x, 0 <= d[j] <= 65535.
+***********************************************************************/
+
+/***********************************************************************
+* NAME
+*
+* bigmul - multiply unsigned integer numbers of arbitrary precision
+*
+* SYNOPSIS
+*
+* #include "bignum.h"
+* void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
+*
+* DESCRIPTION
+*
+* The routine bigmul multiplies unsigned integer numbers of arbitrary
+* precision.
+*
+* n is the number of digits of multiplicand, n >= 1;
+*
+* m is the number of digits of multiplier, m >= 1;
+*
+* x is an array containing digits of the multiplicand in elements
+* x[m], x[m+1], ..., x[n+m-1]. Contents of x[0], x[1], ..., x[m-1] are
+* ignored on entry.
+*
+* y is an array containing digits of the multiplier in elements y[0],
+* y[1], ..., y[m-1].
+*
+* On exit digits of the product are stored in elements x[0], x[1], ...,
+* x[n+m-1]. The array y is not changed. */
+
+void bigmul(int n, int m, unsigned short x[], unsigned short y[])
+{ int i, j;
+ unsigned int t;
+ xassert(n >= 1);
+ xassert(m >= 1);
+ for (j = 0; j < m; j++) x[j] = 0;
+ for (i = 0; i < n; i++)
+ { if (x[i+m])
+ { t = 0;
+ for (j = 0; j < m; j++)
+ { t += (unsigned int)x[i+m] * (unsigned int)y[j] +
+ (unsigned int)x[i+j];
+ x[i+j] = (unsigned short)t;
+ t >>= 16;
+ }
+ x[i+m] = (unsigned short)t;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* bigdiv - divide unsigned integer numbers of arbitrary precision
+*
+* SYNOPSIS
+*
+* #include "bignum.h"
+* void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
+*
+* DESCRIPTION
+*
+* The routine bigdiv divides one unsigned integer number of arbitrary
+* precision by another with the algorithm described in [1].
+*
+* n is the difference between the number of digits of dividend and the
+* number of digits of divisor, n >= 0.
+*
+* m is the number of digits of divisor, m >= 1.
+*
+* x is an array containing digits of the dividend in elements x[0],
+* x[1], ..., x[n+m-1].
+*
+* y is an array containing digits of the divisor in elements y[0],
+* y[1], ..., y[m-1]. The highest digit y[m-1] must be non-zero.
+*
+* On exit n+1 digits of the quotient are stored in elements x[m],
+* x[m+1], ..., x[n+m], and m digits of the remainder are stored in
+* elements x[0], x[1], ..., x[m-1]. The array y is changed but then
+* restored.
+*
+* REFERENCES
+*
+* 1. D. Knuth. The Art of Computer Programming. Vol. 2: Seminumerical
+* Algorithms. Stanford University, 1969. */
+
+void bigdiv(int n, int m, unsigned short x[], unsigned short y[])
+{ int i, j;
+ unsigned int t;
+ unsigned short d, q, r;
+ xassert(n >= 0);
+ xassert(m >= 1);
+ xassert(y[m-1] != 0);
+ /* special case when divisor has the only digit */
+ if (m == 1)
+ { d = 0;
+ for (i = n; i >= 0; i--)
+ { t = ((unsigned int)d << 16) + (unsigned int)x[i];
+ x[i+1] = (unsigned short)(t / y[0]);
+ d = (unsigned short)(t % y[0]);
+ }
+ x[0] = d;
+ goto done;
+ }
+ /* multiply dividend and divisor by a normalizing coefficient in
+ * order to provide the condition y[m-1] >= base / 2 */
+ d = (unsigned short)(0x10000 / ((unsigned int)y[m-1] + 1));
+ if (d == 1)
+ x[n+m] = 0;
+ else
+ { t = 0;
+ for (i = 0; i < n+m; i++)
+ { t += (unsigned int)x[i] * (unsigned int)d;
+ x[i] = (unsigned short)t;
+ t >>= 16;
+ }
+ x[n+m] = (unsigned short)t;
+ t = 0;
+ for (j = 0; j < m; j++)
+ { t += (unsigned int)y[j] * (unsigned int)d;
+ y[j] = (unsigned short)t;
+ t >>= 16;
+ }
+ }
+ /* main loop */
+ for (i = n; i >= 0; i--)
+ { /* estimate and correct the current digit of quotient */
+ if (x[i+m] < y[m-1])
+ { t = ((unsigned int)x[i+m] << 16) + (unsigned int)x[i+m-1];
+ q = (unsigned short)(t / (unsigned int)y[m-1]);
+ r = (unsigned short)(t % (unsigned int)y[m-1]);
+ if (q == 0) goto putq; else goto test;
+ }
+ q = 0;
+ r = x[i+m-1];
+decr: q--; /* if q = 0 then q-- = 0xFFFF */
+ t = (unsigned int)r + (unsigned int)y[m-1];
+ r = (unsigned short)t;
+ if (t > 0xFFFF) goto msub;
+test: t = (unsigned int)y[m-2] * (unsigned int)q;
+ if ((unsigned short)(t >> 16) > r) goto decr;
+ if ((unsigned short)(t >> 16) < r) goto msub;
+ if ((unsigned short)t > x[i+m-2]) goto decr;
+msub: /* now subtract divisor multiplied by the current digit of
+ * quotient from the current dividend */
+ if (q == 0) goto putq;
+ t = 0;
+ for (j = 0; j < m; j++)
+ { t += (unsigned int)y[j] * (unsigned int)q;
+ if (x[i+j] < (unsigned short)t) t += 0x10000;
+ x[i+j] -= (unsigned short)t;
+ t >>= 16;
+ }
+ if (x[i+m] >= (unsigned short)t) goto putq;
+ /* perform correcting addition, because the current digit of
+ * quotient is greater by one than its correct value */
+ q--;
+ t = 0;
+ for (j = 0; j < m; j++)
+ { t += (unsigned int)x[i+j] + (unsigned int)y[j];
+ x[i+j] = (unsigned short)t;
+ t >>= 16;
+ }
+putq: /* store the current digit of quotient */
+ x[i+m] = q;
+ }
+ /* divide divisor and remainder by the normalizing coefficient in
+ * order to restore their original values */
+ if (d > 1)
+ { t = 0;
+ for (i = m-1; i >= 0; i--)
+ { t = (t << 16) + (unsigned int)x[i];
+ x[i] = (unsigned short)(t / (unsigned int)d);
+ t %= (unsigned int)d;
+ }
+ t = 0;
+ for (j = m-1; j >= 0; j--)
+ { t = (t << 16) + (unsigned int)y[j];
+ y[j] = (unsigned short)(t / (unsigned int)d);
+ t %= (unsigned int)d;
+ }
+ }
+done: return;
+}
+
+/**********************************************************************/
+
+#ifdef GLP_TEST
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "rng.h"
+
+#define N_MAX 7
+/* maximal number of digits in multiplicand */
+
+#define M_MAX 5
+/* maximal number of digits in multiplier */
+
+#define N_TEST 1000000
+/* number of tests */
+
+int main(void)
+{ RNG *rand;
+ int d, j, n, m, test;
+ unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX];
+ rand = rng_create_rand();
+ for (test = 1; test <= N_TEST; test++)
+ { /* x[0,...,n-1] := multiplicand */
+ n = 1 + rng_unif_rand(rand, N_MAX-1);
+ assert(1 <= n && n <= N_MAX);
+ for (j = 0; j < n; j++)
+ { d = rng_unif_rand(rand, 65536);
+ assert(0 <= d && d <= 65535);
+ x[j] = (unsigned short)d;
+ }
+ /* y[0,...,m-1] := multiplier */
+ m = 1 + rng_unif_rand(rand, M_MAX-1);
+ assert(1 <= m && m <= M_MAX);
+ for (j = 0; j < m; j++)
+ { d = rng_unif_rand(rand, 65536);
+ assert(0 <= d && d <= 65535);
+ y[j] = (unsigned short)d;
+ }
+ if (y[m-1] == 0) y[m-1] = 1;
+ /* z[0,...,n+m-1] := x * y */
+ for (j = 0; j < n; j++) z[m+j] = x[j];
+ bigmul(n, m, z, y);
+ /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */
+ bigdiv(n, m, z, y);
+ /* z mod y must be 0 */
+ for (j = 0; j < m; j++) assert(z[j] == 0);
+ /* z div y must be x */
+ for (j = 0; j < n; j++) assert(z[m+j] == x[j]);
+ }
+ fprintf(stderr, "%d tests successfully passed\n", N_TEST);
+ rng_delete_rand(rand);
+ return 0;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/bignum.h b/test/monniaux/glpk-4.65/src/misc/bignum.h
new file mode 100644
index 00000000..8567519b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/bignum.h
@@ -0,0 +1,37 @@
+/* bignum.h (bignum arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2006-2013 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/>.
+***********************************************************************/
+
+#ifndef BIGNUM_H
+#define BIGNUM_H
+
+#define bigmul _glp_bigmul
+void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
+/* multiply unsigned integer numbers of arbitrary precision */
+
+#define bigdiv _glp_bigdiv
+void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
+/* divide unsigned integer numbers of arbitrary precision */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/dimacs.c b/test/monniaux/glpk-4.65/src/misc/dimacs.c
new file mode 100644
index 00000000..6aa630a5
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/dimacs.c
@@ -0,0 +1,147 @@
+/* dimacs.c (reading data in DIMACS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2015 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/>.
+***********************************************************************/
+
+#include "dimacs.h"
+
+void dmx_error(DMX *csa, const char *fmt, ...)
+{ /* print error message and terminate processing */
+ va_list arg;
+ xprintf("%s:%d: error: ", csa->fname, csa->count);
+ va_start(arg, fmt);
+ xvprintf(fmt, arg);
+ va_end(arg);
+ xprintf("\n");
+ longjmp(csa->jump, 1);
+ /* no return */
+}
+
+void dmx_warning(DMX *csa, const char *fmt, ...)
+{ /* print warning message and continue processing */
+ va_list arg;
+ xprintf("%s:%d: warning: ", csa->fname, csa->count);
+ va_start(arg, fmt);
+ xvprintf(fmt, arg);
+ va_end(arg);
+ xprintf("\n");
+ return;
+}
+
+void dmx_read_char(DMX *csa)
+{ /* read character from input text file */
+ int c;
+ if (csa->c == '\n') csa->count++;
+ c = glp_getc(csa->fp);
+ if (c < 0)
+ { if (glp_ioerr(csa->fp))
+ dmx_error(csa, "read error - %s", get_err_msg());
+ else if (csa->c == '\n')
+ dmx_error(csa, "unexpected end of file");
+ else
+ { dmx_warning(csa, "missing final end of line");
+ c = '\n';
+ }
+ }
+ else if (c == '\n')
+ ;
+ else if (isspace(c))
+ c = ' ';
+ else if (iscntrl(c))
+ dmx_error(csa, "invalid control character 0x%02X", c);
+ csa->c = c;
+ return;
+}
+
+void dmx_read_designator(DMX *csa)
+{ /* read one-character line designator */
+ xassert(csa->c == '\n');
+ dmx_read_char(csa);
+ for (;;)
+ { /* skip preceding white-space characters */
+ while (csa->c == ' ')
+ dmx_read_char(csa);
+ if (csa->c == '\n')
+ { /* ignore empty line */
+ if (!csa->empty)
+ { dmx_warning(csa, "empty line ignored");
+ csa->empty = 1;
+ }
+ dmx_read_char(csa);
+ }
+ else if (csa->c == 'c')
+ { /* skip comment line */
+ while (csa->c != '\n')
+ dmx_read_char(csa);
+ dmx_read_char(csa);
+ }
+ else
+ { /* hmm... looks like a line designator */
+ csa->field[0] = (char)csa->c, csa->field[1] = '\0';
+ /* check that it is followed by a white-space character */
+ dmx_read_char(csa);
+ if (!(csa->c == ' ' || csa->c == '\n'))
+ dmx_error(csa, "line designator missing or invalid");
+ break;
+ }
+ }
+ return;
+}
+
+void dmx_read_field(DMX *csa)
+{ /* read data field */
+ int len = 0;
+ /* skip preceding white-space characters */
+ while (csa->c == ' ')
+ dmx_read_char(csa);
+ /* scan data field */
+ if (csa->c == '\n')
+ dmx_error(csa, "unexpected end of line");
+ while (!(csa->c == ' ' || csa->c == '\n'))
+ { if (len == sizeof(csa->field)-1)
+ dmx_error(csa, "data field '%.15s...' too long",
+ csa->field);
+ csa->field[len++] = (char)csa->c;
+ dmx_read_char(csa);
+ }
+ csa->field[len] = '\0';
+ return;
+}
+
+void dmx_end_of_line(DMX *csa)
+{ /* skip white-space characters until end of line */
+ while (csa->c == ' ')
+ dmx_read_char(csa);
+ if (csa->c != '\n')
+ dmx_error(csa, "too many data fields specified");
+ return;
+}
+
+void dmx_check_int(DMX *csa, double num)
+{ /* print a warning if non-integer data are detected */
+ if (!csa->nonint && num != floor(num))
+ { dmx_warning(csa, "non-integer data detected");
+ csa->nonint = 1;
+ }
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/dimacs.h b/test/monniaux/glpk-4.65/src/misc/dimacs.h
new file mode 100644
index 00000000..42fb9996
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/dimacs.h
@@ -0,0 +1,81 @@
+/* dimacs.h (reading data in DIMACS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2015 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/>.
+***********************************************************************/
+
+#ifndef DIMACS_H
+#define DIMACS_H
+
+#include "env.h"
+
+typedef struct DMX DMX;
+
+struct DMX
+{ /* DIMACS data reader */
+ jmp_buf jump;
+ /* label for go to in case of error */
+ const char *fname;
+ /* name of input text file */
+ glp_file *fp;
+ /* stream assigned to input text file */
+ int count;
+ /* line count */
+ int c;
+ /* current character */
+ char field[255+1];
+ /* data field */
+ int empty;
+ /* warning 'empty line ignored' was printed */
+ int nonint;
+ /* warning 'non-integer data detected' was printed */
+};
+
+#define dmx_error _glp_dmx_error
+void dmx_error(DMX *csa, const char *fmt, ...);
+/* print error message and terminate processing */
+
+#define dmx_warning _glp_dmx_warning
+void dmx_warning(DMX *csa, const char *fmt, ...);
+/* print warning message and continue processing */
+
+#define dmx_read_char _glp_dmx_read_char
+void dmx_read_char(DMX *csa);
+/* read character from input text file */
+
+#define dmx_read_designator _glp_dmx_read_designator
+void dmx_read_designator(DMX *csa);
+/* read one-character line designator */
+
+#define dmx_read_field _glp_dmx_read_field
+void dmx_read_field(DMX *csa);
+/* read data field */
+
+#define dmx_end_of_line _glp_dmx_end_of_line
+void dmx_end_of_line(DMX *csa);
+/* skip white-space characters until end of line */
+
+#define dmx_check_int _glp_dmx_check_int
+void dmx_check_int(DMX *csa, double num);
+/* print a warning if non-integer data are detected */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/dmp.c b/test/monniaux/glpk-4.65/src/misc/dmp.c
new file mode 100644
index 00000000..a4882c86
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/dmp.c
@@ -0,0 +1,243 @@
+/* dmp.c (dynamic memory pool) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "dmp.h"
+
+struct DMP
+{ /* dynamic memory pool */
+ void *avail[32];
+ /* avail[k], 0 <= k <= 31, is a pointer to first available (free)
+ * atom of (k+1)*8 bytes long; at the beginning of each free atom
+ * there is a pointer to another free atom of the same size */
+ void *block;
+ /* pointer to most recently allocated memory block; at the
+ * beginning of each allocated memory block there is a pointer to
+ * previously allocated memory block */
+ int used;
+ /* number of bytes used in most recently allocated memory block */
+ size_t count;
+ /* number of atoms which are currently in use */
+};
+
+#define DMP_BLK_SIZE 8000
+/* size of memory blocks, in bytes, allocated for memory pools */
+
+struct prefix
+{ /* atom prefix (for debugging only) */
+ DMP *pool;
+ /* dynamic memory pool */
+ int size;
+ /* original atom size, in bytes */
+};
+
+#define prefix_size ((sizeof(struct prefix) + 7) & ~7)
+/* size of atom prefix rounded up to multiple of 8 bytes */
+
+int dmp_debug;
+/* debug mode flag */
+
+/***********************************************************************
+* NAME
+*
+* dmp_create_pool - create dynamic memory pool
+*
+* SYNOPSIS
+*
+* #include "dmp.h"
+* DMP *dmp_create_pool(void);
+*
+* DESCRIPTION
+*
+* The routine dmp_create_pool creates a dynamic memory pool.
+*
+* RETURNS
+*
+* The routine returns a pointer to the memory pool created. */
+
+DMP *dmp_create_pool(void)
+{ DMP *pool;
+ int k;
+ xassert(sizeof(void *) <= 8);
+ if (dmp_debug)
+ xprintf("dmp_create_pool: warning: debug mode is on\n");
+ pool = talloc(1, DMP);
+ for (k = 0; k <= 31; k++)
+ pool->avail[k] = NULL;
+ pool->block = NULL;
+ pool->used = DMP_BLK_SIZE;
+ pool->count = 0;
+ return pool;
+}
+
+/***********************************************************************
+* NAME
+*
+* dmp_get_atom - get free atom from dynamic memory pool
+*
+* SYNOPSIS
+*
+* #include "dmp.h"
+* void *dmp_get_atom(DMP *pool, int size);
+*
+* DESCRIPTION
+*
+* The routine dmp_get_atom obtains a free atom (memory space) from the
+* specified memory pool.
+*
+* The parameter size is the atom size, in bytes, 1 <= size <= 256.
+*
+* Note that the free atom contains arbitrary data, not binary zeros.
+*
+* RETURNS
+*
+* The routine returns a pointer to the free atom obtained. */
+
+void *dmp_get_atom(DMP *pool, int size)
+{ void *atom;
+ int k, need;
+ xassert(1 <= size && size <= 256);
+ /* round up atom size to multiple of 8 bytes */
+ need = (size + 7) & ~7;
+ /* determine number of corresponding list of free atoms */
+ k = (need >> 3) - 1;
+ /* obtain free atom */
+ if (pool->avail[k] == NULL)
+ { /* corresponding list of free atoms is empty */
+ /* if debug mode is on, add atom prefix size */
+ if (dmp_debug)
+ need += prefix_size;
+ if (pool->used + need > DMP_BLK_SIZE)
+ { /* allocate new memory block */
+ void *block = talloc(DMP_BLK_SIZE, char);
+ *(void **)block = pool->block;
+ pool->block = block;
+ pool->used = 8; /* sufficient to store pointer */
+ }
+ /* allocate new atom in current memory block */
+ atom = (char *)pool->block + pool->used;
+ pool->used += need;
+ }
+ else
+ { /* obtain atom from corresponding list of free atoms */
+ atom = pool->avail[k];
+ pool->avail[k] = *(void **)atom;
+ }
+ /* if debug mode is on, fill atom prefix */
+ if (dmp_debug)
+ { ((struct prefix *)atom)->pool = pool;
+ ((struct prefix *)atom)->size = size;
+ atom = (char *)atom + prefix_size;
+ }
+ /* increase number of allocated atoms */
+ pool->count++;
+ return atom;
+}
+
+/***********************************************************************
+* NAME
+*
+* dmp_free_atom - return atom to dynamic memory pool
+*
+* SYNOPSIS
+*
+* #include "dmp.h"
+* void dmp_free_atom(DMP *pool, void *atom, int size);
+*
+* DESCRIPTION
+*
+* The routine dmp_free_atom returns the specified atom (memory space)
+* to the specified memory pool, making the atom free.
+*
+* The parameter size is the atom size, in bytes, 1 <= size <= 256.
+*
+* Note that the atom can be returned only to the pool, from which it
+* was obtained, and its size must be exactly the same as on obtaining
+* it from the pool. */
+
+void dmp_free_atom(DMP *pool, void *atom, int size)
+{ int k;
+ xassert(1 <= size && size <= 256);
+ /* determine number of corresponding list of free atoms */
+ k = ((size + 7) >> 3) - 1;
+ /* if debug mode is on, check atom prefix */
+ if (dmp_debug)
+ { atom = (char *)atom - prefix_size;
+ xassert(((struct prefix *)atom)->pool == pool);
+ xassert(((struct prefix *)atom)->size == size);
+ }
+ /* return atom to corresponding list of free atoms */
+ *(void **)atom = pool->avail[k];
+ pool->avail[k] = atom;
+ /* decrease number of allocated atoms */
+ xassert(pool->count > 0);
+ pool->count--;
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* dmp_in_use - determine how many atoms are still in use
+*
+* SYNOPSIS
+*
+* #include "dmp.h"
+* size_t dmp_in_use(DMP *pool);
+*
+* RETURNS
+*
+* The routine returns the number of atoms of the specified memory pool
+* which are still in use. */
+
+size_t dmp_in_use(DMP *pool)
+{ return
+ pool->count;
+}
+
+/***********************************************************************
+* NAME
+*
+* dmp_delete_pool - delete dynamic memory pool
+*
+* SYNOPSIS
+*
+* #include "dmp.h"
+* void dmp_delete_pool(DMP *pool);
+*
+* DESCRIPTION
+*
+* The routine dmp_delete_pool deletes the specified dynamic memory
+* pool freeing all the memory allocated to this object. */
+
+void dmp_delete_pool(DMP *pool)
+{ while (pool->block != NULL)
+ { void *block = pool->block;
+ pool->block = *(void **)block;
+ tfree(block);
+ }
+ tfree(pool);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/dmp.h b/test/monniaux/glpk-4.65/src/misc/dmp.h
new file mode 100644
index 00000000..85fe7176
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/dmp.h
@@ -0,0 +1,63 @@
+/* dmp.h (dynamic memory pool) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#ifndef DMP_H
+#define DMP_H
+
+#include "stdc.h"
+
+typedef struct DMP DMP;
+
+#define dmp_debug _glp_dmp_debug
+extern int dmp_debug;
+/* debug mode flag */
+
+#define dmp_create_pool _glp_dmp_create_pool
+DMP *dmp_create_pool(void);
+/* create dynamic memory pool */
+
+#define dmp_talloc(pool, type) \
+ ((type *)dmp_get_atom(pool, sizeof(type)))
+
+#define dmp_get_atom _glp_dmp_get_atom
+void *dmp_get_atom(DMP *pool, int size);
+/* get free atom from dynamic memory pool */
+
+#define dmp_tfree(pool, atom) \
+ dmp_free_atom(pool, atom, sizeof(*(atom)))
+
+#define dmp_free_atom _glp_dmp_free_atom
+void dmp_free_atom(DMP *pool, void *atom, int size);
+/* return atom to dynamic memory pool */
+
+#define dmp_in_use _glp_dmp_in_use
+size_t dmp_in_use(DMP *pool);
+/* determine how many atoms are still in use */
+
+#define dmp_delete_pool _glp_dmp_delete_pool
+void dmp_delete_pool(DMP *pool);
+/* delete dynamic memory pool */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/ffalg.c b/test/monniaux/glpk-4.65/src/misc/ffalg.c
new file mode 100644
index 00000000..4ea2913d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/ffalg.c
@@ -0,0 +1,221 @@
+/* ffalg.c (Ford-Fulkerson algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ffalg.h"
+
+/***********************************************************************
+* NAME
+*
+* ffalg - Ford-Fulkerson algorithm
+*
+* SYNOPSIS
+*
+* #include "ffalg.h"
+* void ffalg(int nv, int na, const int tail[], const int head[],
+* int s, int t, const int cap[], int x[], char cut[]);
+*
+* DESCRIPTION
+*
+* The routine ffalg implements the Ford-Fulkerson algorithm to find a
+* maximal flow in the specified flow network.
+*
+* INPUT PARAMETERS
+*
+* nv is the number of nodes, nv >= 2.
+*
+* na is the number of arcs, na >= 0.
+*
+* tail[a], a = 1,...,na, is the index of tail node of arc a.
+*
+* head[a], a = 1,...,na, is the index of head node of arc a.
+*
+* s is the source node index, 1 <= s <= nv.
+*
+* t is the sink node index, 1 <= t <= nv, t != s.
+*
+* cap[a], a = 1,...,na, is the capacity of arc a, cap[a] >= 0.
+*
+* NOTE: Multiple arcs are allowed, but self-loops are not allowed.
+*
+* OUTPUT PARAMETERS
+*
+* x[a], a = 1,...,na, is optimal value of the flow through arc a.
+*
+* cut[i], i = 1,...,nv, is 1 if node i is labelled, and 0 otherwise.
+* The set of arcs, whose one endpoint is labelled and other is not,
+* defines the minimal cut corresponding to the maximal flow found.
+* If the parameter cut is NULL, the cut information are not stored.
+*
+* REFERENCES
+*
+* L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
+* Corp., Report R-375-PR (August 1962), Chap. I "Static Maximal Flow,"
+* pp.30-33. */
+
+void ffalg(int nv, int na, const int tail[], const int head[],
+ int s, int t, const int cap[], int x[], char cut[])
+{ int a, delta, i, j, k, pos1, pos2, temp,
+ *ptr, *arc, *link, *list;
+ /* sanity checks */
+ xassert(nv >= 2);
+ xassert(na >= 0);
+ xassert(1 <= s && s <= nv);
+ xassert(1 <= t && t <= nv);
+ xassert(s != t);
+ for (a = 1; a <= na; a++)
+ { i = tail[a], j = head[a];
+ xassert(1 <= i && i <= nv);
+ xassert(1 <= j && j <= nv);
+ xassert(i != j);
+ xassert(cap[a] >= 0);
+ }
+ /* allocate working arrays */
+ ptr = xcalloc(1+nv+1, sizeof(int));
+ arc = xcalloc(1+na+na, sizeof(int));
+ link = xcalloc(1+nv, sizeof(int));
+ list = xcalloc(1+nv, sizeof(int));
+ /* ptr[i] := (degree of node i) */
+ for (i = 1; i <= nv; i++)
+ ptr[i] = 0;
+ for (a = 1; a <= na; a++)
+ { ptr[tail[a]]++;
+ ptr[head[a]]++;
+ }
+ /* initialize arc pointers */
+ ptr[1]++;
+ for (i = 1; i < nv; i++)
+ ptr[i+1] += ptr[i];
+ ptr[nv+1] = ptr[nv];
+ /* build arc lists */
+ for (a = 1; a <= na; a++)
+ { arc[--ptr[tail[a]]] = a;
+ arc[--ptr[head[a]]] = a;
+ }
+ xassert(ptr[1] == 1);
+ xassert(ptr[nv+1] == na+na+1);
+ /* now the indices of arcs incident to node i are stored in
+ * locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
+ /* initialize arc flows */
+ for (a = 1; a <= na; a++)
+ x[a] = 0;
+loop: /* main loop starts here */
+ /* build augmenting tree rooted at s */
+ /* link[i] = 0 means that node i is not labelled yet;
+ * link[i] = a means that arc a immediately precedes node i */
+ /* initially node s is labelled as the root */
+ for (i = 1; i <= nv; i++)
+ link[i] = 0;
+ link[s] = -1, list[1] = s, pos1 = pos2 = 1;
+ /* breadth first search */
+ while (pos1 <= pos2)
+ { /* dequeue node i */
+ i = list[pos1++];
+ /* consider all arcs incident to node i */
+ for (k = ptr[i]; k < ptr[i+1]; k++)
+ { a = arc[k];
+ if (tail[a] == i)
+ { /* a = i->j is a forward arc from s to t */
+ j = head[a];
+ /* if node j has been labelled, skip the arc */
+ if (link[j] != 0) continue;
+ /* if the arc does not allow increasing the flow through
+ * it, skip the arc */
+ if (x[a] == cap[a]) continue;
+ }
+ else if (head[a] == i)
+ { /* a = i<-j is a backward arc from s to t */
+ j = tail[a];
+ /* if node j has been labelled, skip the arc */
+ if (link[j] != 0) continue;
+ /* if the arc does not allow decreasing the flow through
+ * it, skip the arc */
+ if (x[a] == 0) continue;
+ }
+ else
+ xassert(a != a);
+ /* label node j and enqueue it */
+ link[j] = a, list[++pos2] = j;
+ /* check for breakthrough */
+ if (j == t) goto brkt;
+ }
+ }
+ /* NONBREAKTHROUGH */
+ /* no augmenting path exists; current flow is maximal */
+ /* store minimal cut information, if necessary */
+ if (cut != NULL)
+ { for (i = 1; i <= nv; i++)
+ cut[i] = (char)(link[i] != 0);
+ }
+ goto done;
+brkt: /* BREAKTHROUGH */
+ /* walk through arcs of the augmenting path (s, ..., t) found in
+ * the reverse order and determine maximal change of the flow */
+ delta = 0;
+ for (j = t; j != s; j = i)
+ { /* arc a immediately precedes node j in the path */
+ a = link[j];
+ if (head[a] == j)
+ { /* a = i->j is a forward arc of the cycle */
+ i = tail[a];
+ /* x[a] may be increased until its upper bound */
+ temp = cap[a] - x[a];
+ }
+ else if (tail[a] == j)
+ { /* a = i<-j is a backward arc of the cycle */
+ i = head[a];
+ /* x[a] may be decreased until its lower bound */
+ temp = x[a];
+ }
+ else
+ xassert(a != a);
+ if (delta == 0 || delta > temp) delta = temp;
+ }
+ xassert(delta > 0);
+ /* increase the flow along the path */
+ for (j = t; j != s; j = i)
+ { /* arc a immediately precedes node j in the path */
+ a = link[j];
+ if (head[a] == j)
+ { /* a = i->j is a forward arc of the cycle */
+ i = tail[a];
+ x[a] += delta;
+ }
+ else if (tail[a] == j)
+ { /* a = i<-j is a backward arc of the cycle */
+ i = head[a];
+ x[a] -= delta;
+ }
+ else
+ xassert(a != a);
+ }
+ goto loop;
+done: /* free working arrays */
+ xfree(ptr);
+ xfree(arc);
+ xfree(link);
+ xfree(list);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/ffalg.h b/test/monniaux/glpk-4.65/src/misc/ffalg.h
new file mode 100644
index 00000000..7016f8fa
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/ffalg.h
@@ -0,0 +1,34 @@
+/* ffalg.h (Ford-Fulkerson algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2013 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/>.
+***********************************************************************/
+
+#ifndef FFALG_H
+#define FFALG_H
+
+#define ffalg _glp_ffalg
+void ffalg(int nv, int na, const int tail[], const int head[],
+ int s, int t, const int cap[], int x[], char cut[]);
+/* Ford-Fulkerson algorithm */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/fp2rat.c b/test/monniaux/glpk-4.65/src/misc/fp2rat.c
new file mode 100644
index 00000000..4699bbd1
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/fp2rat.c
@@ -0,0 +1,164 @@
+/* fp2rat.c (convert floating-point number to rational number) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "misc.h"
+
+/***********************************************************************
+* NAME
+*
+* fp2rat - convert floating-point number to rational number
+*
+* SYNOPSIS
+*
+* #include "misc.h"
+* int fp2rat(double x, double eps, double *p, double *q);
+*
+* DESCRIPTION
+*
+* Given a floating-point number 0 <= x < 1 the routine fp2rat finds
+* its "best" rational approximation p / q, where p >= 0 and q > 0 are
+* integer numbers, such that |x - p / q| <= eps.
+*
+* RETURNS
+*
+* The routine fp2rat returns the number of iterations used to achieve
+* the specified precision eps.
+*
+* EXAMPLES
+*
+* For x = sqrt(2) - 1 = 0.414213562373095 and eps = 1e-6 the routine
+* gives p = 408 and q = 985, where 408 / 985 = 0.414213197969543.
+*
+* BACKGROUND
+*
+* It is well known that every positive real number x can be expressed
+* as the following continued fraction:
+*
+* x = b[0] + a[1]
+* ------------------------
+* b[1] + a[2]
+* -----------------
+* b[2] + a[3]
+* ----------
+* b[3] + ...
+*
+* where:
+*
+* a[k] = 1, k = 0, 1, 2, ...
+*
+* b[k] = floor(x[k]), k = 0, 1, 2, ...
+*
+* x[0] = x,
+*
+* x[k] = 1 / frac(x[k-1]), k = 1, 2, 3, ...
+*
+* To find the "best" rational approximation of x the routine computes
+* partial fractions f[k] by dropping after k terms as follows:
+*
+* f[k] = A[k] / B[k],
+*
+* where:
+*
+* A[-1] = 1, A[0] = b[0], B[-1] = 0, B[0] = 1,
+*
+* A[k] = b[k] * A[k-1] + a[k] * A[k-2],
+*
+* B[k] = b[k] * B[k-1] + a[k] * B[k-2].
+*
+* Once the condition
+*
+* |x - f[k]| <= eps
+*
+* has been satisfied, the routine reports p = A[k] and q = B[k] as the
+* final answer.
+*
+* In the table below here is some statistics obtained for one million
+* random numbers uniformly distributed in the range [0, 1).
+*
+* eps max p mean p max q mean q max k mean k
+* -------------------------------------------------------------
+* 1e-1 8 1.6 9 3.2 3 1.4
+* 1e-2 98 6.2 99 12.4 5 2.4
+* 1e-3 997 20.7 998 41.5 8 3.4
+* 1e-4 9959 66.6 9960 133.5 10 4.4
+* 1e-5 97403 211.7 97404 424.2 13 5.3
+* 1e-6 479669 669.9 479670 1342.9 15 6.3
+* 1e-7 1579030 2127.3 3962146 4257.8 16 7.3
+* 1e-8 26188823 6749.4 26188824 13503.4 19 8.2
+*
+* REFERENCES
+*
+* W. B. Jones and W. J. Thron, "Continued Fractions: Analytic Theory
+* and Applications," Encyclopedia on Mathematics and Its Applications,
+* Addison-Wesley, 1980. */
+
+int fp2rat(double x, double eps, double *p, double *q)
+{ int k;
+ double xk, Akm1, Ak, Bkm1, Bk, ak, bk, fk, temp;
+ xassert(0.0 <= x && x < 1.0);
+ for (k = 0; ; k++)
+ { xassert(k <= 100);
+ if (k == 0)
+ { /* x[0] = x */
+ xk = x;
+ /* A[-1] = 1 */
+ Akm1 = 1.0;
+ /* A[0] = b[0] = floor(x[0]) = 0 */
+ Ak = 0.0;
+ /* B[-1] = 0 */
+ Bkm1 = 0.0;
+ /* B[0] = 1 */
+ Bk = 1.0;
+ }
+ else
+ { /* x[k] = 1 / frac(x[k-1]) */
+ temp = xk - floor(xk);
+ xassert(temp != 0.0);
+ xk = 1.0 / temp;
+ /* a[k] = 1 */
+ ak = 1.0;
+ /* b[k] = floor(x[k]) */
+ bk = floor(xk);
+ /* A[k] = b[k] * A[k-1] + a[k] * A[k-2] */
+ temp = bk * Ak + ak * Akm1;
+ Akm1 = Ak, Ak = temp;
+ /* B[k] = b[k] * B[k-1] + a[k] * B[k-2] */
+ temp = bk * Bk + ak * Bkm1;
+ Bkm1 = Bk, Bk = temp;
+ }
+ /* f[k] = A[k] / B[k] */
+ fk = Ak / Bk;
+#if 0
+ print("%.*g / %.*g = %.*g",
+ DBL_DIG, Ak, DBL_DIG, Bk, DBL_DIG, fk);
+#endif
+ if (fabs(x - fk) <= eps)
+ break;
+ }
+ *p = Ak;
+ *q = Bk;
+ return k;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/fvs.c b/test/monniaux/glpk-4.65/src/misc/fvs.c
new file mode 100644
index 00000000..916a1bf9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/fvs.c
@@ -0,0 +1,137 @@
+/* fvs.c (sparse vector in FVS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2016 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "fvs.h"
+
+void fvs_alloc_vec(FVS *x, int n)
+{ /* allocate sparse vector */
+ int j;
+ xassert(n >= 0);
+ x->n = n;
+ x->nnz = 0;
+ x->ind = talloc(1+n, int);
+ x->vec = talloc(1+n, double);
+ for (j = 1; j <= n; j++)
+ x->vec[j] = 0.0;
+ return;
+}
+
+void fvs_check_vec(const FVS *x)
+{ /* check sparse vector */
+ /* NOTE: for testing/debugging only */
+ int n = x->n;
+ int nnz = x->nnz;
+ int *ind = x->ind;
+ double *vec = x->vec;
+ char *map;
+ int j, k;
+ xassert(n >= 0);
+ xassert(0 <= nnz && nnz <= n);
+ map = talloc(1+n, char);
+ for (j = 1; j <= n; j++)
+ map[j] = (vec[j] != 0.0);
+ for (k = 1; k <= nnz; k++)
+ { j = ind[k];
+ xassert(1 <= j && j <= n);
+ xassert(map[j]);
+ map[j] = 0;
+ }
+ for (j = 1; j <= n; j++)
+ xassert(!map[j]);
+ tfree(map);
+ return;
+}
+
+void fvs_gather_vec(FVS *x, double eps)
+{ /* gather sparse vector */
+ int n = x->n;
+ int *ind = x->ind;
+ double *vec = x->vec;
+ int j, nnz = 0;
+ for (j = n; j >= 1; j--)
+ { if (-eps < vec[j] && vec[j] < +eps)
+ vec[j] = 0.0;
+ else
+ ind[++nnz] = j;
+ }
+ x->nnz = nnz;
+ return;
+}
+
+void fvs_clear_vec(FVS *x)
+{ /* clear sparse vector */
+ int *ind = x->ind;
+ double *vec = x->vec;
+ int k;
+ for (k = x->nnz; k >= 1; k--)
+ vec[ind[k]] = 0.0;
+ x->nnz = 0;
+ return;
+}
+
+void fvs_copy_vec(FVS *x, const FVS *y)
+{ /* copy sparse vector */
+ int *x_ind = x->ind;
+ double *x_vec = x->vec;
+ int *y_ind = y->ind;
+ double *y_vec = y->vec;
+ int j, k;
+ xassert(x != y);
+ xassert(x->n == y->n);
+ fvs_clear_vec(x);
+ for (k = x->nnz = y->nnz; k >= 1; k--)
+ { j = x_ind[k] = y_ind[k];
+ x_vec[j] = y_vec[j];
+ }
+ return;
+}
+
+void fvs_adjust_vec(FVS *x, double eps)
+{ /* replace tiny vector elements by exact zeros */
+ int nnz = x->nnz;
+ int *ind = x->ind;
+ double *vec = x->vec;
+ int j, k, cnt = 0;
+ for (k = 1; k <= nnz; k++)
+ { j = ind[k];
+ if (-eps < vec[j] && vec[j] < +eps)
+ vec[j] = 0.0;
+ else
+ ind[++cnt] = j;
+ }
+ x->nnz = cnt;
+ return;
+}
+
+void fvs_free_vec(FVS *x)
+{ /* deallocate sparse vector */
+ tfree(x->ind);
+ tfree(x->vec);
+ x->n = x->nnz = -1;
+ x->ind = NULL;
+ x->vec = NULL;
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/fvs.h b/test/monniaux/glpk-4.65/src/misc/fvs.h
new file mode 100644
index 00000000..abfed8cc
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/fvs.h
@@ -0,0 +1,76 @@
+/* fvs.h (sparse vector in FVS format) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2016 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/>.
+***********************************************************************/
+
+#ifndef FVS_H
+#define FVS_H
+
+typedef struct FVS FVS;
+
+struct FVS
+{ /* sparse vector in FVS (Full Vector Storage) format */
+ int n;
+ /* vector dimension (total number of elements) */
+ int nnz;
+ /* number of non-zero elements, 0 <= nnz <= n */
+ int *ind; /* int ind[1+n]; */
+ /* ind[0] is not used;
+ * ind[k] = j, 1 <= k <= nnz, means that vec[j] != 0
+ * non-zero indices in the array ind are stored in arbitrary
+ * order; if vec[j] = 0, its index j SHOULD NOT be presented in
+ * the array ind */
+ double *vec; /* double vec[1+n]; */
+ /* vec[0] is not used;
+ * vec[j], 1 <= j <= n, is a numeric value of j-th element */
+};
+
+#define fvs_alloc_vec _glp_fvs_alloc_vec
+void fvs_alloc_vec(FVS *x, int n);
+/* allocate sparse vector */
+
+#define fvs_check_vec _glp_fvs_check_vec
+void fvs_check_vec(const FVS *x);
+/* check sparse vector */
+
+#define fvs_gather_vec _glp_fvs_gather_vec
+void fvs_gather_vec(FVS *x, double eps);
+/* gather sparse vector */
+
+#define fvs_clear_vec _glp_fvs_clear_vec
+void fvs_clear_vec(FVS *x);
+/* clear sparse vector */
+
+#define fvs_copy_vec _glp_fvs_copy_vec
+void fvs_copy_vec(FVS *x, const FVS *y);
+/* copy sparse vector */
+
+#define fvs_adjust_vec _glp_fvs_adjust_vec
+void fvs_adjust_vec(FVS *x, double eps);
+/* replace tiny vector elements by exact zeros */
+
+#define fvs_free_vec _glp_fvs_free_vec
+void fvs_free_vec(FVS *x);
+/* deallocate sparse vector */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/gcd.c b/test/monniaux/glpk-4.65/src/misc/gcd.c
new file mode 100644
index 00000000..95c48cc0
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/gcd.c
@@ -0,0 +1,102 @@
+/* gcd.c (greatest common divisor) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "misc.h"
+
+/***********************************************************************
+* NAME
+*
+* gcd - find greatest common divisor of two integers
+*
+* SYNOPSIS
+*
+* #include "misc.h"
+* int gcd(int x, int y);
+*
+* RETURNS
+*
+* The routine gcd returns gcd(x, y), the greatest common divisor of
+* the two positive integers given.
+*
+* ALGORITHM
+*
+* The routine gcd is based on Euclid's algorithm.
+*
+* REFERENCES
+*
+* Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical
+* Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The
+* Greatest Common Divisor, pp. 333-56. */
+
+int gcd(int x, int y)
+{ int r;
+ xassert(x > 0 && y > 0);
+ while (y > 0)
+ r = x % y, x = y, y = r;
+ return x;
+}
+
+/***********************************************************************
+* NAME
+*
+* gcdn - find greatest common divisor of n integers
+*
+* SYNOPSIS
+*
+* #include "misc.h"
+* int gcdn(int n, int x[]);
+*
+* RETURNS
+*
+* The routine gcdn returns gcd(x[1], x[2], ..., x[n]), the greatest
+* common divisor of n positive integers given, n > 0.
+*
+* BACKGROUND
+*
+* The routine gcdn is based on the following identity:
+*
+* gcd(x, y, z) = gcd(gcd(x, y), z).
+*
+* REFERENCES
+*
+* Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical
+* Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The
+* Greatest Common Divisor, pp. 333-56. */
+
+int gcdn(int n, int x[])
+{ int d, j;
+ xassert(n > 0);
+ for (j = 1; j <= n; j++)
+ { xassert(x[j] > 0);
+ if (j == 1)
+ d = x[1];
+ else
+ d = gcd(d, x[j]);
+ if (d == 1)
+ break;
+ }
+ return d;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/jd.c b/test/monniaux/glpk-4.65/src/misc/jd.c
new file mode 100644
index 00000000..c9d63171
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/jd.c
@@ -0,0 +1,152 @@
+/* jd.c (conversions between calendar date and Julian day number) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include <stddef.h>
+#include "jd.h"
+
+/***********************************************************************
+* NAME
+*
+* jday - convert calendar date to Julian day number
+*
+* SYNOPSIS
+*
+* #include "jd.h"
+* int jday(int d, int m, int y);
+*
+* DESCRIPTION
+*
+* The routine jday converts a calendar date, Gregorian calendar, to
+* corresponding Julian day number j.
+*
+* From the given day d, month m, and year y, the Julian day number j
+* is computed without using tables.
+*
+* The routine is valid for 1 <= y <= 4000.
+*
+* RETURNS
+*
+* The routine jday returns the Julian day number, or negative value if
+* the specified date is incorrect.
+*
+* REFERENCES
+*
+* R. G. Tantzen, Algorithm 199: conversions between calendar date and
+* Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444,
+* Aug. 1963. */
+
+int jday(int d, int m, int y)
+{ int c, ya, j, dd;
+ if (!(1 <= d && d <= 31 &&
+ 1 <= m && m <= 12 &&
+ 1 <= y && y <= 4000))
+ return -1;
+ if (m >= 3)
+ m -= 3;
+ else
+ m += 9, y--;
+ c = y / 100;
+ ya = y - 100 * c;
+ j = (146097 * c) / 4 + (1461 * ya) / 4 + (153 * m + 2) / 5 + d +
+ 1721119;
+ jdate(j, &dd, NULL, NULL);
+ if (d != dd)
+ return -1;
+ return j;
+}
+
+/***********************************************************************
+* NAME
+*
+* jdate - convert Julian day number to calendar date
+*
+* SYNOPSIS
+*
+* #include "jd.h"
+* int jdate(int j, int *d, int *m, int *y);
+*
+* DESCRIPTION
+*
+* The routine jdate converts a Julian day number j to corresponding
+* calendar date, Gregorian calendar.
+*
+* The day d, month m, and year y are computed without using tables and
+* stored in corresponding locations.
+*
+* The routine is valid for 1721426 <= j <= 3182395.
+*
+* RETURNS
+*
+* If the conversion is successful, the routine returns zero, otherwise
+* non-zero.
+*
+* REFERENCES
+*
+* R. G. Tantzen, Algorithm 199: conversions between calendar date and
+* Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444,
+* Aug. 1963. */
+
+int jdate(int j, int *d_, int *m_, int *y_)
+{ int d, m, y;
+ if (!(1721426 <= j && j <= 3182395))
+ return 1;
+ j -= 1721119;
+ y = (4 * j - 1) / 146097;
+ j = (4 * j - 1) % 146097;
+ d = j / 4;
+ j = (4 * d + 3) / 1461;
+ d = (4 * d + 3) % 1461;
+ d = (d + 4) / 4;
+ m = (5 * d - 3) / 153;
+ d = (5 * d - 3) % 153;
+ d = (d + 5) / 5;
+ y = 100 * y + j;
+ if (m <= 9)
+ m += 3;
+ else m -= 9,
+ y++;
+ if (d_ != NULL) *d_ = d;
+ if (m_ != NULL) *m_ = m;
+ if (y_ != NULL) *y_ = y;
+ return 0;
+}
+
+#ifdef GLP_TEST
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void)
+{ int jbeg, jend, j, d, m, y;
+ jbeg = jday(1, 1, 1);
+ jend = jday(31, 12, 4000);
+ for (j = jbeg; j <= jend; j++)
+ { assert(jdate(j, &d, &m, &y) == 0);
+ assert(jday(d, m, y) == j);
+ }
+ printf("Routines jday and jdate work correctly.\n");
+ return 0;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/jd.h b/test/monniaux/glpk-4.65/src/misc/jd.h
new file mode 100644
index 00000000..009d2daa
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/jd.h
@@ -0,0 +1,32 @@
+/* jd.h (conversions between calendar date and Julian day number) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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 jday _glp_jday
+int jday(int d, int m, int y);
+/* convert calendar date to Julian day number */
+
+#define jdate _glp_jdate
+int jdate(int j, int *d, int *m, int *y);
+/* convert Julian day number to calendar date */
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/keller.c b/test/monniaux/glpk-4.65/src/misc/keller.c
new file mode 100644
index 00000000..d64d3c1e
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/keller.c
@@ -0,0 +1,235 @@
+/* keller.c (cover edges by cliques, Kellerman's heuristic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2013 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/>.
+***********************************************************************/
+
+#include "glpk.h"
+#include "env.h"
+#include "keller.h"
+
+/***********************************************************************
+* NAME
+*
+* kellerman - cover edges by cliques with Kellerman's heuristic
+*
+* SYNOPSIS
+*
+* #include "keller.h"
+* int kellerman(int n, int (*func)(void *info, int i, int ind[]),
+* void *info, glp_graph *H);
+*
+* DESCRIPTION
+*
+* The routine kellerman implements Kellerman's heuristic algorithm
+* to find a minimal set of cliques which cover all edges of specified
+* graph G = (V, E).
+*
+* The parameter n specifies the number of vertices |V|, n >= 0.
+*
+* Formal routine func specifies the set of edges E in the following
+* way. Running the routine kellerman calls the routine func and passes
+* to it parameter i, which is the number of some vertex, 1 <= i <= n.
+* In response the routine func should store numbers of all vertices
+* adjacent to vertex i to locations ind[1], ind[2], ..., ind[len] and
+* return the value of len, which is the number of adjacent vertices,
+* 0 <= len <= n. Self-loops are allowed, but ignored. Multiple edges
+* are not allowed.
+*
+* The parameter info is a transit pointer (magic cookie) passed to the
+* formal routine func as its first parameter.
+*
+* The result provided by the routine kellerman is the bipartite graph
+* H = (V union C, F), which defines the covering found. (The program
+* object of type glp_graph specified by the parameter H should be
+* previously created with the routine glp_create_graph. On entry the
+* routine kellerman erases the content of this object with the routine
+* glp_erase_graph.) Vertices of first part V correspond to vertices of
+* the graph G and have the same ordinal numbers 1, 2, ..., n. Vertices
+* of second part C correspond to cliques and have ordinal numbers
+* n+1, n+2, ..., n+k, where k is the total number of cliques in the
+* edge covering found. Every edge f in F in the program object H is
+* represented as arc f = (i->j), where i in V and j in C, which means
+* that vertex i of the graph G is in clique C[j], 1 <= j <= k. (Thus,
+* if two vertices of the graph G are in the same clique, these vertices
+* are adjacent in G, and corresponding edge is covered by that clique.)
+*
+* RETURNS
+*
+* The routine Kellerman returns k, the total number of cliques in the
+* edge covering found.
+*
+* REFERENCE
+*
+* For more details see: glpk/doc/notes/keller.pdf (in Russian). */
+
+struct set
+{ /* set of vertices */
+ int size;
+ /* size (cardinality) of the set, 0 <= card <= n */
+ int *list; /* int list[1+n]; */
+ /* the set contains vertices list[1,...,size] */
+ int *pos; /* int pos[1+n]; */
+ /* pos[i] > 0 means that vertex i is in the set and
+ * list[pos[i]] = i; pos[i] = 0 means that vertex i is not in
+ * the set */
+};
+
+int kellerman(int n, int (*func)(void *info, int i, int ind[]),
+ void *info, void /* glp_graph */ *H_)
+{ glp_graph *H = H_;
+ struct set W_, *W = &W_, V_, *V = &V_;
+ glp_arc *a;
+ int i, j, k, m, t, len, card, best;
+ xassert(n >= 0);
+ /* H := (V, 0; 0), where V is the set of vertices of graph G */
+ glp_erase_graph(H, H->v_size, H->a_size);
+ glp_add_vertices(H, n);
+ /* W := 0 */
+ W->size = 0;
+ W->list = xcalloc(1+n, sizeof(int));
+ W->pos = xcalloc(1+n, sizeof(int));
+ memset(&W->pos[1], 0, sizeof(int) * n);
+ /* V := 0 */
+ V->size = 0;
+ V->list = xcalloc(1+n, sizeof(int));
+ V->pos = xcalloc(1+n, sizeof(int));
+ memset(&V->pos[1], 0, sizeof(int) * n);
+ /* main loop */
+ for (i = 1; i <= n; i++)
+ { /* W must be empty */
+ xassert(W->size == 0);
+ /* W := { j : i > j and (i,j) in E } */
+ len = func(info, i, W->list);
+ xassert(0 <= len && len <= n);
+ for (t = 1; t <= len; t++)
+ { j = W->list[t];
+ xassert(1 <= j && j <= n);
+ if (j >= i) continue;
+ xassert(W->pos[j] == 0);
+ W->list[++W->size] = j, W->pos[j] = W->size;
+ }
+ /* on i-th iteration we need to cover edges (i,j) for all
+ * j in W */
+ /* if W is empty, it is a special case */
+ if (W->size == 0)
+ { /* set k := k + 1 and create new clique C[k] = { i } */
+ k = glp_add_vertices(H, 1) - n;
+ glp_add_arc(H, i, n + k);
+ continue;
+ }
+ /* try to include vertex i into existing cliques */
+ /* V must be empty */
+ xassert(V->size == 0);
+ /* k is the number of cliques found so far */
+ k = H->nv - n;
+ for (m = 1; m <= k; m++)
+ { /* do while V != W; since here V is within W, we can use
+ * equivalent condition: do while |V| < |W| */
+ if (V->size == W->size) break;
+ /* check if C[m] is within W */
+ for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
+ { j = a->tail->i;
+ if (W->pos[j] == 0) break;
+ }
+ if (a != NULL) continue;
+ /* C[m] is within W, expand clique C[m] with vertex i */
+ /* C[m] := C[m] union {i} */
+ glp_add_arc(H, i, n + m);
+ /* V is a set of vertices whose incident edges are already
+ * covered by existing cliques */
+ /* V := V union C[m] */
+ for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
+ { j = a->tail->i;
+ if (V->pos[j] == 0)
+ V->list[++V->size] = j, V->pos[j] = V->size;
+ }
+ }
+ /* remove from set W the vertices whose incident edges are
+ * already covered by existing cliques */
+ /* W := W \ V, V := 0 */
+ for (t = 1; t <= V->size; t++)
+ { j = V->list[t], V->pos[j] = 0;
+ if (W->pos[j] != 0)
+ { /* remove vertex j from W */
+ if (W->pos[j] != W->size)
+ { int jj = W->list[W->size];
+ W->list[W->pos[j]] = jj;
+ W->pos[jj] = W->pos[j];
+ }
+ W->size--, W->pos[j] = 0;
+ }
+ }
+ V->size = 0;
+ /* now set W contains only vertices whose incident edges are
+ * still not covered by existing cliques; create new cliques
+ * to cover remaining edges until set W becomes empty */
+ while (W->size > 0)
+ { /* find clique C[m], 1 <= m <= k, which shares maximal
+ * number of vertices with W; to break ties choose clique
+ * having smallest number m */
+ m = 0, best = -1;
+ k = H->nv - n;
+ for (t = 1; t <= k; t++)
+ { /* compute cardinality of intersection of W and C[t] */
+ card = 0;
+ for (a = H->v[n + t]->in; a != NULL; a = a->h_next)
+ { j = a->tail->i;
+ if (W->pos[j] != 0) card++;
+ }
+ if (best < card)
+ m = t, best = card;
+ }
+ xassert(m > 0);
+ /* set k := k + 1 and create new clique:
+ * C[k] := (W intersect C[m]) union { i }, which covers all
+ * edges incident to vertices from (W intersect C[m]) */
+ k = glp_add_vertices(H, 1) - n;
+ for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
+ { j = a->tail->i;
+ if (W->pos[j] != 0)
+ { /* vertex j is in both W and C[m]; include it in new
+ * clique C[k] */
+ glp_add_arc(H, j, n + k);
+ /* remove vertex j from W, since edge (i,j) will be
+ * covered by new clique C[k] */
+ if (W->pos[j] != W->size)
+ { int jj = W->list[W->size];
+ W->list[W->pos[j]] = jj;
+ W->pos[jj] = W->pos[j];
+ }
+ W->size--, W->pos[j] = 0;
+ }
+ }
+ /* include vertex i to new clique C[k] to cover edges (i,j)
+ * incident to all vertices j just removed from W */
+ glp_add_arc(H, i, n + k);
+ }
+ }
+ /* free working arrays */
+ xfree(W->list);
+ xfree(W->pos);
+ xfree(V->list);
+ xfree(V->pos);
+ /* return the number of cliques in the edge covering found */
+ return H->nv - n;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/keller.h b/test/monniaux/glpk-4.65/src/misc/keller.h
new file mode 100644
index 00000000..d7a5b343
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/keller.h
@@ -0,0 +1,34 @@
+/* keller.h (cover edges by cliques, Kellerman's heuristic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2013 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/>.
+***********************************************************************/
+
+#ifndef KELLER_H
+#define KELLER_H
+
+#define kellerman _glp_kellerman
+int kellerman(int n, int (*func)(void *info, int i, int ind[]),
+ void *info, void /* glp_graph */ *H);
+/* cover edges by cliques with Kellerman's heuristic */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/ks.c b/test/monniaux/glpk-4.65/src/misc/ks.c
new file mode 100644
index 00000000..0720cc90
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/ks.c
@@ -0,0 +1,466 @@
+/* ks.c (0-1 knapsack problem) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2017-2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ks.h"
+#include "mt1.h"
+
+/***********************************************************************
+* 0-1 knapsack problem has the following formulation:
+*
+* maximize z = sum{j in 1..n} c[j]x[j] (1)
+*
+* s.t. sum{j in 1..n} a[j]x[j] <= b (2)
+*
+* x[j] in {0, 1} for all j in 1..n (3)
+*
+* In general case it is assumed that the instance is non-normalized,
+* i.e. parameters a, b, and c may have any sign.
+***********************************************************************/
+
+/***********************************************************************
+* ks_enum - solve 0-1 knapsack problem by complete enumeration
+*
+* This routine finds optimal solution to 0-1 knapsack problem (1)-(3)
+* by complete enumeration. It is intended mainly for testing purposes.
+*
+* The instance to be solved is specified by parameters n, a, b, and c.
+* Note that these parameters can have any sign, i.e. normalization is
+* not needed.
+*
+* On exit the routine stores the optimal point found in locations
+* x[1], ..., x[n] and returns the optimal objective value. However, if
+* the instance is infeasible, the routine returns INT_MIN.
+*
+* Since the complete enumeration is inefficient, this routine can be
+* used only for small instances (n <= 20-30). */
+
+#define N_MAX 40
+
+int ks_enum(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/],
+ char x[/*1+n*/])
+{ int j, s, z, z_best;
+ char x_best[1+N_MAX];
+ xassert(0 <= n && n <= N_MAX);
+ /* initialization */
+ memset(&x[1], 0, n * sizeof(char));
+ z_best = INT_MIN;
+loop: /* compute constraint and objective at current x */
+ s = z = 0;
+ for (j = 1; j <= n; j++)
+ { if (x[j])
+ s += a[j], z += c[j];
+ }
+ /* check constraint violation */
+ if (s > b)
+ goto next;
+ /* check objective function */
+ if (z_best < z)
+ { /* better solution has been found */
+ memcpy(&x_best[1], &x[1], n * sizeof(char));
+ z_best = z;
+ }
+next: /* generate next x */
+ for (j = 1; j <= n; j++)
+ { if (!x[j])
+ { x[j] = 1;
+ goto loop;
+ }
+ x[j] = 0;
+ }
+ /* report best (optimal) solution */
+ memcpy(&x[1], &x_best[1], n * sizeof(char));
+ return z_best;
+}
+
+/***********************************************************************
+* reduce - prepare reduced instance of 0-1 knapsack
+*
+* Given original instance of 0-1 knapsack (1)-(3) specified by the
+* parameters n, a, b, and c this routine transforms it to equivalent
+* reduced instance in the same format. The reduced instance is
+* normalized, i.e. the following additional conditions are met:
+*
+* n >= 2 (4)
+*
+* 1 <= a[j] <= b for all j in 1..n (5)
+*
+* sum{j in 1..n} a[j] >= b+1 (6)
+*
+* c[j] >= 1 for all j in 1..n (7)
+*
+* The routine creates the structure ks and stores there parameters n,
+* a, b, and c of the reduced instance as well as template of solution
+* to original instance.
+*
+* Normally the routine returns a pointer to the structure ks created.
+* However, if the original instance is infeasible, the routine returns
+* a null pointer. */
+
+struct ks
+{ int orig_n;
+ /* original problem dimension */
+ int n;
+ /* reduced problem dimension */
+ int *a; /* int a[1+orig_n]; */
+ /* a{j in 1..n} are constraint coefficients (2) */
+ int b;
+ /* b is constraint right-hand side (2) */
+ int *c; /* int c[1+orig_n]; */
+ /* c{j in 1..n} are objective coefficients (1) */
+ int c0;
+ /* c0 is objective constant term */
+ char *x; /* char x[1+orig_n]; */
+ /* x{j in 1..orig_n} is solution template to original instance:
+ * x[j] = 0 x[j] is fixed at 0
+ * x[j] = 1 x[j] is fixed at 1
+ * x[j] = 0x10 x[j] = x[j']
+ * x[j] = 0x11 x[j] = 1 - x[j']
+ * where x[j'] is corresponding solution to reduced instance */
+};
+
+static void free_ks(struct ks *ks);
+
+static struct ks *reduce(const int n, const int a[/*1+n*/], int b,
+ const int c[/*1+n*/])
+{ struct ks *ks;
+ int j, s;
+ xassert(n >= 0);
+ /* initially reduced instance is the same as original one */
+ ks = talloc(1, struct ks);
+ ks->orig_n = n;
+ ks->n = 0;
+ ks->a = talloc(1+n, int);
+ memcpy(&ks->a[1], &a[1], n * sizeof(int));
+ ks->b = b;
+ ks->c = talloc(1+n, int);
+ memcpy(&ks->c[1], &c[1], n * sizeof(int));
+ ks->c0 = 0;
+ ks->x = talloc(1+n, char);
+ /* make all a[j] non-negative */
+ for (j = 1; j <= n; j++)
+ { if (a[j] >= 0)
+ { /* keep original x[j] */
+ ks->x[j] = 0x10;
+ }
+ else /* a[j] < 0 */
+ { /* substitute x[j] = 1 - x'[j] */
+ ks->x[j] = 0x11;
+ /* ... + a[j]x[j] + ... <= b
+ * ... + a[j](1 - x'[j]) + ... <= b
+ * ... - a[j]x'[j] + ... <= b - a[j] */
+ ks->a[j] = - ks->a[j];
+ ks->b += ks->a[j];
+ /* z = ... + c[j]x[j] + ... + c0 =
+ * = ... + c[j](1 - x'[j]) + ... + c0 =
+ * = ... - c[j]x'[j] + ... + (c0 + c[j]) */
+ ks->c0 += ks->c[j];
+ ks->c[j] = - ks->c[j];
+ }
+ }
+ /* now a[j] >= 0 for all j in 1..n */
+ if (ks->b < 0)
+ { /* instance is infeasible */
+ free_ks(ks);
+ return NULL;
+ }
+ /* build reduced instance */
+ for (j = 1; j <= n; j++)
+ { if (ks->a[j] == 0)
+ { if (ks->c[j] <= 0)
+ { /* fix x[j] at 0 */
+ ks->x[j] ^= 0x10;
+ }
+ else
+ { /* fix x[j] at 1 */
+ ks->x[j] ^= 0x11;
+ ks->c0 += ks->c[j];
+ }
+ }
+ else if (ks->a[j] > ks->b || ks->c[j] <= 0)
+ { /* fix x[j] at 0 */
+ ks->x[j] ^= 0x10;
+ }
+ else
+ { /* include x[j] in reduced instance */
+ ks->n++;
+ ks->a[ks->n] = ks->a[j];
+ ks->c[ks->n] = ks->c[j];
+ }
+ }
+ /* now conditions (5) and (7) are met */
+ /* check condition (6) */
+ s = 0;
+ for (j = 1; j <= ks->n; j++)
+ { xassert(1 <= ks->a[j] && ks->a[j] <= ks->b);
+ xassert(ks->c[j] >= 1);
+ s += ks->a[j];
+ }
+ if (s <= ks->b)
+ { /* sum{j in 1..n} a[j] <= b */
+ /* fix all remaining x[j] at 1 to obtain trivial solution */
+ for (j = 1; j <= n; j++)
+ { if (ks->x[j] & 0x10)
+ ks->x[j] ^= 0x11;
+ }
+ for (j = 1; j <= ks->n; j++)
+ ks->c0 += ks->c[j];
+ /* reduced instance is empty */
+ ks->n = 0;
+ }
+ /* here n = 0 or n >= 2 due to condition (6) */
+ xassert(ks->n == 0 || ks->n >= 2);
+ return ks;
+}
+
+/***********************************************************************
+* restore - restore solution to original 0-1 knapsack instance
+*
+* Given optimal solution x{j in 1..ks->n} to the reduced 0-1 knapsack
+* instance (previously prepared by the routine reduce) this routine
+* constructs optimal solution to the original instance and stores it
+* in the array ks->x{j in 1..ks->orig_n}.
+*
+* On exit the routine returns optimal objective value for the original
+* instance.
+*
+* NOTE: This operation should be performed only once. */
+
+static int restore(struct ks *ks, char x[])
+{ int j, k, z;
+ z = ks->c0;
+ for (j = 1, k = 0; j <= ks->orig_n; j++)
+ { if (ks->x[j] & 0x10)
+ { k++;
+ xassert(k <= ks->n);
+ xassert(x[k] == 0 || x[k] == 1);
+ if (ks->x[j] & 1)
+ ks->x[j] = 1 - x[k];
+ else
+ ks->x[j] = x[k];
+ if (x[k])
+ z += ks->c[k];
+ }
+ }
+ xassert(k == ks->n);
+ return z;
+}
+
+/***********************************************************************
+* free_ks - deallocate structure ks
+*
+* This routine frees memory previously allocated to the structure ks
+* and all its components. */
+
+static void free_ks(struct ks *ks)
+{ xassert(ks != NULL);
+ tfree(ks->a);
+ tfree(ks->c);
+ tfree(ks->x);
+ tfree(ks);
+}
+
+/***********************************************************************
+* ks_mt1 - solve 0-1 knapsack problem with Martello & Toth algorithm
+*
+* This routine finds optimal solution to 0-1 knapsack problem (1)-(3)
+* with Martello & Toth algorithm MT1.
+*
+* The instance to be solved is specified by parameters n, a, b, and c.
+* Note that these parameters can have any sign, i.e. normalization is
+* not needed.
+*
+* On exit the routine stores the optimal point found in locations
+* x[1], ..., x[n] and returns the optimal objective value. However, if
+* the instance is infeasible, the routine returns INT_MIN.
+*
+* REFERENCES
+*
+* S.Martello, P.Toth. Knapsack Problems: Algorithms and Computer Imp-
+* lementations. John Wiley & Sons, 1990. */
+
+struct mt
+{ int j;
+ float r; /* r[j] = c[j] / a[j] */
+};
+
+static int CDECL fcmp(const void *p1, const void *p2)
+{ if (((struct mt *)p1)->r > ((struct mt *)p2)->r)
+ return -1;
+ else if (((struct mt *)p1)->r < ((struct mt *)p2)->r)
+ return +1;
+ else
+ return 0;
+}
+
+static int mt1a(int n, const int a[], int b, const int c[], char x[])
+{ /* interface routine to MT1 */
+ struct mt *mt;
+ int j, z, *p, *w, *x1, *xx, *min, *psign, *wsign, *zsign;
+ xassert(n >= 2);
+ /* allocate working arrays */
+ mt = talloc(1+n, struct mt);
+ p = talloc(1+n+1, int);
+ w = talloc(1+n+1, int);
+ x1 = talloc(1+n+1, int);
+ xx = talloc(1+n+1, int);
+ min = talloc(1+n+1, int);
+ psign = talloc(1+n+1, int);
+ wsign = talloc(1+n+1, int);
+ zsign = talloc(1+n+1, int);
+ /* reorder items to provide c[j] / a[j] >= a[j+1] / a[j+1] */
+ for (j = 1; j <= n; j++)
+ { mt[j].j = j;
+ mt[j].r = (float)c[j] / (float)a[j];
+ }
+ qsort(&mt[1], n, sizeof(struct mt), fcmp);
+ /* load instance parameters */
+ for (j = 1; j <= n; j++)
+ { p[j] = c[mt[j].j];
+ w[j] = a[mt[j].j];
+ }
+ /* find optimal solution */
+ z = mt1(n, p, w, b, x1, 1, xx, min, psign, wsign, zsign);
+ xassert(z >= 0);
+ /* store optimal point found */
+ for (j = 1; j <= n; j++)
+ { xassert(x1[j] == 0 || x1[j] == 1);
+ x[mt[j].j] = x1[j];
+ }
+ /* free working arrays */
+ tfree(mt);
+ tfree(p);
+ tfree(w);
+ tfree(x1);
+ tfree(xx);
+ tfree(min);
+ tfree(psign);
+ tfree(wsign);
+ tfree(zsign);
+ return z;
+}
+
+int ks_mt1(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/],
+ char x[/*1+n*/])
+{ struct ks *ks;
+ int j, s1, s2, z;
+ xassert(n >= 0);
+ /* prepare reduced instance */
+ ks = reduce(n, a, b, c);
+ if (ks == NULL)
+ { /* original instance is infeasible */
+ return INT_MIN;
+ }
+ /* find optimal solution to reduced instance */
+ if (ks->n > 0)
+ mt1a(ks->n, ks->a, ks->b, ks->c, x);
+ /* restore solution to original instance */
+ z = restore(ks, x);
+ memcpy(&x[1], &ks->x[1], n * sizeof(char));
+ free_ks(ks);
+ /* check solution found */
+ s1 = s2 = 0;
+ for (j = 1; j <= n; j++)
+ { xassert(x[j] == 0 || x[j] == 1);
+ if (x[j])
+ s1 += a[j], s2 += c[j];
+ }
+ xassert(s1 <= b);
+ xassert(s2 == z);
+ return z;
+}
+
+/***********************************************************************
+* ks_greedy - solve 0-1 knapsack problem with greedy heuristic
+*
+* This routine finds (sub)optimal solution to 0-1 knapsack problem
+* (1)-(3) with greedy heuristic.
+*
+* The instance to be solved is specified by parameters n, a, b, and c.
+* Note that these parameters can have any sign, i.e. normalization is
+* not needed.
+*
+* On exit the routine stores the optimal point found in locations
+* x[1], ..., x[n] and returns the optimal objective value. However, if
+* the instance is infeasible, the routine returns INT_MIN. */
+
+static int greedy(int n, const int a[], int b, const int c[], char x[])
+{ /* core routine for normalized 0-1 knapsack instance */
+ struct mt *mt;
+ int j, s, z;
+ xassert(n >= 2);
+ /* reorder items to provide c[j] / a[j] >= a[j+1] / a[j+1] */
+ mt = talloc(1+n, struct mt);
+ for (j = 1; j <= n; j++)
+ { mt[j].j = j;
+ mt[j].r = (float)c[j] / (float)a[j];
+ }
+ qsort(&mt[1], n, sizeof(struct mt), fcmp);
+ /* take items starting from most valuable ones until the knapsack
+ * is full */
+ s = z = 0;
+ for (j = 1; j <= n; j++)
+ { if (s + a[mt[j].j] > b)
+ break;
+ x[mt[j].j] = 1;
+ s += a[mt[j].j];
+ z += c[mt[j].j];
+ }
+ /* don't take remaining items */
+ for (j = j; j <= n; j++)
+ x[mt[j].j] = 0;
+ tfree(mt);
+ return z;
+}
+
+int ks_greedy(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/],
+ char x[/*1+n*/])
+{ struct ks *ks;
+ int j, s1, s2, z;
+ xassert(n >= 0);
+ /* prepare reduced instance */
+ ks = reduce(n, a, b, c);
+ if (ks == NULL)
+ { /* original instance is infeasible */
+ return INT_MIN;
+ }
+ /* find suboptimal solution to reduced instance */
+ if (ks->n > 0)
+ greedy(ks->n, ks->a, ks->b, ks->c, x);
+ /* restore solution to original instance */
+ z = restore(ks, x);
+ memcpy(&x[1], &ks->x[1], n * sizeof(char));
+ free_ks(ks);
+ /* check solution found */
+ s1 = s2 = 0;
+ for (j = 1; j <= n; j++)
+ { xassert(x[j] == 0 || x[j] == 1);
+ if (x[j])
+ s1 += a[j], s2 += c[j];
+ }
+ xassert(s1 <= b);
+ xassert(s2 == z);
+ return z;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/ks.h b/test/monniaux/glpk-4.65/src/misc/ks.h
new file mode 100644
index 00000000..d607dc44
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/ks.h
@@ -0,0 +1,44 @@
+/* ks.h (0-1 knapsack problem) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2017-2018 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/>.
+***********************************************************************/
+
+#ifndef KS_H
+#define KS_H
+
+#define ks_enum _glp_ks_enum
+int ks_enum(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/],
+ char x[/*1+n*/]);
+/* solve 0-1 knapsack problem by complete enumeration */
+
+#define ks_mt1 _glp_ks_mt1
+int ks_mt1(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/],
+ char x[/*1+n*/]);
+/* solve 0-1 knapsack problem with Martello & Toth algorithm */
+
+#define ks_greedy _glp_ks_greedy
+int ks_greedy(int n, const int a[/*1+n*/], int b, const int c[/*1+n*/],
+ char x[/*1+n*/]);
+/* solve 0-1 knapsack problem with greedy heuristic */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/mc13d.c b/test/monniaux/glpk-4.65/src/misc/mc13d.c
new file mode 100644
index 00000000..d8bab398
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/mc13d.c
@@ -0,0 +1,314 @@
+/* mc13d.c (permutations to block triangular form) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* This code is the result of translation of the Fortran subroutines
+* MC13D and MC13E associated with the following paper:
+*
+* I.S.Duff, J.K.Reid, Algorithm 529: Permutations to block triangular
+* form, ACM Trans. on Math. Softw. 4 (1978), 189-192.
+*
+* Use of ACM Algorithms is subject to the ACM Software Copyright and
+* License Agreement. See <http://www.acm.org/publications/policies>.
+*
+* The translation was made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "mc13d.h"
+
+/***********************************************************************
+* NAME
+*
+* mc13d - permutations to block triangular form
+*
+* SYNOPSIS
+*
+* #include "mc13d.h"
+* int mc13d(int n, const int icn[], const int ip[], const int lenr[],
+* int ior[], int ib[], int lowl[], int numb[], int prev[]);
+*
+* DESCRIPTION
+*
+* Given the column numbers of the nonzeros in each row of the sparse
+* matrix, the routine mc13d finds a symmetric permutation that makes
+* the matrix block lower triangular.
+*
+* INPUT PARAMETERS
+*
+* n order of the matrix.
+*
+* icn array containing the column indices of the non-zeros. Those
+* belonging to a single row must be contiguous but the ordering
+* of column indices within each row is unimportant and wasted
+* space between rows is permitted.
+*
+* ip ip[i], i = 1,2,...,n, is the position in array icn of the
+* first column index of a non-zero in row i.
+*
+* lenr lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
+*
+* OUTPUT PARAMETERS
+*
+* ior ior[i], i = 1,2,...,n, gives the position on the original
+* ordering of the row or column which is in position i in the
+* permuted form.
+*
+* ib ib[i], i = 1,2,...,num, is the row number in the permuted
+* matrix of the beginning of block i, 1 <= num <= n.
+*
+* WORKING ARRAYS
+*
+* arp working array of length [1+n], where arp[0] is not used.
+* arp[i] is one less than the number of unsearched edges leaving
+* node i. At the end of the algorithm it is set to a permutation
+* which puts the matrix in block lower triangular form.
+*
+* ib working array of length [1+n], where ib[0] is not used.
+* ib[i] is the position in the ordering of the start of the ith
+* block. ib[n+1-i] holds the node number of the ith node on the
+* stack.
+*
+* lowl working array of length [1+n], where lowl[0] is not used.
+* lowl[i] is the smallest stack position of any node to which a
+* path from node i has been found. It is set to n+1 when node i
+* is removed from the stack.
+*
+* numb working array of length [1+n], where numb[0] is not used.
+* numb[i] is the position of node i in the stack if it is on it,
+* is the permuted order of node i for those nodes whose final
+* position has been found and is otherwise zero.
+*
+* prev working array of length [1+n], where prev[0] is not used.
+* prev[i] is the node at the end of the path when node i was
+* placed on the stack.
+*
+* RETURNS
+*
+* The routine mc13d returns num, the number of blocks found. */
+
+int mc13d(int n, const int icn[], const int ip[], const int lenr[],
+ int ior[], int ib[], int lowl[], int numb[], int prev[])
+{ int *arp = ior;
+ int dummy, i, i1, i2, icnt, ii, isn, ist, ist1, iv, iw, j, lcnt,
+ nnm1, num, stp;
+ /* icnt is the number of nodes whose positions in final ordering
+ * have been found. */
+ icnt = 0;
+ /* num is the number of blocks that have been found. */
+ num = 0;
+ nnm1 = n + n - 1;
+ /* Initialization of arrays. */
+ for (j = 1; j <= n; j++)
+ { numb[j] = 0;
+ arp[j] = lenr[j] - 1;
+ }
+ for (isn = 1; isn <= n; isn++)
+ { /* Look for a starting node. */
+ if (numb[isn] != 0) continue;
+ iv = isn;
+ /* ist is the number of nodes on the stack ... it is the stack
+ * pointer. */
+ ist = 1;
+ /* Put node iv at beginning of stack. */
+ lowl[iv] = numb[iv] = 1;
+ ib[n] = iv;
+ /* The body of this loop puts a new node on the stack or
+ * backtracks. */
+ for (dummy = 1; dummy <= nnm1; dummy++)
+ { i1 = arp[iv];
+ /* Have all edges leaving node iv been searched? */
+ if (i1 >= 0)
+ { i2 = ip[iv] + lenr[iv] - 1;
+ i1 = i2 - i1;
+ /* Look at edges leaving node iv until one enters a new
+ * node or all edges are exhausted. */
+ for (ii = i1; ii <= i2; ii++)
+ { iw = icn[ii];
+ /* Has node iw been on stack already? */
+ if (numb[iw] == 0) goto L70;
+ /* Update value of lowl[iv] if necessary. */
+ if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
+ }
+ /* There are no more edges leaving node iv. */
+ arp[iv] = -1;
+ }
+ /* Is node iv the root of a block? */
+ if (lowl[iv] < numb[iv]) goto L60;
+ /* Order nodes in a block. */
+ num++;
+ ist1 = n + 1 - ist;
+ lcnt = icnt + 1;
+ /* Peel block off the top of the stack starting at the top
+ * and working down to the root of the block. */
+ for (stp = ist1; stp <= n; stp++)
+ { iw = ib[stp];
+ lowl[iw] = n + 1;
+ numb[iw] = ++icnt;
+ if (iw == iv) break;
+ }
+ ist = n - stp;
+ ib[num] = lcnt;
+ /* Are there any nodes left on the stack? */
+ if (ist != 0) goto L60;
+ /* Have all the nodes been ordered? */
+ if (icnt < n) break;
+ goto L100;
+L60: /* Backtrack to previous node on path. */
+ iw = iv;
+ iv = prev[iv];
+ /* Update value of lowl[iv] if necessary. */
+ if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
+ continue;
+L70: /* Put new node on the stack. */
+ arp[iv] = i2 - ii - 1;
+ prev[iw] = iv;
+ iv = iw;
+ lowl[iv] = numb[iv] = ++ist;
+ ib[n+1-ist] = iv;
+ }
+ }
+L100: /* Put permutation in the required form. */
+ for (i = 1; i <= n; i++)
+ arp[numb[i]] = i;
+ return num;
+}
+
+/**********************************************************************/
+
+#ifdef GLP_TEST
+#include "env.h"
+
+void test(int n, int ipp);
+
+int main(void)
+{ /* test program for routine mc13d */
+ test( 1, 0);
+ test( 2, 1);
+ test( 2, 2);
+ test( 3, 3);
+ test( 4, 4);
+ test( 5, 10);
+ test(10, 10);
+ test(10, 20);
+ test(20, 20);
+ test(20, 50);
+ test(50, 50);
+ test(50, 200);
+ return 0;
+}
+
+void fa01bs(int max, int *nrand);
+
+void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]);
+
+void test(int n, int ipp)
+{ int ip[1+50], icn[1+1000], ior[1+50], ib[1+51], iw[1+150],
+ lenr[1+50];
+ char a[1+50][1+50], hold[1+100];
+ int i, ii, iblock, ij, index, j, jblock, jj, k9, num;
+ xprintf("\n\n\nMatrix is of order %d and has %d off-diagonal non-"
+ "zeros\n", n, ipp);
+ for (j = 1; j <= n; j++)
+ { for (i = 1; i <= n; i++)
+ a[i][j] = 0;
+ a[j][j] = 1;
+ }
+ for (k9 = 1; k9 <= ipp; k9++)
+ { /* these statements should be replaced by calls to your
+ * favorite random number generator to place two pseudo-random
+ * numbers between 1 and n in the variables i and j */
+ for (;;)
+ { fa01bs(n, &i);
+ fa01bs(n, &j);
+ if (!a[i][j]) break;
+ }
+ a[i][j] = 1;
+ }
+ /* setup converts matrix a[i,j] to required sparsity-oriented
+ * storage format */
+ setup(n, a, ip, icn, lenr);
+ num = mc13d(n, icn, ip, lenr, ior, ib, &iw[0], &iw[n], &iw[n+n]);
+ /* output reordered matrix with blocking to improve clarity */
+ xprintf("\nThe reordered matrix which has %d block%s is of the fo"
+ "rm\n", num, num == 1 ? "" : "s");
+ ib[num+1] = n + 1;
+ index = 100;
+ iblock = 1;
+ for (i = 1; i <= n; i++)
+ { for (ij = 1; ij <= index; ij++)
+ hold[ij] = ' ';
+ if (i == ib[iblock])
+ { xprintf("\n");
+ iblock++;
+ }
+ jblock = 1;
+ index = 0;
+ for (j = 1; j <= n; j++)
+ { if (j == ib[jblock])
+ { hold[++index] = ' ';
+ jblock++;
+ }
+ ii = ior[i];
+ jj = ior[j];
+ hold[++index] = (char)(a[ii][jj] ? 'X' : '0');
+ }
+ xprintf("%.*s\n", index, &hold[1]);
+ }
+ xprintf("\nThe starting point for each block is given by\n");
+ for (i = 1; i <= num; i++)
+ { if ((i - 1) % 12 == 0) xprintf("\n");
+ xprintf(" %4d", ib[i]);
+ }
+ xprintf("\n");
+ return;
+}
+
+void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[])
+{ int i, j, ind;
+ for (i = 1; i <= n; i++)
+ lenr[i] = 0;
+ ind = 1;
+ for (i = 1; i <= n; i++)
+ { ip[i] = ind;
+ for (j = 1; j <= n; j++)
+ { if (a[i][j])
+ { lenr[i]++;
+ icn[ind++] = j;
+ }
+ }
+ }
+ return;
+}
+
+double g = 1431655765.0;
+
+double fa01as(int i)
+{ /* random number generator */
+ g = fmod(g * 9228907.0, 4294967296.0);
+ if (i >= 0)
+ return g / 4294967296.0;
+ else
+ return 2.0 * g / 4294967296.0 - 1.0;
+}
+
+void fa01bs(int max, int *nrand)
+{ *nrand = (int)(fa01as(1) * (double)max) + 1;
+ return;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/mc13d.h b/test/monniaux/glpk-4.65/src/misc/mc13d.h
new file mode 100644
index 00000000..bdd57a19
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/mc13d.h
@@ -0,0 +1,34 @@
+/* mc13d.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2013 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/>.
+***********************************************************************/
+
+#ifndef MC13D_H
+#define MC13D_H
+
+#define mc13d _glp_mc13d
+int mc13d(int n, const int icn[], const int ip[], const int lenr[],
+ int ior[], int ib[], int lowl[], int numb[], int prev[]);
+/* permutations to block triangular form */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/mc21a.c b/test/monniaux/glpk-4.65/src/misc/mc21a.c
new file mode 100644
index 00000000..700d0f4e
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/mc21a.c
@@ -0,0 +1,301 @@
+/* mc21a.c (permutations for zero-free diagonal) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* This code is the result of translation of the Fortran subroutines
+* MC21A and MC21B associated with the following paper:
+*
+* I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
+* Trans. on Math. Softw. 7 (1981), 387-390.
+*
+* Use of ACM Algorithms is subject to the ACM Software Copyright and
+* License Agreement. See <http://www.acm.org/publications/policies>.
+*
+* The translation was made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "mc21a.h"
+
+/***********************************************************************
+* NAME
+*
+* mc21a - permutations for zero-free diagonal
+*
+* SYNOPSIS
+*
+* #include "mc21a.h"
+* int mc21a(int n, const int icn[], const int ip[], const int lenr[],
+* int iperm[], int pr[], int arp[], int cv[], int out[]);
+*
+* DESCRIPTION
+*
+* Given the pattern of nonzeros of a sparse matrix, the routine mc21a
+* attempts to find a permutation of its rows that makes the matrix have
+* no zeros on its diagonal.
+*
+* INPUT PARAMETERS
+*
+* n order of matrix.
+*
+* icn array containing the column indices of the non-zeros. Those
+* belonging to a single row must be contiguous but the ordering
+* of column indices within each row is unimportant and wasted
+* space between rows is permitted.
+*
+* ip ip[i], i = 1,2,...,n, is the position in array icn of the
+* first column index of a non-zero in row i.
+*
+* lenr lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
+*
+* OUTPUT PARAMETER
+*
+* iperm contains permutation to make diagonal have the smallest
+* number of zeros on it. Elements (iperm[i], i), i = 1,2,...,n,
+* are non-zero at the end of the algorithm unless the matrix is
+* structurally singular. In this case, (iperm[i], i) will be
+* zero for n - numnz entries.
+*
+* WORKING ARRAYS
+*
+* pr working array of length [1+n], where pr[0] is not used.
+* pr[i] is the previous row to i in the depth first search.
+*
+* arp working array of length [1+n], where arp[0] is not used.
+* arp[i] is one less than the number of non-zeros in row i which
+* have not been scanned when looking for a cheap assignment.
+*
+* cv working array of length [1+n], where cv[0] is not used.
+* cv[i] is the most recent row extension at which column i was
+* visited.
+*
+* out working array of length [1+n], where out[0] is not used.
+* out[i] is one less than the number of non-zeros in row i
+* which have not been scanned during one pass through the main
+* loop.
+*
+* RETURNS
+*
+* The routine mc21a returns numnz, the number of non-zeros on diagonal
+* of permuted matrix. */
+
+int mc21a(int n, const int icn[], const int ip[], const int lenr[],
+ int iperm[], int pr[], int arp[], int cv[], int out[])
+{ int i, ii, in1, in2, j, j1, jord, k, kk, numnz;
+ /* Initialization of arrays. */
+ for (i = 1; i <= n; i++)
+ { arp[i] = lenr[i] - 1;
+ cv[i] = iperm[i] = 0;
+ }
+ numnz = 0;
+ /* Main loop. */
+ /* Each pass round this loop either results in a new assignment
+ * or gives a row with no assignment. */
+ for (jord = 1; jord <= n; jord++)
+ { j = jord;
+ pr[j] = -1;
+ for (k = 1; k <= jord; k++)
+ { /* Look for a cheap assignment. */
+ in1 = arp[j];
+ if (in1 >= 0)
+ { in2 = ip[j] + lenr[j] - 1;
+ in1 = in2 - in1;
+ for (ii = in1; ii <= in2; ii++)
+ { i = icn[ii];
+ if (iperm[i] == 0) goto L110;
+ }
+ /* No cheap assignment in row. */
+ arp[j] = -1;
+ }
+ /* Begin looking for assignment chain starting with row j.*/
+ out[j] = lenr[j] - 1;
+ /* Inner loop. Extends chain by one or backtracks. */
+ for (kk = 1; kk <= jord; kk++)
+ { in1 = out[j];
+ if (in1 >= 0)
+ { in2 = ip[j] + lenr[j] - 1;
+ in1 = in2 - in1;
+ /* Forward scan. */
+ for (ii = in1; ii <= in2; ii++)
+ { i = icn[ii];
+ if (cv[i] != jord)
+ { /* Column i has not yet been accessed during
+ * this pass. */
+ j1 = j;
+ j = iperm[i];
+ cv[i] = jord;
+ pr[j] = j1;
+ out[j1] = in2 - ii - 1;
+ goto L100;
+ }
+ }
+ }
+ /* Backtracking step. */
+ j = pr[j];
+ if (j == -1) goto L130;
+ }
+L100: ;
+ }
+L110: /* New assignment is made. */
+ iperm[i] = j;
+ arp[j] = in2 - ii - 1;
+ numnz++;
+ for (k = 1; k <= jord; k++)
+ { j = pr[j];
+ if (j == -1) break;
+ ii = ip[j] + lenr[j] - out[j] - 2;
+ i = icn[ii];
+ iperm[i] = j;
+ }
+L130: ;
+ }
+ /* If matrix is structurally singular, we now complete the
+ * permutation iperm. */
+ if (numnz < n)
+ { for (i = 1; i <= n; i++)
+ arp[i] = 0;
+ k = 0;
+ for (i = 1; i <= n; i++)
+ { if (iperm[i] == 0)
+ out[++k] = i;
+ else
+ arp[iperm[i]] = i;
+ }
+ k = 0;
+ for (i = 1; i <= n; i++)
+ { if (arp[i] == 0)
+ iperm[out[++k]] = i;
+ }
+ }
+ return numnz;
+}
+
+/**********************************************************************/
+
+#ifdef GLP_TEST
+#include "env.h"
+
+int sing;
+
+void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum,
+ int iw[]);
+
+void fa01bs(int max, int *nrand);
+
+int main(void)
+{ /* test program for the routine mc21a */
+ /* these runs on random matrices cause all possible statements in
+ * mc21a to be executed */
+ int i, iold, j, j1, j2, jj, knum, l, licn, n, nov4, num, numnz;
+ int ip[1+21], icn[1+1000], iperm[1+20], lenr[1+20], iw1[1+80];
+ licn = 1000;
+ /* run on random matrices of orders 1 through 20 */
+ for (n = 1; n <= 20; n++)
+ { nov4 = n / 4;
+ if (nov4 < 1) nov4 = 1;
+L10: fa01bs(nov4, &l);
+ knum = l * n;
+ /* knum is requested number of non-zeros in random matrix */
+ if (knum > licn) goto L10;
+ /* if sing is false, matrix is guaranteed structurally
+ * non-singular */
+ sing = ((n / 2) * 2 == n);
+ /* call to subroutine to generate random matrix */
+ ranmat(n, n, icn, ip, n+1, &knum, iw1);
+ /* knum is now actual number of non-zeros in random matrix */
+ if (knum > licn) goto L10;
+ xprintf("n = %2d; nz = %4d; sing = %d\n", n, knum, sing);
+ /* set up array of row lengths */
+ for (i = 1; i <= n; i++)
+ lenr[i] = ip[i+1] - ip[i];
+ /* call to mc21a */
+ numnz = mc21a(n, icn, ip, lenr, iperm, &iw1[0], &iw1[n],
+ &iw1[n+n], &iw1[n+n+n]);
+ /* testing to see if there are numnz non-zeros on the diagonal
+ * of the permuted matrix. */
+ num = 0;
+ for (i = 1; i <= n; i++)
+ { iold = iperm[i];
+ j1 = ip[iold];
+ j2 = j1 + lenr[iold] - 1;
+ if (j2 < j1) continue;
+ for (jj = j1; jj <= j2; jj++)
+ { j = icn[jj];
+ if (j == i)
+ { num++;
+ break;
+ }
+ }
+ }
+ if (num != numnz)
+ xprintf("Failure in mc21a, numnz = %d instead of %d\n",
+ numnz, num);
+ }
+ return 0;
+}
+
+void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum,
+ int iw[])
+{ /* subroutine to generate random matrix */
+ int i, ii, inum, j, lrow, matnum;
+ inum = (*knum / n) * 2;
+ if (inum > n-1) inum = n-1;
+ matnum = 1;
+ /* each pass through this loop generates a row of the matrix */
+ for (j = 1; j <= m; j++)
+ { iptr[j] = matnum;
+ if (!(sing || j > n))
+ icn[matnum++] = j;
+ if (n == 1) continue;
+ for (i = 1; i <= n; i++) iw[i] = 0;
+ if (!sing) iw[j] = 1;
+ fa01bs(inum, &lrow);
+ lrow--;
+ if (lrow == 0) continue;
+ /* lrow off-diagonal non-zeros in row j of the matrix */
+ for (ii = 1; ii <= lrow; ii++)
+ { for (;;)
+ { fa01bs(n, &i);
+ if (iw[i] != 1) break;
+ }
+ iw[i] = 1;
+ icn[matnum++] = i;
+ }
+ }
+ for (i = m+1; i <= nnnp1; i++)
+ iptr[i] = matnum;
+ *knum = matnum - 1;
+ return;
+}
+
+double g = 1431655765.0;
+
+double fa01as(int i)
+{ /* random number generator */
+ g = fmod(g * 9228907.0, 4294967296.0);
+ if (i >= 0)
+ return g / 4294967296.0;
+ else
+ return 2.0 * g / 4294967296.0 - 1.0;
+}
+
+void fa01bs(int max, int *nrand)
+{ *nrand = (int)(fa01as(1) * (double)max) + 1;
+ return;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/mc21a.h b/test/monniaux/glpk-4.65/src/misc/mc21a.h
new file mode 100644
index 00000000..755f28b2
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/mc21a.h
@@ -0,0 +1,34 @@
+/* mc21a.h (permutations for zero-free diagonal) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2013 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/>.
+***********************************************************************/
+
+#ifndef MC21A_H
+#define MC21A_H
+
+#define mc21a _glp_mc21a
+int mc21a(int n, const int icn[], const int ip[], const int lenr[],
+ int iperm[], int pr[], int arp[], int cv[], int out[]);
+/* permutations for zero-free diagonal */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/misc.h b/test/monniaux/glpk-4.65/src/misc/misc.h
new file mode 100644
index 00000000..1ba1dc50
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/misc.h
@@ -0,0 +1,61 @@
+/* misc.h (miscellaneous routines) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#ifndef MISC_H
+#define MISC_H
+
+#define str2int _glp_str2int
+int str2int(const char *str, int *val);
+/* convert character string to value of int type */
+
+#define str2num _glp_str2num
+int str2num(const char *str, double *val);
+/* convert character string to value of double type */
+
+#define strspx _glp_strspx
+char *strspx(char *str);
+/* remove all spaces from character string */
+
+#define strtrim _glp_strtrim
+char *strtrim(char *str);
+/* remove trailing spaces from character string */
+
+#define gcd _glp_gcd
+int gcd(int x, int y);
+/* find greatest common divisor of two integers */
+
+#define gcdn _glp_gcdn
+int gcdn(int n, int x[]);
+/* find greatest common divisor of n integers */
+
+#define round2n _glp_round2n
+double round2n(double x);
+/* round floating-point number to nearest power of two */
+
+#define fp2rat _glp_fp2rat
+int fp2rat(double x, double eps, double *p, double *q);
+/* convert floating-point number to rational number */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/mt1.c b/test/monniaux/glpk-4.65/src/misc/mt1.c
new file mode 100644
index 00000000..63a0f80e
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/mt1.c
@@ -0,0 +1,1110 @@
+/* mt1.c (0-1 knapsack problem; Martello & Toth algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES
+* MT1 FROM THE BOOK:
+*
+* SILVANO MARTELLO, PAOLO TOTH. KNAPSACK PROBLEMS: ALGORITHMS AND
+* COMPUTER IMPLEMENTATIONS. JOHN WILEY & SONS, 1990.
+*
+* THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS OF
+* THE ORIGINAL FORTRAN SUBROUTINES: SILVANO MARTELLO AND PAOLO TOTH.
+*
+* The translation was made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#line 1 ""
+/* -- translated by f2c (version 20100827).
+ You must link the resulting object file with libf2c:
+ on Microsoft Windows system, link with libf2c.lib;
+ on Linux or Unix systems, link with .../path/to/libf2c.a -lm
+ or, if you install libf2c.a in a standard place, with -lf2c -lm
+ -- in that order, at the end of the command line, as in
+ cc *.o -lf2c -lm
+ Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
+
+ http://www.netlib.org/f2c/libf2c.zip
+*/
+
+#if 0 /* by mao */
+#include "f2c.h"
+#else
+#include "env.h"
+#include "mt1.h"
+
+typedef int integer;
+typedef float real;
+#endif
+
+#line 1 ""
+/*< SUBROUTINE MT1(N,P,W,C,Z,X,JDIM,JCK,XX,MIN,PSIGN,WSIGN,ZSIGN) >*/
+#if 1 /* by mao */
+static int chmt1_(int *, int *, int *, int *, int *, int *);
+
+static
+#endif
+/* Subroutine */ int mt1_(integer *n, integer *p, integer *w, integer *c__,
+ integer *z__, integer *x, integer *jdim, integer *jck, integer *xx,
+ integer *min__, integer *psign, integer *wsign, integer *zsign)
+{
+ /* System generated locals */
+ integer i__1;
+
+ /* Local variables */
+ static real a, b;
+ static integer j, r__, t, j1, n1, ch, ii, jj, kk, in, ll, ip, nn, iu, ii1,
+ chs, lim, lim1, diff, lold, mink;
+ extern /* Subroutine */ int chmt1_(integer *, integer *, integer *,
+ integer *, integer *, integer *);
+ static integer profit;
+
+
+/* THIS SUBROUTINE SOLVES THE 0-1 SINGLE KNAPSACK PROBLEM */
+
+/* MAXIMIZE Z = P(1)*X(1) + ... + P(N)*X(N) */
+
+/* SUBJECT TO: W(1)*X(1) + ... + W(N)*X(N) .LE. C , */
+/* X(J) = 0 OR 1 FOR J=1,...,N. */
+
+/* THE PROGRAM IS INCLUDED IN THE VOLUME */
+/* S. MARTELLO, P. TOTH, "KNAPSACK PROBLEMS: ALGORITHMS */
+/* AND COMPUTER IMPLEMENTATIONS", JOHN WILEY, 1990 */
+/* AND IMPLEMENTS THE BRANCH-AND-BOUND ALGORITHM DESCRIBED IN */
+/* SECTION 2.5.2 . */
+/* THE PROGRAM DERIVES FROM AN EARLIER CODE PRESENTED IN */
+/* S. MARTELLO, P. TOTH, "ALGORITHM FOR THE SOLUTION OF THE 0-1 SINGLE */
+/* KNAPSACK PROBLEM", COMPUTING, 1978. */
+
+/* THE INPUT PROBLEM MUST SATISFY THE CONDITIONS */
+
+/* 1) 2 .LE. N .LE. JDIM - 1 ; */
+/* 2) P(J), W(J), C POSITIVE INTEGERS; */
+/* 3) MAX (W(J)) .LE. C ; */
+/* 4) W(1) + ... + W(N) .GT. C ; */
+/* 5) P(J)/W(J) .GE. P(J+1)/W(J+1) FOR J=1,...,N-1. */
+
+/* MT1 CALLS 1 PROCEDURE: CHMT1. */
+
+/* THE PROGRAM IS COMPLETELY SELF-CONTAINED AND COMMUNICATION TO IT IS */
+/* ACHIEVED SOLELY THROUGH THE PARAMETER LIST OF MT1. */
+/* NO MACHINE-DEPENDENT CONSTANT IS USED. */
+/* THE PROGRAM IS WRITTEN IN 1967 AMERICAN NATIONAL STANDARD FORTRAN */
+/* AND IS ACCEPTED BY THE PFORT VERIFIER (PFORT IS THE PORTABLE */
+/* SUBSET OF ANSI DEFINED BY THE ASSOCIATION FOR COMPUTING MACHINERY). */
+/* THE PROGRAM HAS BEEN TESTED ON A DIGITAL VAX 11/780 AND AN H.P. */
+/* 9000/840. */
+
+/* MT1 NEEDS 8 ARRAYS ( P , W , X , XX , MIN , PSIGN , WSIGN */
+/* AND ZSIGN ) OF LENGTH AT LEAST N + 1 . */
+
+/* MEANING OF THE INPUT PARAMETERS: */
+/* N = NUMBER OF ITEMS; */
+/* P(J) = PROFIT OF ITEM J (J=1,...,N); */
+/* W(J) = WEIGHT OF ITEM J (J=1,...,N); */
+/* C = CAPACITY OF THE KNAPSACK; */
+/* JDIM = DIMENSION OF THE 8 ARRAYS; */
+/* JCK = 1 IF CHECK ON THE INPUT DATA IS DESIRED, */
+/* = 0 OTHERWISE. */
+
+/* MEANING OF THE OUTPUT PARAMETERS: */
+/* Z = VALUE OF THE OPTIMAL SOLUTION IF Z .GT. 0 , */
+/* = ERROR IN THE INPUT DATA (WHEN JCK=1) IF Z .LT. 0 : CONDI- */
+/* TION - Z IS VIOLATED; */
+/* X(J) = 1 IF ITEM J IS IN THE OPTIMAL SOLUTION, */
+/* = 0 OTHERWISE. */
+
+/* ARRAYS XX, MIN, PSIGN, WSIGN AND ZSIGN ARE DUMMY. */
+
+/* ALL THE PARAMETERS ARE INTEGER. ON RETURN OF MT1 ALL THE INPUT */
+/* PARAMETERS ARE UNCHANGED. */
+
+/*< INTEGER P(JDIM),W(JDIM),X(JDIM),C,Z >*/
+/*< INTEGER XX(JDIM),MIN(JDIM),PSIGN(JDIM),WSIGN(JDIM),ZSIGN(JDIM) >*/
+/*< INTEGER CH,CHS,DIFF,PROFIT,R,T >*/
+/*< Z = 0 >*/
+#line 65 ""
+ /* Parameter adjustments */
+#line 65 ""
+ --zsign;
+#line 65 ""
+ --wsign;
+#line 65 ""
+ --psign;
+#line 65 ""
+ --min__;
+#line 65 ""
+ --xx;
+#line 65 ""
+ --x;
+#line 65 ""
+ --w;
+#line 65 ""
+ --p;
+#line 65 ""
+
+#line 65 ""
+ /* Function Body */
+#line 65 ""
+ *z__ = 0;
+/*< IF ( JCK .EQ. 1 ) CALL CHMT1(N,P,W,C,Z,JDIM) >*/
+#line 66 ""
+ if (*jck == 1) {
+#line 66 ""
+ chmt1_(n, &p[1], &w[1], c__, z__, jdim);
+#line 66 ""
+ }
+/*< IF ( Z .LT. 0 ) RETURN >*/
+#line 67 ""
+ if (*z__ < 0) {
+#line 67 ""
+ return 0;
+#line 67 ""
+ }
+/* INITIALIZE. */
+/*< CH = C >*/
+#line 69 ""
+ ch = *c__;
+/*< IP = 0 >*/
+#line 70 ""
+ ip = 0;
+/*< CHS = CH >*/
+#line 71 ""
+ chs = ch;
+/*< DO 10 LL=1,N >*/
+#line 72 ""
+ i__1 = *n;
+#line 72 ""
+ for (ll = 1; ll <= i__1; ++ll) {
+/*< IF ( W(LL) .GT. CHS ) GO TO 20 >*/
+#line 73 ""
+ if (w[ll] > chs) {
+#line 73 ""
+ goto L20;
+#line 73 ""
+ }
+/*< IP = IP + P(LL) >*/
+#line 74 ""
+ ip += p[ll];
+/*< CHS = CHS - W(LL) >*/
+#line 75 ""
+ chs -= w[ll];
+/*< 10 CONTINUE >*/
+#line 76 ""
+/* L10: */
+#line 76 ""
+ }
+/*< 20 LL = LL - 1 >*/
+#line 77 ""
+L20:
+#line 77 ""
+ --ll;
+/*< IF ( CHS .EQ. 0 ) GO TO 50 >*/
+#line 78 ""
+ if (chs == 0) {
+#line 78 ""
+ goto L50;
+#line 78 ""
+ }
+/*< P(N+1) = 0 >*/
+#line 79 ""
+ p[*n + 1] = 0;
+/*< W(N+1) = CH + 1 >*/
+#line 80 ""
+ w[*n + 1] = ch + 1;
+/*< LIM = IP + CHS*P(LL+2)/W(LL+2) >*/
+#line 81 ""
+ lim = ip + chs * p[ll + 2] / w[ll + 2];
+/*< A = W(LL+1) - CHS >*/
+#line 82 ""
+ a = (real) (w[ll + 1] - chs);
+/*< B = IP + P(LL+1) >*/
+#line 83 ""
+ b = (real) (ip + p[ll + 1]);
+/*< LIM1 = B - A*FLOAT(P(LL))/FLOAT(W(LL)) >*/
+#line 84 ""
+ lim1 = b - a * (real) p[ll] / (real) w[ll];
+/*< IF ( LIM1 .GT. LIM ) LIM = LIM1 >*/
+#line 85 ""
+ if (lim1 > lim) {
+#line 85 ""
+ lim = lim1;
+#line 85 ""
+ }
+/*< MINK = CH + 1 >*/
+#line 86 ""
+ mink = ch + 1;
+/*< MIN(N) = MINK >*/
+#line 87 ""
+ min__[*n] = mink;
+/*< DO 30 J=2,N >*/
+#line 88 ""
+ i__1 = *n;
+#line 88 ""
+ for (j = 2; j <= i__1; ++j) {
+/*< KK = N + 2 - J >*/
+#line 89 ""
+ kk = *n + 2 - j;
+/*< IF ( W(KK) .LT. MINK ) MINK = W(KK) >*/
+#line 90 ""
+ if (w[kk] < mink) {
+#line 90 ""
+ mink = w[kk];
+#line 90 ""
+ }
+/*< MIN(KK-1) = MINK >*/
+#line 91 ""
+ min__[kk - 1] = mink;
+/*< 30 CONTINUE >*/
+#line 92 ""
+/* L30: */
+#line 92 ""
+ }
+/*< DO 40 J=1,N >*/
+#line 93 ""
+ i__1 = *n;
+#line 93 ""
+ for (j = 1; j <= i__1; ++j) {
+/*< XX(J) = 0 >*/
+#line 94 ""
+ xx[j] = 0;
+/*< 40 CONTINUE >*/
+#line 95 ""
+/* L40: */
+#line 95 ""
+ }
+/*< Z = 0 >*/
+#line 96 ""
+ *z__ = 0;
+/*< PROFIT = 0 >*/
+#line 97 ""
+ profit = 0;
+/*< LOLD = N >*/
+#line 98 ""
+ lold = *n;
+/*< II = 1 >*/
+#line 99 ""
+ ii = 1;
+/*< GO TO 170 >*/
+#line 100 ""
+ goto L170;
+/*< 50 Z = IP >*/
+#line 101 ""
+L50:
+#line 101 ""
+ *z__ = ip;
+/*< DO 60 J=1,LL >*/
+#line 102 ""
+ i__1 = ll;
+#line 102 ""
+ for (j = 1; j <= i__1; ++j) {
+/*< X(J) = 1 >*/
+#line 103 ""
+ x[j] = 1;
+/*< 60 CONTINUE >*/
+#line 104 ""
+/* L60: */
+#line 104 ""
+ }
+/*< NN = LL + 1 >*/
+#line 105 ""
+ nn = ll + 1;
+/*< DO 70 J=NN,N >*/
+#line 106 ""
+ i__1 = *n;
+#line 106 ""
+ for (j = nn; j <= i__1; ++j) {
+/*< X(J) = 0 >*/
+#line 107 ""
+ x[j] = 0;
+/*< 70 CONTINUE >*/
+#line 108 ""
+/* L70: */
+#line 108 ""
+ }
+/*< RETURN >*/
+#line 109 ""
+ return 0;
+/* TRY TO INSERT THE II-TH ITEM INTO THE CURRENT SOLUTION. */
+/*< 80 IF ( W(II) .LE. CH ) GO TO 90 >*/
+#line 111 ""
+L80:
+#line 111 ""
+ if (w[ii] <= ch) {
+#line 111 ""
+ goto L90;
+#line 111 ""
+ }
+/*< II1 = II + 1 >*/
+#line 112 ""
+ ii1 = ii + 1;
+/*< IF ( Z .GE. CH*P(II1)/W(II1) + PROFIT ) GO TO 280 >*/
+#line 113 ""
+ if (*z__ >= ch * p[ii1] / w[ii1] + profit) {
+#line 113 ""
+ goto L280;
+#line 113 ""
+ }
+/*< II = II1 >*/
+#line 114 ""
+ ii = ii1;
+/*< GO TO 80 >*/
+#line 115 ""
+ goto L80;
+/* BUILD A NEW CURRENT SOLUTION. */
+/*< 90 IP = PSIGN(II) >*/
+#line 117 ""
+L90:
+#line 117 ""
+ ip = psign[ii];
+/*< CHS = CH - WSIGN(II) >*/
+#line 118 ""
+ chs = ch - wsign[ii];
+/*< IN = ZSIGN(II) >*/
+#line 119 ""
+ in = zsign[ii];
+/*< DO 100 LL=IN,N >*/
+#line 120 ""
+ i__1 = *n;
+#line 120 ""
+ for (ll = in; ll <= i__1; ++ll) {
+/*< IF ( W(LL) .GT. CHS ) GO TO 160 >*/
+#line 121 ""
+ if (w[ll] > chs) {
+#line 121 ""
+ goto L160;
+#line 121 ""
+ }
+/*< IP = IP + P(LL) >*/
+#line 122 ""
+ ip += p[ll];
+/*< CHS = CHS - W(LL) >*/
+#line 123 ""
+ chs -= w[ll];
+/*< 100 CONTINUE >*/
+#line 124 ""
+/* L100: */
+#line 124 ""
+ }
+/*< LL = N >*/
+#line 125 ""
+ ll = *n;
+/*< 110 IF ( Z .GE. IP + PROFIT ) GO TO 280 >*/
+#line 126 ""
+L110:
+#line 126 ""
+ if (*z__ >= ip + profit) {
+#line 126 ""
+ goto L280;
+#line 126 ""
+ }
+/*< Z = IP + PROFIT >*/
+#line 127 ""
+ *z__ = ip + profit;
+/*< NN = II - 1 >*/
+#line 128 ""
+ nn = ii - 1;
+/*< DO 120 J=1,NN >*/
+#line 129 ""
+ i__1 = nn;
+#line 129 ""
+ for (j = 1; j <= i__1; ++j) {
+/*< X(J) = XX(J) >*/
+#line 130 ""
+ x[j] = xx[j];
+/*< 120 CONTINUE >*/
+#line 131 ""
+/* L120: */
+#line 131 ""
+ }
+/*< DO 130 J=II,LL >*/
+#line 132 ""
+ i__1 = ll;
+#line 132 ""
+ for (j = ii; j <= i__1; ++j) {
+/*< X(J) = 1 >*/
+#line 133 ""
+ x[j] = 1;
+/*< 130 CONTINUE >*/
+#line 134 ""
+/* L130: */
+#line 134 ""
+ }
+/*< IF ( LL .EQ. N ) GO TO 150 >*/
+#line 135 ""
+ if (ll == *n) {
+#line 135 ""
+ goto L150;
+#line 135 ""
+ }
+/*< NN = LL + 1 >*/
+#line 136 ""
+ nn = ll + 1;
+/*< DO 140 J=NN,N >*/
+#line 137 ""
+ i__1 = *n;
+#line 137 ""
+ for (j = nn; j <= i__1; ++j) {
+/*< X(J) = 0 >*/
+#line 138 ""
+ x[j] = 0;
+/*< 140 CONTINUE >*/
+#line 139 ""
+/* L140: */
+#line 139 ""
+ }
+/*< 150 IF ( Z .NE. LIM ) GO TO 280 >*/
+#line 140 ""
+L150:
+#line 140 ""
+ if (*z__ != lim) {
+#line 140 ""
+ goto L280;
+#line 140 ""
+ }
+/*< RETURN >*/
+#line 141 ""
+ return 0;
+/*< 160 IU = CHS*P(LL)/W(LL) >*/
+#line 142 ""
+L160:
+#line 142 ""
+ iu = chs * p[ll] / w[ll];
+/*< LL = LL - 1 >*/
+#line 143 ""
+ --ll;
+/*< IF ( IU .EQ. 0 ) GO TO 110 >*/
+#line 144 ""
+ if (iu == 0) {
+#line 144 ""
+ goto L110;
+#line 144 ""
+ }
+/*< IF ( Z .GE. PROFIT + IP + IU ) GO TO 280 >*/
+#line 145 ""
+ if (*z__ >= profit + ip + iu) {
+#line 145 ""
+ goto L280;
+#line 145 ""
+ }
+/* SAVE THE CURRENT SOLUTION. */
+/*< 170 WSIGN(II) = CH - CHS >*/
+#line 147 ""
+L170:
+#line 147 ""
+ wsign[ii] = ch - chs;
+/*< PSIGN(II) = IP >*/
+#line 148 ""
+ psign[ii] = ip;
+/*< ZSIGN(II) = LL + 1 >*/
+#line 149 ""
+ zsign[ii] = ll + 1;
+/*< XX(II) = 1 >*/
+#line 150 ""
+ xx[ii] = 1;
+/*< NN = LL - 1 >*/
+#line 151 ""
+ nn = ll - 1;
+/*< IF ( NN .LT. II) GO TO 190 >*/
+#line 152 ""
+ if (nn < ii) {
+#line 152 ""
+ goto L190;
+#line 152 ""
+ }
+/*< DO 180 J=II,NN >*/
+#line 153 ""
+ i__1 = nn;
+#line 153 ""
+ for (j = ii; j <= i__1; ++j) {
+/*< WSIGN(J+1) = WSIGN(J) - W(J) >*/
+#line 154 ""
+ wsign[j + 1] = wsign[j] - w[j];
+/*< PSIGN(J+1) = PSIGN(J) - P(J) >*/
+#line 155 ""
+ psign[j + 1] = psign[j] - p[j];
+/*< ZSIGN(J+1) = LL + 1 >*/
+#line 156 ""
+ zsign[j + 1] = ll + 1;
+/*< XX(J+1) = 1 >*/
+#line 157 ""
+ xx[j + 1] = 1;
+/*< 180 CONTINUE >*/
+#line 158 ""
+/* L180: */
+#line 158 ""
+ }
+/*< 190 J1 = LL + 1 >*/
+#line 159 ""
+L190:
+#line 159 ""
+ j1 = ll + 1;
+/*< DO 200 J=J1,LOLD >*/
+#line 160 ""
+ i__1 = lold;
+#line 160 ""
+ for (j = j1; j <= i__1; ++j) {
+/*< WSIGN(J) = 0 >*/
+#line 161 ""
+ wsign[j] = 0;
+/*< PSIGN(J) = 0 >*/
+#line 162 ""
+ psign[j] = 0;
+/*< ZSIGN(J) = J >*/
+#line 163 ""
+ zsign[j] = j;
+/*< 200 CONTINUE >*/
+#line 164 ""
+/* L200: */
+#line 164 ""
+ }
+/*< LOLD = LL >*/
+#line 165 ""
+ lold = ll;
+/*< CH = CHS >*/
+#line 166 ""
+ ch = chs;
+/*< PROFIT = PROFIT + IP >*/
+#line 167 ""
+ profit += ip;
+/*< IF ( LL - (N - 2) ) 240, 220, 210 >*/
+#line 168 ""
+ if ((i__1 = ll - (*n - 2)) < 0) {
+#line 168 ""
+ goto L240;
+#line 168 ""
+ } else if (i__1 == 0) {
+#line 168 ""
+ goto L220;
+#line 168 ""
+ } else {
+#line 168 ""
+ goto L210;
+#line 168 ""
+ }
+/*< 210 II = N >*/
+#line 169 ""
+L210:
+#line 169 ""
+ ii = *n;
+/*< GO TO 250 >*/
+#line 170 ""
+ goto L250;
+/*< 220 IF ( CH .LT. W(N) ) GO TO 230 >*/
+#line 171 ""
+L220:
+#line 171 ""
+ if (ch < w[*n]) {
+#line 171 ""
+ goto L230;
+#line 171 ""
+ }
+/*< CH = CH - W(N) >*/
+#line 172 ""
+ ch -= w[*n];
+/*< PROFIT = PROFIT + P(N) >*/
+#line 173 ""
+ profit += p[*n];
+/*< XX(N) = 1 >*/
+#line 174 ""
+ xx[*n] = 1;
+/*< 230 II = N - 1 >*/
+#line 175 ""
+L230:
+#line 175 ""
+ ii = *n - 1;
+/*< GO TO 250 >*/
+#line 176 ""
+ goto L250;
+/*< 240 II = LL + 2 >*/
+#line 177 ""
+L240:
+#line 177 ""
+ ii = ll + 2;
+/*< IF ( CH .GE. MIN(II-1) ) GO TO 80 >*/
+#line 178 ""
+ if (ch >= min__[ii - 1]) {
+#line 178 ""
+ goto L80;
+#line 178 ""
+ }
+/* SAVE THE CURRENT OPTIMAL SOLUTION. */
+/*< 250 IF ( Z .GE. PROFIT ) GO TO 270 >*/
+#line 180 ""
+L250:
+#line 180 ""
+ if (*z__ >= profit) {
+#line 180 ""
+ goto L270;
+#line 180 ""
+ }
+/*< Z = PROFIT >*/
+#line 181 ""
+ *z__ = profit;
+/*< DO 260 J=1,N >*/
+#line 182 ""
+ i__1 = *n;
+#line 182 ""
+ for (j = 1; j <= i__1; ++j) {
+/*< X(J) = XX(J) >*/
+#line 183 ""
+ x[j] = xx[j];
+/*< 260 CONTINUE >*/
+#line 184 ""
+/* L260: */
+#line 184 ""
+ }
+/*< IF ( Z .EQ. LIM ) RETURN >*/
+#line 185 ""
+ if (*z__ == lim) {
+#line 185 ""
+ return 0;
+#line 185 ""
+ }
+/*< 270 IF ( XX(N) .EQ. 0 ) GO TO 280 >*/
+#line 186 ""
+L270:
+#line 186 ""
+ if (xx[*n] == 0) {
+#line 186 ""
+ goto L280;
+#line 186 ""
+ }
+/*< XX(N) = 0 >*/
+#line 187 ""
+ xx[*n] = 0;
+/*< CH = CH + W(N) >*/
+#line 188 ""
+ ch += w[*n];
+/*< PROFIT = PROFIT - P(N) >*/
+#line 189 ""
+ profit -= p[*n];
+/* BACKTRACK. */
+/*< 280 NN = II - 1 >*/
+#line 191 ""
+L280:
+#line 191 ""
+ nn = ii - 1;
+/*< IF ( NN .EQ. 0 ) RETURN >*/
+#line 192 ""
+ if (nn == 0) {
+#line 192 ""
+ return 0;
+#line 192 ""
+ }
+/*< DO 290 J=1,NN >*/
+#line 193 ""
+ i__1 = nn;
+#line 193 ""
+ for (j = 1; j <= i__1; ++j) {
+/*< KK = II - J >*/
+#line 194 ""
+ kk = ii - j;
+/*< IF ( XX(KK) .EQ. 1 ) GO TO 300 >*/
+#line 195 ""
+ if (xx[kk] == 1) {
+#line 195 ""
+ goto L300;
+#line 195 ""
+ }
+/*< 290 CONTINUE >*/
+#line 196 ""
+/* L290: */
+#line 196 ""
+ }
+/*< RETURN >*/
+#line 197 ""
+ return 0;
+/*< 300 R = CH >*/
+#line 198 ""
+L300:
+#line 198 ""
+ r__ = ch;
+/*< CH = CH + W(KK) >*/
+#line 199 ""
+ ch += w[kk];
+/*< PROFIT = PROFIT - P(KK) >*/
+#line 200 ""
+ profit -= p[kk];
+/*< XX(KK) = 0 >*/
+#line 201 ""
+ xx[kk] = 0;
+/*< IF ( R .LT. MIN(KK) ) GO TO 310 >*/
+#line 202 ""
+ if (r__ < min__[kk]) {
+#line 202 ""
+ goto L310;
+#line 202 ""
+ }
+/*< II = KK + 1 >*/
+#line 203 ""
+ ii = kk + 1;
+/*< GO TO 80 >*/
+#line 204 ""
+ goto L80;
+/*< 310 NN = KK + 1 >*/
+#line 205 ""
+L310:
+#line 205 ""
+ nn = kk + 1;
+/*< II = KK >*/
+#line 206 ""
+ ii = kk;
+/* TRY TO SUBSTITUTE THE NN-TH ITEM FOR THE KK-TH. */
+/*< 320 IF ( Z .GE. PROFIT + CH*P(NN)/W(NN) ) GO TO 280 >*/
+#line 208 ""
+L320:
+#line 208 ""
+ if (*z__ >= profit + ch * p[nn] / w[nn]) {
+#line 208 ""
+ goto L280;
+#line 208 ""
+ }
+/*< DIFF = W(NN) - W(KK) >*/
+#line 209 ""
+ diff = w[nn] - w[kk];
+/*< IF ( DIFF ) 370, 330, 340 >*/
+#line 210 ""
+ if (diff < 0) {
+#line 210 ""
+ goto L370;
+#line 210 ""
+ } else if (diff == 0) {
+#line 210 ""
+ goto L330;
+#line 210 ""
+ } else {
+#line 210 ""
+ goto L340;
+#line 210 ""
+ }
+/*< 330 NN = NN + 1 >*/
+#line 211 ""
+L330:
+#line 211 ""
+ ++nn;
+/*< GO TO 320 >*/
+#line 212 ""
+ goto L320;
+/*< 340 IF ( DIFF .GT. R ) GO TO 330 >*/
+#line 213 ""
+L340:
+#line 213 ""
+ if (diff > r__) {
+#line 213 ""
+ goto L330;
+#line 213 ""
+ }
+/*< IF ( Z .GE. PROFIT + P(NN) ) GO TO 330 >*/
+#line 214 ""
+ if (*z__ >= profit + p[nn]) {
+#line 214 ""
+ goto L330;
+#line 214 ""
+ }
+/*< Z = PROFIT + P(NN) >*/
+#line 215 ""
+ *z__ = profit + p[nn];
+/*< DO 350 J=1,KK >*/
+#line 216 ""
+ i__1 = kk;
+#line 216 ""
+ for (j = 1; j <= i__1; ++j) {
+/*< X(J) = XX(J) >*/
+#line 217 ""
+ x[j] = xx[j];
+/*< 350 CONTINUE >*/
+#line 218 ""
+/* L350: */
+#line 218 ""
+ }
+/*< JJ = KK + 1 >*/
+#line 219 ""
+ jj = kk + 1;
+/*< DO 360 J=JJ,N >*/
+#line 220 ""
+ i__1 = *n;
+#line 220 ""
+ for (j = jj; j <= i__1; ++j) {
+/*< X(J) = 0 >*/
+#line 221 ""
+ x[j] = 0;
+/*< 360 CONTINUE >*/
+#line 222 ""
+/* L360: */
+#line 222 ""
+ }
+/*< X(NN) = 1 >*/
+#line 223 ""
+ x[nn] = 1;
+/*< IF ( Z .EQ. LIM ) RETURN >*/
+#line 224 ""
+ if (*z__ == lim) {
+#line 224 ""
+ return 0;
+#line 224 ""
+ }
+/*< R = R - DIFF >*/
+#line 225 ""
+ r__ -= diff;
+/*< KK = NN >*/
+#line 226 ""
+ kk = nn;
+/*< NN = NN + 1 >*/
+#line 227 ""
+ ++nn;
+/*< GO TO 320 >*/
+#line 228 ""
+ goto L320;
+/*< 370 T = R - DIFF >*/
+#line 229 ""
+L370:
+#line 229 ""
+ t = r__ - diff;
+/*< IF ( T .LT. MIN(NN) ) GO TO 330 >*/
+#line 230 ""
+ if (t < min__[nn]) {
+#line 230 ""
+ goto L330;
+#line 230 ""
+ }
+/*< IF ( Z .GE. PROFIT + P(NN) + T*P(NN+1)/W(NN+1)) GO TO 280 >*/
+#line 231 ""
+ if (*z__ >= profit + p[nn] + t * p[nn + 1] / w[nn + 1]) {
+#line 231 ""
+ goto L280;
+#line 231 ""
+ }
+/*< CH = CH - W(NN) >*/
+#line 232 ""
+ ch -= w[nn];
+/*< PROFIT = PROFIT + P(NN) >*/
+#line 233 ""
+ profit += p[nn];
+/*< XX(NN) = 1 >*/
+#line 234 ""
+ xx[nn] = 1;
+/*< II = NN + 1 >*/
+#line 235 ""
+ ii = nn + 1;
+/*< WSIGN(NN) = W(NN) >*/
+#line 236 ""
+ wsign[nn] = w[nn];
+/*< PSIGN(NN) = P(NN) >*/
+#line 237 ""
+ psign[nn] = p[nn];
+/*< ZSIGN(NN) = II >*/
+#line 238 ""
+ zsign[nn] = ii;
+/*< N1 = NN + 1 >*/
+#line 239 ""
+ n1 = nn + 1;
+/*< DO 380 J=N1,LOLD >*/
+#line 240 ""
+ i__1 = lold;
+#line 240 ""
+ for (j = n1; j <= i__1; ++j) {
+/*< WSIGN(J) = 0 >*/
+#line 241 ""
+ wsign[j] = 0;
+/*< PSIGN(J) = 0 >*/
+#line 242 ""
+ psign[j] = 0;
+/*< ZSIGN(J) = J >*/
+#line 243 ""
+ zsign[j] = j;
+/*< 380 CONTINUE >*/
+#line 244 ""
+/* L380: */
+#line 244 ""
+ }
+/*< LOLD = NN >*/
+#line 245 ""
+ lold = nn;
+/*< GO TO 80 >*/
+#line 246 ""
+ goto L80;
+/*< END >*/
+} /* mt1_ */
+
+/*< SUBROUTINE CHMT1(N,P,W,C,Z,JDIM) >*/
+#if 1 /* by mao */
+static
+#endif
+/* Subroutine */ int chmt1_(integer *n, integer *p, integer *w, integer *c__,
+ integer *z__, integer *jdim)
+{
+ /* System generated locals */
+ integer i__1;
+
+ /* Local variables */
+ static integer j;
+ static real r__, rr;
+ static integer jsw;
+
+
+/* CHECK THE INPUT DATA. */
+
+/*< INTEGER P(JDIM),W(JDIM),C,Z >*/
+/*< IF ( N .GE. 2 .AND. N .LE. JDIM - 1 ) GO TO 10 >*/
+#line 253 ""
+ /* Parameter adjustments */
+#line 253 ""
+ --w;
+#line 253 ""
+ --p;
+#line 253 ""
+
+#line 253 ""
+ /* Function Body */
+#line 253 ""
+ if (*n >= 2 && *n <= *jdim - 1) {
+#line 253 ""
+ goto L10;
+#line 253 ""
+ }
+/*< Z = - 1 >*/
+#line 254 ""
+ *z__ = -1;
+/*< RETURN >*/
+#line 255 ""
+ return 0;
+/*< 10 IF ( C .GT. 0 ) GO TO 30 >*/
+#line 256 ""
+L10:
+#line 256 ""
+ if (*c__ > 0) {
+#line 256 ""
+ goto L30;
+#line 256 ""
+ }
+/*< 20 Z = - 2 >*/
+#line 257 ""
+L20:
+#line 257 ""
+ *z__ = -2;
+/*< RETURN >*/
+#line 258 ""
+ return 0;
+/*< 30 JSW = 0 >*/
+#line 259 ""
+L30:
+#line 259 ""
+ jsw = 0;
+/*< RR = FLOAT(P(1))/FLOAT(W(1)) >*/
+#line 260 ""
+ rr = (real) p[1] / (real) w[1];
+/*< DO 50 J=1,N >*/
+#line 261 ""
+ i__1 = *n;
+#line 261 ""
+ for (j = 1; j <= i__1; ++j) {
+/*< R = RR >*/
+#line 262 ""
+ r__ = rr;
+/*< IF ( P(J) .LE. 0 ) GO TO 20 >*/
+#line 263 ""
+ if (p[j] <= 0) {
+#line 263 ""
+ goto L20;
+#line 263 ""
+ }
+/*< IF ( W(J) .LE. 0 ) GO TO 20 >*/
+#line 264 ""
+ if (w[j] <= 0) {
+#line 264 ""
+ goto L20;
+#line 264 ""
+ }
+/*< JSW = JSW + W(J) >*/
+#line 265 ""
+ jsw += w[j];
+/*< IF ( W(J) .LE. C ) GO TO 40 >*/
+#line 266 ""
+ if (w[j] <= *c__) {
+#line 266 ""
+ goto L40;
+#line 266 ""
+ }
+/*< Z = - 3 >*/
+#line 267 ""
+ *z__ = -3;
+/*< RETURN >*/
+#line 268 ""
+ return 0;
+/*< 40 RR = FLOAT(P(J))/FLOAT(W(J)) >*/
+#line 269 ""
+L40:
+#line 269 ""
+ rr = (real) p[j] / (real) w[j];
+/*< IF ( RR .LE. R ) GO TO 50 >*/
+#line 270 ""
+ if (rr <= r__) {
+#line 270 ""
+ goto L50;
+#line 270 ""
+ }
+/*< Z = - 5 >*/
+#line 271 ""
+ *z__ = -5;
+/*< RETURN >*/
+#line 272 ""
+ return 0;
+/*< 50 CONTINUE >*/
+#line 273 ""
+L50:
+#line 273 ""
+ ;
+#line 273 ""
+ }
+/*< IF ( JSW .GT. C ) RETURN >*/
+#line 274 ""
+ if (jsw > *c__) {
+#line 274 ""
+ return 0;
+#line 274 ""
+ }
+/*< Z = - 4 >*/
+#line 275 ""
+ *z__ = -4;
+/*< RETURN >*/
+#line 276 ""
+ return 0;
+/*< END >*/
+} /* chmt1_ */
+
+#if 1 /* by mao */
+int mt1(int n, int p[], int w[], int c, int x[], int jck, int xx[],
+ int min[], int psign[], int wsign[], int zsign[])
+{ /* solve 0-1 knapsack problem */
+ int z, jdim = n+1, j, s1, s2;
+ mt1_(&n, &p[1], &w[1], &c, &z, &x[1], &jdim, &jck, &xx[1],
+ &min[1], &psign[1], &wsign[1], &zsign[1]);
+ /* check solution found */
+ s1 = s2 = 0;
+ for (j = 1; j <= n; j++)
+ { xassert(x[j] == 0 || x[j] == 1);
+ if (x[j])
+ s1 += p[j], s2 += w[j];
+ }
+ xassert(s1 == z);
+ xassert(s2 <= c);
+ return z;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/mt1.f b/test/monniaux/glpk-4.65/src/misc/mt1.f
new file mode 100644
index 00000000..82cc4a1b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/mt1.f
@@ -0,0 +1,277 @@
+ SUBROUTINE MT1(N,P,W,C,Z,X,JDIM,JCK,XX,MIN,PSIGN,WSIGN,ZSIGN)
+C
+C THIS SUBROUTINE SOLVES THE 0-1 SINGLE KNAPSACK PROBLEM
+C
+C MAXIMIZE Z = P(1)*X(1) + ... + P(N)*X(N)
+C
+C SUBJECT TO: W(1)*X(1) + ... + W(N)*X(N) .LE. C ,
+C X(J) = 0 OR 1 FOR J=1,...,N.
+C
+C THE PROGRAM IS INCLUDED IN THE VOLUME
+C S. MARTELLO, P. TOTH, "KNAPSACK PROBLEMS: ALGORITHMS
+C AND COMPUTER IMPLEMENTATIONS", JOHN WILEY, 1990
+C AND IMPLEMENTS THE BRANCH-AND-BOUND ALGORITHM DESCRIBED IN
+C SECTION 2.5.2 .
+C THE PROGRAM DERIVES FROM AN EARLIER CODE PRESENTED IN
+C S. MARTELLO, P. TOTH, "ALGORITHM FOR THE SOLUTION OF THE 0-1 SINGLE
+C KNAPSACK PROBLEM", COMPUTING, 1978.
+C
+C THE INPUT PROBLEM MUST SATISFY THE CONDITIONS
+C
+C 1) 2 .LE. N .LE. JDIM - 1 ;
+C 2) P(J), W(J), C POSITIVE INTEGERS;
+C 3) MAX (W(J)) .LE. C ;
+C 4) W(1) + ... + W(N) .GT. C ;
+C 5) P(J)/W(J) .GE. P(J+1)/W(J+1) FOR J=1,...,N-1.
+C
+C MT1 CALLS 1 PROCEDURE: CHMT1.
+C
+C THE PROGRAM IS COMPLETELY SELF-CONTAINED AND COMMUNICATION TO IT IS
+C ACHIEVED SOLELY THROUGH THE PARAMETER LIST OF MT1.
+C NO MACHINE-DEPENDENT CONSTANT IS USED.
+C THE PROGRAM IS WRITTEN IN 1967 AMERICAN NATIONAL STANDARD FORTRAN
+C AND IS ACCEPTED BY THE PFORT VERIFIER (PFORT IS THE PORTABLE
+C SUBSET OF ANSI DEFINED BY THE ASSOCIATION FOR COMPUTING MACHINERY).
+C THE PROGRAM HAS BEEN TESTED ON A DIGITAL VAX 11/780 AND AN H.P.
+C 9000/840.
+C
+C MT1 NEEDS 8 ARRAYS ( P , W , X , XX , MIN , PSIGN , WSIGN
+C AND ZSIGN ) OF LENGTH AT LEAST N + 1 .
+C
+C MEANING OF THE INPUT PARAMETERS:
+C N = NUMBER OF ITEMS;
+C P(J) = PROFIT OF ITEM J (J=1,...,N);
+C W(J) = WEIGHT OF ITEM J (J=1,...,N);
+C C = CAPACITY OF THE KNAPSACK;
+C JDIM = DIMENSION OF THE 8 ARRAYS;
+C JCK = 1 IF CHECK ON THE INPUT DATA IS DESIRED,
+C = 0 OTHERWISE.
+C
+C MEANING OF THE OUTPUT PARAMETERS:
+C Z = VALUE OF THE OPTIMAL SOLUTION IF Z .GT. 0 ,
+C = ERROR IN THE INPUT DATA (WHEN JCK=1) IF Z .LT. 0 : CONDI-
+C TION - Z IS VIOLATED;
+C X(J) = 1 IF ITEM J IS IN THE OPTIMAL SOLUTION,
+C = 0 OTHERWISE.
+C
+C ARRAYS XX, MIN, PSIGN, WSIGN AND ZSIGN ARE DUMMY.
+C
+C ALL THE PARAMETERS ARE INTEGER. ON RETURN OF MT1 ALL THE INPUT
+C PARAMETERS ARE UNCHANGED.
+C
+ INTEGER P(JDIM),W(JDIM),X(JDIM),C,Z
+ INTEGER XX(JDIM),MIN(JDIM),PSIGN(JDIM),WSIGN(JDIM),ZSIGN(JDIM)
+ INTEGER CH,CHS,DIFF,PROFIT,R,T
+ Z = 0
+ IF ( JCK .EQ. 1 ) CALL CHMT1(N,P,W,C,Z,JDIM)
+ IF ( Z .LT. 0 ) RETURN
+C INITIALIZE.
+ CH = C
+ IP = 0
+ CHS = CH
+ DO 10 LL=1,N
+ IF ( W(LL) .GT. CHS ) GO TO 20
+ IP = IP + P(LL)
+ CHS = CHS - W(LL)
+ 10 CONTINUE
+ 20 LL = LL - 1
+ IF ( CHS .EQ. 0 ) GO TO 50
+ P(N+1) = 0
+ W(N+1) = CH + 1
+ LIM = IP + CHS*P(LL+2)/W(LL+2)
+ A = W(LL+1) - CHS
+ B = IP + P(LL+1)
+ LIM1 = B - A*FLOAT(P(LL))/FLOAT(W(LL))
+ IF ( LIM1 .GT. LIM ) LIM = LIM1
+ MINK = CH + 1
+ MIN(N) = MINK
+ DO 30 J=2,N
+ KK = N + 2 - J
+ IF ( W(KK) .LT. MINK ) MINK = W(KK)
+ MIN(KK-1) = MINK
+ 30 CONTINUE
+ DO 40 J=1,N
+ XX(J) = 0
+ 40 CONTINUE
+ Z = 0
+ PROFIT = 0
+ LOLD = N
+ II = 1
+ GO TO 170
+ 50 Z = IP
+ DO 60 J=1,LL
+ X(J) = 1
+ 60 CONTINUE
+ NN = LL + 1
+ DO 70 J=NN,N
+ X(J) = 0
+ 70 CONTINUE
+ RETURN
+C TRY TO INSERT THE II-TH ITEM INTO THE CURRENT SOLUTION.
+ 80 IF ( W(II) .LE. CH ) GO TO 90
+ II1 = II + 1
+ IF ( Z .GE. CH*P(II1)/W(II1) + PROFIT ) GO TO 280
+ II = II1
+ GO TO 80
+C BUILD A NEW CURRENT SOLUTION.
+ 90 IP = PSIGN(II)
+ CHS = CH - WSIGN(II)
+ IN = ZSIGN(II)
+ DO 100 LL=IN,N
+ IF ( W(LL) .GT. CHS ) GO TO 160
+ IP = IP + P(LL)
+ CHS = CHS - W(LL)
+ 100 CONTINUE
+ LL = N
+ 110 IF ( Z .GE. IP + PROFIT ) GO TO 280
+ Z = IP + PROFIT
+ NN = II - 1
+ DO 120 J=1,NN
+ X(J) = XX(J)
+ 120 CONTINUE
+ DO 130 J=II,LL
+ X(J) = 1
+ 130 CONTINUE
+ IF ( LL .EQ. N ) GO TO 150
+ NN = LL + 1
+ DO 140 J=NN,N
+ X(J) = 0
+ 140 CONTINUE
+ 150 IF ( Z .NE. LIM ) GO TO 280
+ RETURN
+ 160 IU = CHS*P(LL)/W(LL)
+ LL = LL - 1
+ IF ( IU .EQ. 0 ) GO TO 110
+ IF ( Z .GE. PROFIT + IP + IU ) GO TO 280
+C SAVE THE CURRENT SOLUTION.
+ 170 WSIGN(II) = CH - CHS
+ PSIGN(II) = IP
+ ZSIGN(II) = LL + 1
+ XX(II) = 1
+ NN = LL - 1
+ IF ( NN .LT. II) GO TO 190
+ DO 180 J=II,NN
+ WSIGN(J+1) = WSIGN(J) - W(J)
+ PSIGN(J+1) = PSIGN(J) - P(J)
+ ZSIGN(J+1) = LL + 1
+ XX(J+1) = 1
+ 180 CONTINUE
+ 190 J1 = LL + 1
+ DO 200 J=J1,LOLD
+ WSIGN(J) = 0
+ PSIGN(J) = 0
+ ZSIGN(J) = J
+ 200 CONTINUE
+ LOLD = LL
+ CH = CHS
+ PROFIT = PROFIT + IP
+ IF ( LL - (N - 2) ) 240, 220, 210
+ 210 II = N
+ GO TO 250
+ 220 IF ( CH .LT. W(N) ) GO TO 230
+ CH = CH - W(N)
+ PROFIT = PROFIT + P(N)
+ XX(N) = 1
+ 230 II = N - 1
+ GO TO 250
+ 240 II = LL + 2
+ IF ( CH .GE. MIN(II-1) ) GO TO 80
+C SAVE THE CURRENT OPTIMAL SOLUTION.
+ 250 IF ( Z .GE. PROFIT ) GO TO 270
+ Z = PROFIT
+ DO 260 J=1,N
+ X(J) = XX(J)
+ 260 CONTINUE
+ IF ( Z .EQ. LIM ) RETURN
+ 270 IF ( XX(N) .EQ. 0 ) GO TO 280
+ XX(N) = 0
+ CH = CH + W(N)
+ PROFIT = PROFIT - P(N)
+C BACKTRACK.
+ 280 NN = II - 1
+ IF ( NN .EQ. 0 ) RETURN
+ DO 290 J=1,NN
+ KK = II - J
+ IF ( XX(KK) .EQ. 1 ) GO TO 300
+ 290 CONTINUE
+ RETURN
+ 300 R = CH
+ CH = CH + W(KK)
+ PROFIT = PROFIT - P(KK)
+ XX(KK) = 0
+ IF ( R .LT. MIN(KK) ) GO TO 310
+ II = KK + 1
+ GO TO 80
+ 310 NN = KK + 1
+ II = KK
+C TRY TO SUBSTITUTE THE NN-TH ITEM FOR THE KK-TH.
+ 320 IF ( Z .GE. PROFIT + CH*P(NN)/W(NN) ) GO TO 280
+ DIFF = W(NN) - W(KK)
+ IF ( DIFF ) 370, 330, 340
+ 330 NN = NN + 1
+ GO TO 320
+ 340 IF ( DIFF .GT. R ) GO TO 330
+ IF ( Z .GE. PROFIT + P(NN) ) GO TO 330
+ Z = PROFIT + P(NN)
+ DO 350 J=1,KK
+ X(J) = XX(J)
+ 350 CONTINUE
+ JJ = KK + 1
+ DO 360 J=JJ,N
+ X(J) = 0
+ 360 CONTINUE
+ X(NN) = 1
+ IF ( Z .EQ. LIM ) RETURN
+ R = R - DIFF
+ KK = NN
+ NN = NN + 1
+ GO TO 320
+ 370 T = R - DIFF
+ IF ( T .LT. MIN(NN) ) GO TO 330
+ IF ( Z .GE. PROFIT + P(NN) + T*P(NN+1)/W(NN+1)) GO TO 280
+ CH = CH - W(NN)
+ PROFIT = PROFIT + P(NN)
+ XX(NN) = 1
+ II = NN + 1
+ WSIGN(NN) = W(NN)
+ PSIGN(NN) = P(NN)
+ ZSIGN(NN) = II
+ N1 = NN + 1
+ DO 380 J=N1,LOLD
+ WSIGN(J) = 0
+ PSIGN(J) = 0
+ ZSIGN(J) = J
+ 380 CONTINUE
+ LOLD = NN
+ GO TO 80
+ END
+ SUBROUTINE CHMT1(N,P,W,C,Z,JDIM)
+C
+C CHECK THE INPUT DATA.
+C
+ INTEGER P(JDIM),W(JDIM),C,Z
+ IF ( N .GE. 2 .AND. N .LE. JDIM - 1 ) GO TO 10
+ Z = - 1
+ RETURN
+ 10 IF ( C .GT. 0 ) GO TO 30
+ 20 Z = - 2
+ RETURN
+ 30 JSW = 0
+ RR = FLOAT(P(1))/FLOAT(W(1))
+ DO 50 J=1,N
+ R = RR
+ IF ( P(J) .LE. 0 ) GO TO 20
+ IF ( W(J) .LE. 0 ) GO TO 20
+ JSW = JSW + W(J)
+ IF ( W(J) .LE. C ) GO TO 40
+ Z = - 3
+ RETURN
+ 40 RR = FLOAT(P(J))/FLOAT(W(J))
+ IF ( RR .LE. R ) GO TO 50
+ Z = - 5
+ RETURN
+ 50 CONTINUE
+ IF ( JSW .GT. C ) RETURN
+ Z = - 4
+ RETURN
+ END
diff --git a/test/monniaux/glpk-4.65/src/misc/mt1.h b/test/monniaux/glpk-4.65/src/misc/mt1.h
new file mode 100644
index 00000000..cceebba9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/mt1.h
@@ -0,0 +1,34 @@
+/* mt1.h (0-1 knapsack problem; Martello & Toth algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2017-2018 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/>.
+***********************************************************************/
+
+#ifndef MT1_H
+#define MT1_H
+
+#define mt1 _glp_mt1
+int mt1(int n, int p[], int w[], int c, int x[], int jck, int xx[],
+ int min[], int psign[], int wsign[], int zsign[]);
+/* solve 0-1 single knapsack problem */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/mygmp.c b/test/monniaux/glpk-4.65/src/misc/mygmp.c
new file mode 100644
index 00000000..89d053ae
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/mygmp.c
@@ -0,0 +1,1162 @@
+/* mygmp.c (integer and rational arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2008-2015 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/>.
+***********************************************************************/
+
+#include "mygmp.h"
+
+#ifdef HAVE_GMP /* use GNU MP library */
+
+/* nothing is needed */
+
+#else /* use GLPK MP module */
+
+#include "bignum.h"
+#include "dmp.h"
+#include "env.h"
+
+#define gmp_pool env->gmp_pool
+#define gmp_size env->gmp_size
+#define gmp_work env->gmp_work
+
+void *gmp_get_atom(int size)
+{ ENV *env = get_env_ptr();
+ if (gmp_pool == NULL)
+ gmp_pool = dmp_create_pool();
+ return dmp_get_atom(gmp_pool, size);
+}
+
+void gmp_free_atom(void *ptr, int size)
+{ ENV *env = get_env_ptr();
+ xassert(gmp_pool != NULL);
+ dmp_free_atom(gmp_pool, ptr, size);
+ return;
+}
+
+int gmp_pool_count(void)
+{ ENV *env = get_env_ptr();
+ if (gmp_pool == NULL)
+ return 0;
+ else
+ return dmp_in_use(gmp_pool);
+}
+
+unsigned short *gmp_get_work(int size)
+{ ENV *env = get_env_ptr();
+ xassert(size > 0);
+ if (gmp_size < size)
+ { if (gmp_size == 0)
+ { xassert(gmp_work == NULL);
+ gmp_size = 100;
+ }
+ else
+ { xassert(gmp_work != NULL);
+ xfree(gmp_work);
+ }
+ while (gmp_size < size)
+ gmp_size += gmp_size;
+ gmp_work = xcalloc(gmp_size, sizeof(unsigned short));
+ }
+ return gmp_work;
+}
+
+void gmp_free_mem(void)
+{ ENV *env = get_env_ptr();
+ if (gmp_pool != NULL)
+ dmp_delete_pool(gmp_pool);
+ if (gmp_work != NULL)
+ xfree(gmp_work);
+ gmp_pool = NULL;
+ gmp_size = 0;
+ gmp_work = NULL;
+ return;
+}
+
+/*--------------------------------------------------------------------*/
+
+mpz_t _mpz_init(void)
+{ /* initialize x and set its value to 0 */
+ mpz_t x;
+ x = gmp_get_atom(sizeof(struct mpz));
+ x->val = 0;
+ x->ptr = NULL;
+ return x;
+}
+
+void mpz_clear(mpz_t x)
+{ /* free the space occupied by x */
+ mpz_set_si(x, 0);
+ xassert(x->ptr == NULL);
+ /* free the number descriptor */
+ gmp_free_atom(x, sizeof(struct mpz));
+ return;
+}
+
+void mpz_set(mpz_t z, mpz_t x)
+{ /* set the value of z from x */
+ struct mpz_seg *e, *ee, *es;
+ if (z != x)
+ { mpz_set_si(z, 0);
+ z->val = x->val;
+ xassert(z->ptr == NULL);
+ for (e = x->ptr, es = NULL; e != NULL; e = e->next)
+ { ee = gmp_get_atom(sizeof(struct mpz_seg));
+ memcpy(ee->d, e->d, 12);
+ ee->next = NULL;
+ if (z->ptr == NULL)
+ z->ptr = ee;
+ else
+ es->next = ee;
+ es = ee;
+ }
+ }
+ return;
+}
+
+void mpz_set_si(mpz_t x, int val)
+{ /* set the value of x to val */
+ struct mpz_seg *e;
+ /* free existing segments, if any */
+ while (x->ptr != NULL)
+ { e = x->ptr;
+ x->ptr = e->next;
+ gmp_free_atom(e, sizeof(struct mpz_seg));
+ }
+ /* assign new value */
+ if (val == 0x80000000)
+ { /* long format is needed */
+ x->val = -1;
+ x->ptr = e = gmp_get_atom(sizeof(struct mpz_seg));
+ memset(e->d, 0, 12);
+ e->d[1] = 0x8000;
+ e->next = NULL;
+ }
+ else
+ { /* short format is enough */
+ x->val = val;
+ }
+ return;
+}
+
+double mpz_get_d(mpz_t x)
+{ /* convert x to a double, truncating if necessary */
+ struct mpz_seg *e;
+ int j;
+ double val, deg;
+ if (x->ptr == NULL)
+ val = (double)x->val;
+ else
+ { xassert(x->val != 0);
+ val = 0.0;
+ deg = 1.0;
+ for (e = x->ptr; e != NULL; e = e->next)
+ { for (j = 0; j <= 5; j++)
+ { val += deg * (double)((int)e->d[j]);
+ deg *= 65536.0;
+ }
+ }
+ if (x->val < 0)
+ val = - val;
+ }
+ return val;
+}
+
+double mpz_get_d_2exp(int *exp, mpz_t x)
+{ /* convert x to a double, truncating if necessary (i.e. rounding
+ * towards zero), and returning the exponent separately;
+ * the return value is in the range 0.5 <= |d| < 1 and the
+ * exponent is stored to *exp; d*2^exp is the (truncated) x value;
+ * if x is zero, the return is 0.0 and 0 is stored to *exp;
+ * this is similar to the standard C frexp function */
+ struct mpz_seg *e;
+ int j, n, n1;
+ double val;
+ if (x->ptr == NULL)
+ val = (double)x->val, n = 0;
+ else
+ { xassert(x->val != 0);
+ val = 0.0, n = 0;
+ for (e = x->ptr; e != NULL; e = e->next)
+ { for (j = 0; j <= 5; j++)
+ { val += (double)((int)e->d[j]);
+ val /= 65536.0, n += 16;
+ }
+ }
+ if (x->val < 0)
+ val = - val;
+ }
+ val = frexp(val, &n1);
+ *exp = n + n1;
+ return val;
+}
+
+void mpz_swap(mpz_t x, mpz_t y)
+{ /* swap the values x and y efficiently */
+ int val;
+ void *ptr;
+ val = x->val, ptr = x->ptr;
+ x->val = y->val, x->ptr = y->ptr;
+ y->val = val, y->ptr = ptr;
+ return;
+}
+
+static void normalize(mpz_t x)
+{ /* normalize integer x that includes removing non-significant
+ * (leading) zeros and converting to short format, if possible */
+ struct mpz_seg *es, *e;
+ /* if the integer is in short format, it remains unchanged */
+ if (x->ptr == NULL)
+ { xassert(x->val != 0x80000000);
+ goto done;
+ }
+ xassert(x->val == +1 || x->val == -1);
+ /* find the last (most significant) non-zero segment */
+ es = NULL;
+ for (e = x->ptr; e != NULL; e = e->next)
+ { if (e->d[0] || e->d[1] || e->d[2] ||
+ e->d[3] || e->d[4] || e->d[5])
+ es = e;
+ }
+ /* if all segments contain zeros, the integer is zero */
+ if (es == NULL)
+ { mpz_set_si(x, 0);
+ goto done;
+ }
+ /* remove non-significant (leading) zero segments */
+ while (es->next != NULL)
+ { e = es->next;
+ es->next = e->next;
+ gmp_free_atom(e, sizeof(struct mpz_seg));
+ }
+ /* convert the integer to short format, if possible */
+ e = x->ptr;
+ if (e->next == NULL && e->d[1] <= 0x7FFF &&
+ !e->d[2] && !e->d[3] && !e->d[4] && !e->d[5])
+ { int val;
+ val = (int)e->d[0] + ((int)e->d[1] << 16);
+ if (x->val < 0)
+ val = - val;
+ mpz_set_si(x, val);
+ }
+done: return;
+}
+
+void mpz_add(mpz_t z, mpz_t x, mpz_t y)
+{ /* set z to x + y */
+ static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL };
+ struct mpz_seg dumx, dumy, *ex, *ey, *ez, *es, *ee;
+ int k, sx, sy, sz;
+ unsigned int t;
+ /* if [x] = 0 then [z] = [y] */
+ if (x->val == 0)
+ { xassert(x->ptr == NULL);
+ mpz_set(z, y);
+ goto done;
+ }
+ /* if [y] = 0 then [z] = [x] */
+ if (y->val == 0)
+ { xassert(y->ptr == NULL);
+ mpz_set(z, x);
+ goto done;
+ }
+ /* special case when both [x] and [y] are in short format */
+ if (x->ptr == NULL && y->ptr == NULL)
+ { int xval = x->val, yval = y->val, zval = x->val + y->val;
+ xassert(xval != 0x80000000 && yval != 0x80000000);
+ if (!(xval > 0 && yval > 0 && zval <= 0 ||
+ xval < 0 && yval < 0 && zval >= 0))
+ { mpz_set_si(z, zval);
+ goto done;
+ }
+ }
+ /* convert [x] to long format, if necessary */
+ if (x->ptr == NULL)
+ { xassert(x->val != 0x80000000);
+ if (x->val >= 0)
+ { sx = +1;
+ t = (unsigned int)(+ x->val);
+ }
+ else
+ { sx = -1;
+ t = (unsigned int)(- x->val);
+ }
+ ex = &dumx;
+ ex->d[0] = (unsigned short)t;
+ ex->d[1] = (unsigned short)(t >> 16);
+ ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+ ex->next = NULL;
+ }
+ else
+ { sx = x->val;
+ xassert(sx == +1 || sx == -1);
+ ex = x->ptr;
+ }
+ /* convert [y] to long format, if necessary */
+ if (y->ptr == NULL)
+ { xassert(y->val != 0x80000000);
+ if (y->val >= 0)
+ { sy = +1;
+ t = (unsigned int)(+ y->val);
+ }
+ else
+ { sy = -1;
+ t = (unsigned int)(- y->val);
+ }
+ ey = &dumy;
+ ey->d[0] = (unsigned short)t;
+ ey->d[1] = (unsigned short)(t >> 16);
+ ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+ ey->next = NULL;
+ }
+ else
+ { sy = y->val;
+ xassert(sy == +1 || sy == -1);
+ ey = y->ptr;
+ }
+ /* main fragment */
+ sz = sx;
+ ez = es = NULL;
+ if (sx > 0 && sy > 0 || sx < 0 && sy < 0)
+ { /* [x] and [y] have identical signs -- addition */
+ t = 0;
+ for (; ex || ey; ex = ex->next, ey = ey->next)
+ { if (ex == NULL)
+ ex = &zero;
+ if (ey == NULL)
+ ey = &zero;
+ ee = gmp_get_atom(sizeof(struct mpz_seg));
+ for (k = 0; k <= 5; k++)
+ { t += (unsigned int)ex->d[k];
+ t += (unsigned int)ey->d[k];
+ ee->d[k] = (unsigned short)t;
+ t >>= 16;
+ }
+ ee->next = NULL;
+ if (ez == NULL)
+ ez = ee;
+ else
+ es->next = ee;
+ es = ee;
+ }
+ if (t)
+ { /* overflow -- one extra digit is needed */
+ ee = gmp_get_atom(sizeof(struct mpz_seg));
+ ee->d[0] = 1;
+ ee->d[1] = ee->d[2] = ee->d[3] = ee->d[4] = ee->d[5] = 0;
+ ee->next = NULL;
+ xassert(es != NULL);
+ es->next = ee;
+ }
+ }
+ else
+ { /* [x] and [y] have different signs -- subtraction */
+ t = 1;
+ for (; ex || ey; ex = ex->next, ey = ey->next)
+ { if (ex == NULL)
+ ex = &zero;
+ if (ey == NULL)
+ ey = &zero;
+ ee = gmp_get_atom(sizeof(struct mpz_seg));
+ for (k = 0; k <= 5; k++)
+ { t += (unsigned int)ex->d[k];
+ t += (0xFFFF - (unsigned int)ey->d[k]);
+ ee->d[k] = (unsigned short)t;
+ t >>= 16;
+ }
+ ee->next = NULL;
+ if (ez == NULL)
+ ez = ee;
+ else
+ es->next = ee;
+ es = ee;
+ }
+ if (!t)
+ { /* |[x]| < |[y]| -- result in complement coding */
+ sz = - sz;
+ t = 1;
+ for (ee = ez; ee != NULL; ee = ee->next)
+ { for (k = 0; k <= 5; k++)
+ { t += (0xFFFF - (unsigned int)ee->d[k]);
+ ee->d[k] = (unsigned short)t;
+ t >>= 16;
+ }
+ }
+ }
+ }
+ /* contruct and normalize result */
+ mpz_set_si(z, 0);
+ z->val = sz;
+ z->ptr = ez;
+ normalize(z);
+done: return;
+}
+
+void mpz_sub(mpz_t z, mpz_t x, mpz_t y)
+{ /* set z to x - y */
+ if (x == y)
+ mpz_set_si(z, 0);
+ else
+ { y->val = - y->val;
+ mpz_add(z, x, y);
+ if (y != z)
+ y->val = - y->val;
+ }
+ return;
+}
+
+void mpz_mul(mpz_t z, mpz_t x, mpz_t y)
+{ /* set z to x * y */
+ struct mpz_seg dumx, dumy, *ex, *ey, *es, *e;
+ int sx, sy, k, nx, ny, n;
+ unsigned int t;
+ unsigned short *work, *wx, *wy;
+ /* if [x] = 0 then [z] = 0 */
+ if (x->val == 0)
+ { xassert(x->ptr == NULL);
+ mpz_set_si(z, 0);
+ goto done;
+ }
+ /* if [y] = 0 then [z] = 0 */
+ if (y->val == 0)
+ { xassert(y->ptr == NULL);
+ mpz_set_si(z, 0);
+ goto done;
+ }
+ /* special case when both [x] and [y] are in short format */
+ if (x->ptr == NULL && y->ptr == NULL)
+ { int xval = x->val, yval = y->val, sz = +1;
+ xassert(xval != 0x80000000 && yval != 0x80000000);
+ if (xval < 0)
+ xval = - xval, sz = - sz;
+ if (yval < 0)
+ yval = - yval, sz = - sz;
+ if (xval <= 0x7FFFFFFF / yval)
+ { mpz_set_si(z, sz * (xval * yval));
+ goto done;
+ }
+ }
+ /* convert [x] to long format, if necessary */
+ if (x->ptr == NULL)
+ { xassert(x->val != 0x80000000);
+ if (x->val >= 0)
+ { sx = +1;
+ t = (unsigned int)(+ x->val);
+ }
+ else
+ { sx = -1;
+ t = (unsigned int)(- x->val);
+ }
+ ex = &dumx;
+ ex->d[0] = (unsigned short)t;
+ ex->d[1] = (unsigned short)(t >> 16);
+ ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+ ex->next = NULL;
+ }
+ else
+ { sx = x->val;
+ xassert(sx == +1 || sx == -1);
+ ex = x->ptr;
+ }
+ /* convert [y] to long format, if necessary */
+ if (y->ptr == NULL)
+ { xassert(y->val != 0x80000000);
+ if (y->val >= 0)
+ { sy = +1;
+ t = (unsigned int)(+ y->val);
+ }
+ else
+ { sy = -1;
+ t = (unsigned int)(- y->val);
+ }
+ ey = &dumy;
+ ey->d[0] = (unsigned short)t;
+ ey->d[1] = (unsigned short)(t >> 16);
+ ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+ ey->next = NULL;
+ }
+ else
+ { sy = y->val;
+ xassert(sy == +1 || sy == -1);
+ ey = y->ptr;
+ }
+ /* determine the number of digits of [x] */
+ nx = n = 0;
+ for (e = ex; e != NULL; e = e->next)
+ { for (k = 0; k <= 5; k++)
+ { n++;
+ if (e->d[k])
+ nx = n;
+ }
+ }
+ xassert(nx > 0);
+ /* determine the number of digits of [y] */
+ ny = n = 0;
+ for (e = ey; e != NULL; e = e->next)
+ { for (k = 0; k <= 5; k++)
+ { n++;
+ if (e->d[k])
+ ny = n;
+ }
+ }
+ xassert(ny > 0);
+ /* we need working array containing at least nx+ny+ny places */
+ work = gmp_get_work(nx+ny+ny);
+ /* load digits of [x] */
+ wx = &work[0];
+ for (n = 0; n < nx; n++)
+ wx[ny+n] = 0;
+ for (n = 0, e = ex; e != NULL; e = e->next)
+ { for (k = 0; k <= 5; k++, n++)
+ { if (e->d[k])
+ wx[ny+n] = e->d[k];
+ }
+ }
+ /* load digits of [y] */
+ wy = &work[nx+ny];
+ for (n = 0; n < ny; n++) wy[n] = 0;
+ for (n = 0, e = ey; e != NULL; e = e->next)
+ { for (k = 0; k <= 5; k++, n++)
+ { if (e->d[k])
+ wy[n] = e->d[k];
+ }
+ }
+ /* compute [x] * [y] */
+ bigmul(nx, ny, wx, wy);
+ /* construct and normalize result */
+ mpz_set_si(z, 0);
+ z->val = sx * sy;
+ es = NULL;
+ k = 6;
+ for (n = 0; n < nx+ny; n++)
+ { if (k > 5)
+ { e = gmp_get_atom(sizeof(struct mpz_seg));
+ e->d[0] = e->d[1] = e->d[2] = 0;
+ e->d[3] = e->d[4] = e->d[5] = 0;
+ e->next = NULL;
+ if (z->ptr == NULL)
+ z->ptr = e;
+ else
+ es->next = e;
+ es = e;
+ k = 0;
+ }
+ es->d[k++] = wx[n];
+ }
+ normalize(z);
+done: return;
+}
+
+void mpz_neg(mpz_t z, mpz_t x)
+{ /* set z to 0 - x */
+ mpz_set(z, x);
+ z->val = - z->val;
+ return;
+}
+
+void mpz_abs(mpz_t z, mpz_t x)
+{ /* set z to the absolute value of x */
+ mpz_set(z, x);
+ if (z->val < 0)
+ z->val = - z->val;
+ return;
+}
+
+void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y)
+{ /* divide x by y, forming quotient q and/or remainder r
+ * if q = NULL then quotient is not stored; if r = NULL then
+ * remainder is not stored
+ * the sign of quotient is determined as in algebra while the
+ * sign of remainder is the same as the sign of dividend:
+ * +26 : +7 = +3, remainder is +5
+ * -26 : +7 = -3, remainder is -5
+ * +26 : -7 = -3, remainder is +5
+ * -26 : -7 = +3, remainder is -5 */
+ struct mpz_seg dumx, dumy, *ex, *ey, *es, *e;
+ int sx, sy, k, nx, ny, n;
+ unsigned int t;
+ unsigned short *work, *wx, *wy;
+ /* divide by zero is not allowed */
+ if (y->val == 0)
+ { xassert(y->ptr == NULL);
+ xerror("mpz_div: divide by zero not allowed\n");
+ }
+ /* if [x] = 0 then [q] = [r] = 0 */
+ if (x->val == 0)
+ { xassert(x->ptr == NULL);
+ if (q != NULL)
+ mpz_set_si(q, 0);
+ if (r != NULL)
+ mpz_set_si(r, 0);
+ goto done;
+ }
+ /* special case when both [x] and [y] are in short format */
+ if (x->ptr == NULL && y->ptr == NULL)
+ { int xval = x->val, yval = y->val;
+ xassert(xval != 0x80000000 && yval != 0x80000000);
+ /* FIXME: use div function */
+ if (q != NULL)
+ mpz_set_si(q, xval / yval);
+ if (r != NULL)
+ mpz_set_si(r, xval % yval);
+ goto done;
+ }
+ /* convert [x] to long format, if necessary */
+ if (x->ptr == NULL)
+ { xassert(x->val != 0x80000000);
+ if (x->val >= 0)
+ { sx = +1;
+ t = (unsigned int)(+ x->val);
+ }
+ else
+ { sx = -1;
+ t = (unsigned int)(- x->val);
+ }
+ ex = &dumx;
+ ex->d[0] = (unsigned short)t;
+ ex->d[1] = (unsigned short)(t >> 16);
+ ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+ ex->next = NULL;
+ }
+ else
+ { sx = x->val;
+ xassert(sx == +1 || sx == -1);
+ ex = x->ptr;
+ }
+ /* convert [y] to long format, if necessary */
+ if (y->ptr == NULL)
+ { xassert(y->val != 0x80000000);
+ if (y->val >= 0)
+ { sy = +1;
+ t = (unsigned int)(+ y->val);
+ }
+ else
+ { sy = -1;
+ t = (unsigned int)(- y->val);
+ }
+ ey = &dumy;
+ ey->d[0] = (unsigned short)t;
+ ey->d[1] = (unsigned short)(t >> 16);
+ ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+ ey->next = NULL;
+ }
+ else
+ { sy = y->val;
+ xassert(sy == +1 || sy == -1);
+ ey = y->ptr;
+ }
+ /* determine the number of digits of [x] */
+ nx = n = 0;
+ for (e = ex; e != NULL; e = e->next)
+ { for (k = 0; k <= 5; k++)
+ { n++;
+ if (e->d[k])
+ nx = n;
+ }
+ }
+ xassert(nx > 0);
+ /* determine the number of digits of [y] */
+ ny = n = 0;
+ for (e = ey; e != NULL; e = e->next)
+ { for (k = 0; k <= 5; k++)
+ { n++;
+ if (e->d[k])
+ ny = n;
+ }
+ }
+ xassert(ny > 0);
+ /* if nx < ny then [q] = 0 and [r] = [x] */
+ if (nx < ny)
+ { if (r != NULL)
+ mpz_set(r, x);
+ if (q != NULL)
+ mpz_set_si(q, 0);
+ goto done;
+ }
+ /* we need working array containing at least nx+ny+1 places */
+ work = gmp_get_work(nx+ny+1);
+ /* load digits of [x] */
+ wx = &work[0];
+ for (n = 0; n < nx; n++)
+ wx[n] = 0;
+ for (n = 0, e = ex; e != NULL; e = e->next)
+ { for (k = 0; k <= 5; k++, n++)
+ if (e->d[k]) wx[n] = e->d[k];
+ }
+ /* load digits of [y] */
+ wy = &work[nx+1];
+ for (n = 0; n < ny; n++)
+ wy[n] = 0;
+ for (n = 0, e = ey; e != NULL; e = e->next)
+ { for (k = 0; k <= 5; k++, n++)
+ if (e->d[k]) wy[n] = e->d[k];
+ }
+ /* compute quotient and remainder */
+ xassert(wy[ny-1] != 0);
+ bigdiv(nx-ny, ny, wx, wy);
+ /* construct and normalize quotient */
+ if (q != NULL)
+ { mpz_set_si(q, 0);
+ q->val = sx * sy;
+ es = NULL;
+ k = 6;
+ for (n = ny; n <= nx; n++)
+ { if (k > 5)
+ { e = gmp_get_atom(sizeof(struct mpz_seg));
+ e->d[0] = e->d[1] = e->d[2] = 0;
+ e->d[3] = e->d[4] = e->d[5] = 0;
+ e->next = NULL;
+ if (q->ptr == NULL)
+ q->ptr = e;
+ else
+ es->next = e;
+ es = e;
+ k = 0;
+ }
+ es->d[k++] = wx[n];
+ }
+ normalize(q);
+ }
+ /* construct and normalize remainder */
+ if (r != NULL)
+ { mpz_set_si(r, 0);
+ r->val = sx;
+ es = NULL;
+ k = 6;
+ for (n = 0; n < ny; n++)
+ { if (k > 5)
+ { e = gmp_get_atom(sizeof(struct mpz_seg));
+ e->d[0] = e->d[1] = e->d[2] = 0;
+ e->d[3] = e->d[4] = e->d[5] = 0;
+ e->next = NULL;
+ if (r->ptr == NULL)
+ r->ptr = e;
+ else
+ es->next = e;
+ es = e;
+ k = 0;
+ }
+ es->d[k++] = wx[n];
+ }
+ normalize(r);
+ }
+done: return;
+}
+
+void mpz_gcd(mpz_t z, mpz_t x, mpz_t y)
+{ /* set z to the greatest common divisor of x and y */
+ /* in case of arbitrary integers GCD(x, y) = GCD(|x|, |y|), and,
+ * in particular, GCD(0, 0) = 0 */
+ mpz_t u, v, r;
+ mpz_init(u);
+ mpz_init(v);
+ mpz_init(r);
+ mpz_abs(u, x);
+ mpz_abs(v, y);
+ while (mpz_sgn(v))
+ { mpz_div(NULL, r, u, v);
+ mpz_set(u, v);
+ mpz_set(v, r);
+ }
+ mpz_set(z, u);
+ mpz_clear(u);
+ mpz_clear(v);
+ mpz_clear(r);
+ return;
+}
+
+int mpz_cmp(mpz_t x, mpz_t y)
+{ /* compare x and y; return a positive value if x > y, zero if
+ * x = y, or a nefative value if x < y */
+ static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL };
+ struct mpz_seg dumx, dumy, *ex, *ey;
+ int cc, sx, sy, k;
+ unsigned int t;
+ if (x == y)
+ { cc = 0;
+ goto done;
+ }
+ /* special case when both [x] and [y] are in short format */
+ if (x->ptr == NULL && y->ptr == NULL)
+ { int xval = x->val, yval = y->val;
+ xassert(xval != 0x80000000 && yval != 0x80000000);
+ cc = (xval > yval ? +1 : xval < yval ? -1 : 0);
+ goto done;
+ }
+ /* special case when [x] and [y] have different signs */
+ if (x->val > 0 && y->val <= 0 || x->val == 0 && y->val < 0)
+ { cc = +1;
+ goto done;
+ }
+ if (x->val < 0 && y->val >= 0 || x->val == 0 && y->val > 0)
+ { cc = -1;
+ goto done;
+ }
+ /* convert [x] to long format, if necessary */
+ if (x->ptr == NULL)
+ { xassert(x->val != 0x80000000);
+ if (x->val >= 0)
+ { sx = +1;
+ t = (unsigned int)(+ x->val);
+ }
+ else
+ { sx = -1;
+ t = (unsigned int)(- x->val);
+ }
+ ex = &dumx;
+ ex->d[0] = (unsigned short)t;
+ ex->d[1] = (unsigned short)(t >> 16);
+ ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+ ex->next = NULL;
+ }
+ else
+ { sx = x->val;
+ xassert(sx == +1 || sx == -1);
+ ex = x->ptr;
+ }
+ /* convert [y] to long format, if necessary */
+ if (y->ptr == NULL)
+ { xassert(y->val != 0x80000000);
+ if (y->val >= 0)
+ { sy = +1;
+ t = (unsigned int)(+ y->val);
+ }
+ else
+ { sy = -1;
+ t = (unsigned int)(- y->val);
+ }
+ ey = &dumy;
+ ey->d[0] = (unsigned short)t;
+ ey->d[1] = (unsigned short)(t >> 16);
+ ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+ ey->next = NULL;
+ }
+ else
+ { sy = y->val;
+ xassert(sy == +1 || sy == -1);
+ ey = y->ptr;
+ }
+ /* main fragment */
+ xassert(sx > 0 && sy > 0 || sx < 0 && sy < 0);
+ cc = 0;
+ for (; ex || ey; ex = ex->next, ey = ey->next)
+ { if (ex == NULL)
+ ex = &zero;
+ if (ey == NULL)
+ ey = &zero;
+ for (k = 0; k <= 5; k++)
+ { if (ex->d[k] > ey->d[k])
+ cc = +1;
+ if (ex->d[k] < ey->d[k])
+ cc = -1;
+ }
+ }
+ if (sx < 0) cc = - cc;
+done: return cc;
+}
+
+int mpz_sgn(mpz_t x)
+{ /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
+ int s;
+ s = (x->val > 0 ? +1 : x->val < 0 ? -1 : 0);
+ return s;
+}
+
+int mpz_out_str(void *_fp, int base, mpz_t x)
+{ /* output x on stream fp, as a string in given base; the base
+ * may vary from 2 to 36;
+ * return the number of bytes written, or if an error occurred,
+ * return 0 */
+ FILE *fp = _fp;
+ mpz_t b, y, r;
+ int n, j, nwr = 0;
+ unsigned char *d;
+ static char *set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ if (!(2 <= base && base <= 36))
+ xerror("mpz_out_str: base = %d; invalid base\n", base);
+ mpz_init(b);
+ mpz_set_si(b, base);
+ mpz_init(y);
+ mpz_init(r);
+ /* determine the number of digits */
+ mpz_abs(y, x);
+ for (n = 0; mpz_sgn(y) != 0; n++)
+ mpz_div(y, NULL, y, b);
+ if (n == 0) n = 1;
+ /* compute the digits */
+ d = xmalloc(n);
+ mpz_abs(y, x);
+ for (j = 0; j < n; j++)
+ { mpz_div(y, r, y, b);
+ xassert(0 <= r->val && r->val < base && r->ptr == NULL);
+ d[j] = (unsigned char)r->val;
+ }
+ /* output the integer to the stream */
+ if (fp == NULL)
+ fp = stdout;
+ if (mpz_sgn(x) < 0)
+ fputc('-', fp), nwr++;
+ for (j = n-1; j >= 0; j--)
+ fputc(set[d[j]], fp), nwr++;
+ if (ferror(fp))
+ nwr = 0;
+ mpz_clear(b);
+ mpz_clear(y);
+ mpz_clear(r);
+ xfree(d);
+ return nwr;
+}
+
+/*--------------------------------------------------------------------*/
+
+mpq_t _mpq_init(void)
+{ /* initialize x, and set its value to 0/1 */
+ mpq_t x;
+ x = gmp_get_atom(sizeof(struct mpq));
+ x->p.val = 0;
+ x->p.ptr = NULL;
+ x->q.val = 1;
+ x->q.ptr = NULL;
+ return x;
+}
+
+void mpq_clear(mpq_t x)
+{ /* free the space occupied by x */
+ mpz_set_si(&x->p, 0);
+ xassert(x->p.ptr == NULL);
+ mpz_set_si(&x->q, 0);
+ xassert(x->q.ptr == NULL);
+ /* free the number descriptor */
+ gmp_free_atom(x, sizeof(struct mpq));
+ return;
+}
+
+void mpq_canonicalize(mpq_t x)
+{ /* remove any factors that are common to the numerator and
+ * denominator of x, and make the denominator positive */
+ mpz_t f;
+ xassert(x->q.val != 0);
+ if (x->q.val < 0)
+ { mpz_neg(&x->p, &x->p);
+ mpz_neg(&x->q, &x->q);
+ }
+ mpz_init(f);
+ mpz_gcd(f, &x->p, &x->q);
+ if (!(f->val == 1 && f->ptr == NULL))
+ { mpz_div(&x->p, NULL, &x->p, f);
+ mpz_div(&x->q, NULL, &x->q, f);
+ }
+ mpz_clear(f);
+ return;
+}
+
+void mpq_set(mpq_t z, mpq_t x)
+{ /* set the value of z from x */
+ if (z != x)
+ { mpz_set(&z->p, &x->p);
+ mpz_set(&z->q, &x->q);
+ }
+ return;
+}
+
+void mpq_set_si(mpq_t x, int p, unsigned int q)
+{ /* set the value of x to p/q */
+ if (q == 0)
+ xerror("mpq_set_si: zero denominator not allowed\n");
+ mpz_set_si(&x->p, p);
+ xassert(q <= 0x7FFFFFFF);
+ mpz_set_si(&x->q, q);
+ return;
+}
+
+double mpq_get_d(mpq_t x)
+{ /* convert x to a double, truncating if necessary */
+ int np, nq;
+ double p, q;
+ p = mpz_get_d_2exp(&np, &x->p);
+ q = mpz_get_d_2exp(&nq, &x->q);
+ return ldexp(p / q, np - nq);
+}
+
+void mpq_set_d(mpq_t x, double val)
+{ /* set x to val; there is no rounding, the conversion is exact */
+ int s, n, d, j;
+ double f;
+ mpz_t temp;
+ xassert(-DBL_MAX <= val && val <= +DBL_MAX);
+ mpq_set_si(x, 0, 1);
+ if (val > 0.0)
+ s = +1;
+ else if (val < 0.0)
+ s = -1;
+ else
+ goto done;
+ f = frexp(fabs(val), &n);
+ /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
+ mpz_init(temp);
+ while (f != 0.0)
+ { f *= 16.0, n -= 4;
+ d = (int)f;
+ xassert(0 <= d && d <= 15);
+ f -= (double)d;
+ /* x := 16 * x + d */
+ mpz_set_si(temp, 16);
+ mpz_mul(&x->p, &x->p, temp);
+ mpz_set_si(temp, d);
+ mpz_add(&x->p, &x->p, temp);
+ }
+ mpz_clear(temp);
+ /* x := x * 2^n */
+ if (n > 0)
+ { for (j = 1; j <= n; j++)
+ mpz_add(&x->p, &x->p, &x->p);
+ }
+ else if (n < 0)
+ { for (j = 1; j <= -n; j++)
+ mpz_add(&x->q, &x->q, &x->q);
+ mpq_canonicalize(x);
+ }
+ if (s < 0)
+ mpq_neg(x, x);
+done: return;
+}
+
+void mpq_add(mpq_t z, mpq_t x, mpq_t y)
+{ /* set z to x + y */
+ mpz_t p, q;
+ mpz_init(p);
+ mpz_init(q);
+ mpz_mul(p, &x->p, &y->q);
+ mpz_mul(q, &x->q, &y->p);
+ mpz_add(p, p, q);
+ mpz_mul(q, &x->q, &y->q);
+ mpz_set(&z->p, p);
+ mpz_set(&z->q, q);
+ mpz_clear(p);
+ mpz_clear(q);
+ mpq_canonicalize(z);
+ return;
+}
+
+void mpq_sub(mpq_t z, mpq_t x, mpq_t y)
+{ /* set z to x - y */
+ mpz_t p, q;
+ mpz_init(p);
+ mpz_init(q);
+ mpz_mul(p, &x->p, &y->q);
+ mpz_mul(q, &x->q, &y->p);
+ mpz_sub(p, p, q);
+ mpz_mul(q, &x->q, &y->q);
+ mpz_set(&z->p, p);
+ mpz_set(&z->q, q);
+ mpz_clear(p);
+ mpz_clear(q);
+ mpq_canonicalize(z);
+ return;
+}
+
+void mpq_mul(mpq_t z, mpq_t x, mpq_t y)
+{ /* set z to x * y */
+ mpz_mul(&z->p, &x->p, &y->p);
+ mpz_mul(&z->q, &x->q, &y->q);
+ mpq_canonicalize(z);
+ return;
+}
+
+void mpq_div(mpq_t z, mpq_t x, mpq_t y)
+{ /* set z to x / y */
+ mpz_t p, q;
+ if (mpq_sgn(y) == 0)
+ xerror("mpq_div: zero divisor not allowed\n");
+ mpz_init(p);
+ mpz_init(q);
+ mpz_mul(p, &x->p, &y->q);
+ mpz_mul(q, &x->q, &y->p);
+ mpz_set(&z->p, p);
+ mpz_set(&z->q, q);
+ mpz_clear(p);
+ mpz_clear(q);
+ mpq_canonicalize(z);
+ return;
+}
+
+void mpq_neg(mpq_t z, mpq_t x)
+{ /* set z to 0 - x */
+ mpq_set(z, x);
+ mpz_neg(&z->p, &z->p);
+ return;
+}
+
+void mpq_abs(mpq_t z, mpq_t x)
+{ /* set z to the absolute value of x */
+ mpq_set(z, x);
+ mpz_abs(&z->p, &z->p);
+ xassert(mpz_sgn(&x->q) > 0);
+ return;
+}
+
+int mpq_cmp(mpq_t x, mpq_t y)
+{ /* compare x and y; return a positive value if x > y, zero if
+ * x = y, or a negative value if x < y */
+ mpq_t temp;
+ int s;
+ mpq_init(temp);
+ mpq_sub(temp, x, y);
+ s = mpq_sgn(temp);
+ mpq_clear(temp);
+ return s;
+}
+
+int mpq_sgn(mpq_t x)
+{ /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
+ int s;
+ s = mpz_sgn(&x->p);
+ xassert(mpz_sgn(&x->q) > 0);
+ return s;
+}
+
+int mpq_out_str(void *_fp, int base, mpq_t x)
+{ /* output x on stream fp, as a string in given base; the base
+ * may vary from 2 to 36; output is in the form 'num/den' or if
+ * the denominator is 1 then just 'num';
+ * if the parameter fp is a null pointer, stdout is assumed;
+ * return the number of bytes written, or if an error occurred,
+ * return 0 */
+ FILE *fp = _fp;
+ int nwr;
+ if (!(2 <= base && base <= 36))
+ xerror("mpq_out_str: base = %d; invalid base\n", base);
+ if (fp == NULL)
+ fp = stdout;
+ nwr = mpz_out_str(fp, base, &x->p);
+ if (x->q.val == 1 && x->q.ptr == NULL)
+ ;
+ else
+ { fputc('/', fp), nwr++;
+ nwr += mpz_out_str(fp, base, &x->q);
+ }
+ if (ferror(fp))
+ nwr = 0;
+ return nwr;
+}
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/mygmp.h b/test/monniaux/glpk-4.65/src/misc/mygmp.h
new file mode 100644
index 00000000..31d2024d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/mygmp.h
@@ -0,0 +1,254 @@
+/* mygmp.h (integer and rational arithmetic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2008-2015 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/>.
+***********************************************************************/
+
+#ifndef MYGMP_H
+#define MYGMP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_GMP /* use GNU MP library */
+
+#include <gmp.h>
+
+#define gmp_pool_count() 0
+
+#define gmp_free_mem() ((void)0)
+
+#else /* use GLPK MP module */
+
+/***********************************************************************
+* INTEGER NUMBERS
+* ---------------
+* Depending on its magnitude an integer number of arbitrary precision
+* is represented either in short format or in long format.
+*
+* Short format corresponds to the int type and allows representing
+* integer numbers in the range [-(2^31-1), +(2^31-1)]. Note that for
+* the most negative number of int type the short format is not used.
+*
+* In long format integer numbers are represented using the positional
+* system with the base (radix) 2^16 = 65536:
+*
+* x = (-1)^s sum{j in 0..n-1} d[j] * 65536^j,
+*
+* where x is the integer to be represented, s is its sign (+1 or -1),
+* d[j] are its digits (0 <= d[j] <= 65535).
+*
+* RATIONAL NUMBERS
+* ----------------
+* A rational number is represented as an irreducible fraction:
+*
+* p / q,
+*
+* where p (numerator) and q (denominator) are integer numbers (q > 0)
+* having no common divisors. */
+
+struct mpz
+{ /* integer number */
+ int val;
+ /* if ptr is a null pointer, the number is in short format, and
+ val is its value; otherwise, the number is in long format, and
+ val is its sign (+1 or -1) */
+ struct mpz_seg *ptr;
+ /* pointer to the linked list of the number segments ordered in
+ ascending of powers of the base */
+};
+
+struct mpz_seg
+{ /* integer number segment */
+ unsigned short d[6];
+ /* six digits of the number ordered in ascending of powers of the
+ base */
+ struct mpz_seg *next;
+ /* pointer to the next number segment */
+};
+
+struct mpq
+{ /* rational number (p / q) */
+ struct mpz p;
+ /* numerator */
+ struct mpz q;
+ /* denominator */
+};
+
+typedef struct mpz *mpz_t;
+typedef struct mpq *mpq_t;
+
+#define gmp_get_atom _glp_gmp_get_atom
+void *gmp_get_atom(int size);
+
+#define gmp_free_atom _glp_gmp_free_atom
+void gmp_free_atom(void *ptr, int size);
+
+#define gmp_pool_count _glp_gmp_pool_count
+int gmp_pool_count(void);
+
+#define gmp_get_work _glp_gmp_get_work
+unsigned short *gmp_get_work(int size);
+
+#define gmp_free_mem _glp_gmp_free_mem
+void gmp_free_mem(void);
+
+#define mpz_init(x) (void)((x) = _mpz_init())
+
+#define _mpz_init _glp_mpz_init
+mpz_t _mpz_init(void);
+/* initialize x and set its value to 0 */
+
+#define mpz_clear _glp_mpz_clear
+void mpz_clear(mpz_t x);
+/* free the space occupied by x */
+
+#define mpz_set _glp_mpz_set
+void mpz_set(mpz_t z, mpz_t x);
+/* set the value of z from x */
+
+#define mpz_set_si _glp_mpz_set_si
+void mpz_set_si(mpz_t x, int val);
+/* set the value of x to val */
+
+#define mpz_get_d _glp_mpz_get_d
+double mpz_get_d(mpz_t x);
+/* convert x to a double, truncating if necessary */
+
+#define mpz_get_d_2exp _glp_mpz_get_d_2exp
+double mpz_get_d_2exp(int *exp, mpz_t x);
+/* convert x to a double, returning the exponent separately */
+
+#define mpz_swap _glp_mpz_swap
+void mpz_swap(mpz_t x, mpz_t y);
+/* swap the values x and y efficiently */
+
+#define mpz_add _glp_mpz_add
+void mpz_add(mpz_t, mpz_t, mpz_t);
+/* set z to x + y */
+
+#define mpz_sub _glp_mpz_sub
+void mpz_sub(mpz_t, mpz_t, mpz_t);
+/* set z to x - y */
+
+#define mpz_mul _glp_mpz_mul
+void mpz_mul(mpz_t, mpz_t, mpz_t);
+/* set z to x * y */
+
+#define mpz_neg _glp_mpz_neg
+void mpz_neg(mpz_t z, mpz_t x);
+/* set z to 0 - x */
+
+#define mpz_abs _glp_mpz_abs
+void mpz_abs(mpz_t z, mpz_t x);
+/* set z to the absolute value of x */
+
+#define mpz_div _glp_mpz_div
+void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y);
+/* divide x by y, forming quotient q and/or remainder r */
+
+#define mpz_gcd _glp_mpz_gcd
+void mpz_gcd(mpz_t z, mpz_t x, mpz_t y);
+/* set z to the greatest common divisor of x and y */
+
+#define mpz_cmp _glp_mpz_cmp
+int mpz_cmp(mpz_t x, mpz_t y);
+/* compare x and y */
+
+#define mpz_sgn _glp_mpz_sgn
+int mpz_sgn(mpz_t x);
+/* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
+
+#define mpz_out_str _glp_mpz_out_str
+int mpz_out_str(void *fp, int base, mpz_t x);
+/* output x on stream fp, as a string in given base */
+
+#define mpq_init(x) (void)((x) = _mpq_init())
+
+#define _mpq_init _glp_mpq_init
+mpq_t _mpq_init(void);
+/* initialize x, and set its value to 0/1 */
+
+#define mpq_clear _glp_mpq_clear
+void mpq_clear(mpq_t x);
+/* free the space occupied by x */
+
+#define mpq_canonicalize _glp_mpq_canonicalize
+void mpq_canonicalize(mpq_t x);
+/* canonicalize x */
+
+#define mpq_set _glp_mpq_set
+void mpq_set(mpq_t z, mpq_t x);
+/* set the value of z from x */
+
+#define mpq_set_si _glp_mpq_set_si
+void mpq_set_si(mpq_t x, int p, unsigned int q);
+/* set the value of x to p/q */
+
+#define mpq_get_d _glp_mpq_get_d
+double mpq_get_d(mpq_t x);
+/* convert x to a double, truncating if necessary */
+
+#define mpq_set_d _glp_mpq_set_d
+void mpq_set_d(mpq_t x, double val);
+/* set x to val; there is no rounding, the conversion is exact */
+
+#define mpq_add _glp_mpq_add
+void mpq_add(mpq_t z, mpq_t x, mpq_t y);
+/* set z to x + y */
+
+#define mpq_sub _glp_mpq_sub
+void mpq_sub(mpq_t z, mpq_t x, mpq_t y);
+/* set z to x - y */
+
+#define mpq_mul _glp_mpq_mul
+void mpq_mul(mpq_t z, mpq_t x, mpq_t y);
+/* set z to x * y */
+
+#define mpq_div _glp_mpq_div
+void mpq_div(mpq_t z, mpq_t x, mpq_t y);
+/* set z to x / y */
+
+#define mpq_neg _glp_mpq_neg
+void mpq_neg(mpq_t z, mpq_t x);
+/* set z to 0 - x */
+
+#define mpq_abs _glp_mpq_abs
+void mpq_abs(mpq_t z, mpq_t x);
+/* set z to the absolute value of x */
+
+#define mpq_cmp _glp_mpq_cmp
+int mpq_cmp(mpq_t x, mpq_t y);
+/* compare x and y */
+
+#define mpq_sgn _glp_mpq_sgn
+int mpq_sgn(mpq_t x);
+/* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
+
+#define mpq_out_str _glp_mpq_out_str
+int mpq_out_str(void *fp, int base, mpq_t x);
+/* output x on stream fp, as a string in given base */
+
+#endif
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/okalg.c b/test/monniaux/glpk-4.65/src/misc/okalg.c
new file mode 100644
index 00000000..8eecd6df
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/okalg.c
@@ -0,0 +1,382 @@
+/* okalg.c (out-of-kilter algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "okalg.h"
+
+/***********************************************************************
+* NAME
+*
+* okalg - out-of-kilter algorithm
+*
+* SYNOPSIS
+*
+* #include "okalg.h"
+* int okalg(int nv, int na, const int tail[], const int head[],
+* const int low[], const int cap[], const int cost[], int x[],
+* int pi[]);
+*
+* DESCRIPTION
+*
+* The routine okalg implements the out-of-kilter algorithm to find a
+* minimal-cost circulation in the specified flow network.
+*
+* INPUT PARAMETERS
+*
+* nv is the number of nodes, nv >= 0.
+*
+* na is the number of arcs, na >= 0.
+*
+* tail[a], a = 1,...,na, is the index of tail node of arc a.
+*
+* head[a], a = 1,...,na, is the index of head node of arc a.
+*
+* low[a], a = 1,...,na, is an lower bound to the flow through arc a.
+*
+* cap[a], a = 1,...,na, is an upper bound to the flow through arc a,
+* which is the capacity of the arc.
+*
+* cost[a], a = 1,...,na, is a per-unit cost of the flow through arc a.
+*
+* NOTES
+*
+* 1. Multiple arcs are allowed, but self-loops are not allowed.
+*
+* 2. It is required that 0 <= low[a] <= cap[a] for all arcs.
+*
+* 3. Arc costs may have any sign.
+*
+* OUTPUT PARAMETERS
+*
+* x[a], a = 1,...,na, is optimal value of the flow through arc a.
+*
+* pi[i], i = 1,...,nv, is Lagrange multiplier for flow conservation
+* equality constraint corresponding to node i (the node potential).
+*
+* RETURNS
+*
+* 0 optimal circulation found;
+*
+* 1 there is no feasible circulation;
+*
+* 2 integer overflow occured;
+*
+* 3 optimality test failed (logic error).
+*
+* REFERENCES
+*
+* L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
+* Corp., Report R-375-PR (August 1962), Chap. III "Minimal Cost Flow
+* Problems," pp.113-26. */
+
+static int overflow(int u, int v)
+{ /* check for integer overflow on computing u + v */
+ if (u > 0 && v > 0 && u + v < 0) return 1;
+ if (u < 0 && v < 0 && u + v > 0) return 1;
+ return 0;
+}
+
+int okalg(int nv, int na, const int tail[], const int head[],
+ const int low[], const int cap[], const int cost[], int x[],
+ int pi[])
+{ int a, aok, delta, i, j, k, lambda, pos1, pos2, s, t, temp, ret,
+ *ptr, *arc, *link, *list;
+ /* sanity checks */
+ xassert(nv >= 0);
+ xassert(na >= 0);
+ for (a = 1; a <= na; a++)
+ { i = tail[a], j = head[a];
+ xassert(1 <= i && i <= nv);
+ xassert(1 <= j && j <= nv);
+ xassert(i != j);
+ xassert(0 <= low[a] && low[a] <= cap[a]);
+ }
+ /* allocate working arrays */
+ ptr = xcalloc(1+nv+1, sizeof(int));
+ arc = xcalloc(1+na+na, sizeof(int));
+ link = xcalloc(1+nv, sizeof(int));
+ list = xcalloc(1+nv, sizeof(int));
+ /* ptr[i] := (degree of node i) */
+ for (i = 1; i <= nv; i++)
+ ptr[i] = 0;
+ for (a = 1; a <= na; a++)
+ { ptr[tail[a]]++;
+ ptr[head[a]]++;
+ }
+ /* initialize arc pointers */
+ ptr[1]++;
+ for (i = 1; i < nv; i++)
+ ptr[i+1] += ptr[i];
+ ptr[nv+1] = ptr[nv];
+ /* build arc lists */
+ for (a = 1; a <= na; a++)
+ { arc[--ptr[tail[a]]] = a;
+ arc[--ptr[head[a]]] = a;
+ }
+ xassert(ptr[1] == 1);
+ xassert(ptr[nv+1] == na+na+1);
+ /* now the indices of arcs incident to node i are stored in
+ * locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
+ /* initialize arc flows and node potentials */
+ for (a = 1; a <= na; a++)
+ x[a] = 0;
+ for (i = 1; i <= nv; i++)
+ pi[i] = 0;
+loop: /* main loop starts here */
+ /* find out-of-kilter arc */
+ aok = 0;
+ for (a = 1; a <= na; a++)
+ { i = tail[a], j = head[a];
+ if (overflow(cost[a], pi[i] - pi[j]))
+ { ret = 2;
+ goto done;
+ }
+ lambda = cost[a] + (pi[i] - pi[j]);
+ if (x[a] < low[a] || (lambda < 0 && x[a] < cap[a]))
+ { /* arc a = i->j is out of kilter, and we need to increase
+ * the flow through this arc */
+ aok = a, s = j, t = i;
+ break;
+ }
+ if (x[a] > cap[a] || (lambda > 0 && x[a] > low[a]))
+ { /* arc a = i->j is out of kilter, and we need to decrease
+ * the flow through this arc */
+ aok = a, s = i, t = j;
+ break;
+ }
+ }
+ if (aok == 0)
+ { /* all arcs are in kilter */
+ /* check for feasibility */
+ for (a = 1; a <= na; a++)
+ { if (!(low[a] <= x[a] && x[a] <= cap[a]))
+ { ret = 3;
+ goto done;
+ }
+ }
+ for (i = 1; i <= nv; i++)
+ { temp = 0;
+ for (k = ptr[i]; k < ptr[i+1]; k++)
+ { a = arc[k];
+ if (tail[a] == i)
+ { /* a is outgoing arc */
+ temp += x[a];
+ }
+ else if (head[a] == i)
+ { /* a is incoming arc */
+ temp -= x[a];
+ }
+ else
+ xassert(a != a);
+ }
+ if (temp != 0)
+ { ret = 3;
+ goto done;
+ }
+ }
+ /* check for optimality */
+ for (a = 1; a <= na; a++)
+ { i = tail[a], j = head[a];
+ lambda = cost[a] + (pi[i] - pi[j]);
+ if ((lambda > 0 && x[a] != low[a]) ||
+ (lambda < 0 && x[a] != cap[a]))
+ { ret = 3;
+ goto done;
+ }
+ }
+ /* current circulation is optimal */
+ ret = 0;
+ goto done;
+ }
+ /* now we need to find a cycle (t, a, s, ..., t), which allows
+ * increasing the flow along it, where a is the out-of-kilter arc
+ * just found */
+ /* link[i] = 0 means that node i is not labelled yet;
+ * link[i] = a means that arc a immediately precedes node i */
+ /* initially only node s is labelled */
+ for (i = 1; i <= nv; i++)
+ link[i] = 0;
+ link[s] = aok, list[1] = s, pos1 = pos2 = 1;
+ /* breadth first search */
+ while (pos1 <= pos2)
+ { /* dequeue node i */
+ i = list[pos1++];
+ /* consider all arcs incident to node i */
+ for (k = ptr[i]; k < ptr[i+1]; k++)
+ { a = arc[k];
+ if (tail[a] == i)
+ { /* a = i->j is a forward arc from s to t */
+ j = head[a];
+ /* if node j has been labelled, skip the arc */
+ if (link[j] != 0) continue;
+ /* if the arc does not allow increasing the flow through
+ * it, skip the arc */
+ if (x[a] >= cap[a]) continue;
+ if (overflow(cost[a], pi[i] - pi[j]))
+ { ret = 2;
+ goto done;
+ }
+ lambda = cost[a] + (pi[i] - pi[j]);
+ if (lambda > 0 && x[a] >= low[a]) continue;
+ }
+ else if (head[a] == i)
+ { /* a = i<-j is a backward arc from s to t */
+ j = tail[a];
+ /* if node j has been labelled, skip the arc */
+ if (link[j] != 0) continue;
+ /* if the arc does not allow decreasing the flow through
+ * it, skip the arc */
+ if (x[a] <= low[a]) continue;
+ if (overflow(cost[a], pi[j] - pi[i]))
+ { ret = 2;
+ goto done;
+ }
+ lambda = cost[a] + (pi[j] - pi[i]);
+ if (lambda < 0 && x[a] <= cap[a]) continue;
+ }
+ else
+ xassert(a != a);
+ /* label node j and enqueue it */
+ link[j] = a, list[++pos2] = j;
+ /* check for breakthrough */
+ if (j == t) goto brkt;
+ }
+ }
+ /* NONBREAKTHROUGH */
+ /* consider all arcs, whose one endpoint is labelled and other is
+ * not, and determine maximal change of node potentials */
+ delta = 0;
+ for (a = 1; a <= na; a++)
+ { i = tail[a], j = head[a];
+ if (link[i] != 0 && link[j] == 0)
+ { /* a = i->j, where node i is labelled, node j is not */
+ if (overflow(cost[a], pi[i] - pi[j]))
+ { ret = 2;
+ goto done;
+ }
+ lambda = cost[a] + (pi[i] - pi[j]);
+ if (x[a] <= cap[a] && lambda > 0)
+ if (delta == 0 || delta > + lambda) delta = + lambda;
+ }
+ else if (link[i] == 0 && link[j] != 0)
+ { /* a = j<-i, where node j is labelled, node i is not */
+ if (overflow(cost[a], pi[i] - pi[j]))
+ { ret = 2;
+ goto done;
+ }
+ lambda = cost[a] + (pi[i] - pi[j]);
+ if (x[a] >= low[a] && lambda < 0)
+ if (delta == 0 || delta > - lambda) delta = - lambda;
+ }
+ }
+ if (delta == 0)
+ { /* there is no feasible circulation */
+ ret = 1;
+ goto done;
+ }
+ /* increase potentials of all unlabelled nodes */
+ for (i = 1; i <= nv; i++)
+ { if (link[i] == 0)
+ { if (overflow(pi[i], delta))
+ { ret = 2;
+ goto done;
+ }
+ pi[i] += delta;
+ }
+ }
+ goto loop;
+brkt: /* BREAKTHROUGH */
+ /* walk through arcs of the cycle (t, a, s, ..., t) found in the
+ * reverse order and determine maximal change of the flow */
+ delta = 0;
+ for (j = t;; j = i)
+ { /* arc a immediately precedes node j in the cycle */
+ a = link[j];
+ if (head[a] == j)
+ { /* a = i->j is a forward arc of the cycle */
+ i = tail[a];
+ lambda = cost[a] + (pi[i] - pi[j]);
+ if (lambda > 0 && x[a] < low[a])
+ { /* x[a] may be increased until its lower bound */
+ temp = low[a] - x[a];
+ }
+ else if (lambda <= 0 && x[a] < cap[a])
+ { /* x[a] may be increased until its upper bound */
+ temp = cap[a] - x[a];
+ }
+ else
+ xassert(a != a);
+ }
+ else if (tail[a] == j)
+ { /* a = i<-j is a backward arc of the cycle */
+ i = head[a];
+ lambda = cost[a] + (pi[j] - pi[i]);
+ if (lambda < 0 && x[a] > cap[a])
+ { /* x[a] may be decreased until its upper bound */
+ temp = x[a] - cap[a];
+ }
+ else if (lambda >= 0 && x[a] > low[a])
+ { /* x[a] may be decreased until its lower bound */
+ temp = x[a] - low[a];
+ }
+ else
+ xassert(a != a);
+ }
+ else
+ xassert(a != a);
+ if (delta == 0 || delta > temp) delta = temp;
+ /* check for end of the cycle */
+ if (i == t) break;
+ }
+ xassert(delta > 0);
+ /* increase the flow along the cycle */
+ for (j = t;; j = i)
+ { /* arc a immediately precedes node j in the cycle */
+ a = link[j];
+ if (head[a] == j)
+ { /* a = i->j is a forward arc of the cycle */
+ i = tail[a];
+ /* overflow cannot occur */
+ x[a] += delta;
+ }
+ else if (tail[a] == j)
+ { /* a = i<-j is a backward arc of the cycle */
+ i = head[a];
+ /* overflow cannot occur */
+ x[a] -= delta;
+ }
+ else
+ xassert(a != a);
+ /* check for end of the cycle */
+ if (i == t) break;
+ }
+ goto loop;
+done: /* free working arrays */
+ xfree(ptr);
+ xfree(arc);
+ xfree(link);
+ xfree(list);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/okalg.h b/test/monniaux/glpk-4.65/src/misc/okalg.h
new file mode 100644
index 00000000..2f2d9740
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/okalg.h
@@ -0,0 +1,35 @@
+/* okalg.h (out-of-kilter algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2013 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/>.
+***********************************************************************/
+
+#ifndef OKALG_H
+#define OKALG_H
+
+#define okalg _glp_okalg
+int okalg(int nv, int na, const int tail[], const int head[],
+ const int low[], const int cap[], const int cost[], int x[],
+ int pi[]);
+/* out-of-kilter algorithm */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/qmd.c b/test/monniaux/glpk-4.65/src/misc/qmd.c
new file mode 100644
index 00000000..a3397dcf
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/qmd.c
@@ -0,0 +1,584 @@
+/* qmd.c (quotient minimum degree algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES
+* GENQMD, QMDRCH, QMDQT, QMDUPD, AND QMDMRG FROM THE BOOK:
+*
+* ALAN GEORGE, JOSEPH W-H LIU. COMPUTER SOLUTION OF LARGE SPARSE
+* POSITIVE DEFINITE SYSTEMS. PRENTICE-HALL, 1981.
+*
+* THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS
+* OF THE ORIGINAL FORTRAN SUBROUTINES: ALAN GEORGE AND JOSEPH LIU,
+* UNIVERSITY OF WATERLOO, WATERLOO, ONTARIO, CANADA.
+*
+* The translation was made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "qmd.h"
+
+/***********************************************************************
+* NAME
+*
+* genqmd - GENeral Quotient Minimum Degree algorithm
+*
+* SYNOPSIS
+*
+* #include "qmd.h"
+* void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
+* int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
+* int qsize[], int qlink[], int *nofsub);
+*
+* PURPOSE
+*
+* This routine implements the minimum degree algorithm. It makes use
+* of the implicit representation of the elimination graph by quotient
+* graphs, and the notion of indistinguishable nodes.
+*
+* CAUTION
+*
+* The adjancy vector adjncy will be destroyed.
+*
+* INPUT PARAMETERS
+*
+* neqns - number of equations;
+* (xadj, adjncy) -
+* the adjancy structure.
+*
+* OUTPUT PARAMETERS
+*
+* perm - the minimum degree ordering;
+* invp - the inverse of perm.
+*
+* WORKING PARAMETERS
+*
+* deg - the degree vector. deg[i] is negative means node i has been
+* numbered;
+* marker - a marker vector, where marker[i] is negative means node i
+* has been merged with another nodeand thus can be ignored;
+* rchset - vector used for the reachable set;
+* nbrhd - vector used for neighborhood set;
+* qsize - vector used to store the size of indistinguishable
+* supernodes;
+* qlink - vector used to store indistinguishable nodes, i, qlink[i],
+* qlink[qlink[i]], ... are the members of the supernode
+* represented by i.
+*
+* PROGRAM SUBROUTINES
+*
+* qmdrch, qmdqt, qmdupd.
+***********************************************************************/
+
+void genqmd(int *_neqns, int xadj[], int adjncy[], int perm[],
+ int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
+ int qsize[], int qlink[], int *_nofsub)
+{ int inode, ip, irch, j, mindeg, ndeg, nhdsze, node, np, num,
+ nump1, nxnode, rchsze, search, thresh;
+# define neqns (*_neqns)
+# define nofsub (*_nofsub)
+ /* Initialize degree vector and other working variables. */
+ mindeg = neqns;
+ nofsub = 0;
+ for (node = 1; node <= neqns; node++)
+ { perm[node] = node;
+ invp[node] = node;
+ marker[node] = 0;
+ qsize[node] = 1;
+ qlink[node] = 0;
+ ndeg = xadj[node+1] - xadj[node];
+ deg[node] = ndeg;
+ if (ndeg < mindeg) mindeg = ndeg;
+ }
+ num = 0;
+ /* Perform threshold search to get a node of min degree.
+ * Variable search point to where search should start. */
+s200: search = 1;
+ thresh = mindeg;
+ mindeg = neqns;
+s300: nump1 = num + 1;
+ if (nump1 > search) search = nump1;
+ for (j = search; j <= neqns; j++)
+ { node = perm[j];
+ if (marker[node] >= 0)
+ { ndeg = deg[node];
+ if (ndeg <= thresh) goto s500;
+ if (ndeg < mindeg) mindeg = ndeg;
+ }
+ }
+ goto s200;
+ /* Node has minimum degree. Find its reachable sets by calling
+ * qmdrch. */
+s500: search = j;
+ nofsub += deg[node];
+ marker[node] = 1;
+ qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset, &nhdsze,
+ nbrhd);
+ /* Eliminate all nodes indistinguishable from node. They are given
+ * by node, qlink[node], ... . */
+ nxnode = node;
+s600: num++;
+ np = invp[nxnode];
+ ip = perm[num];
+ perm[np] = ip;
+ invp[ip] = np;
+ perm[num] = nxnode;
+ invp[nxnode] = num;
+ deg[nxnode] = -1;
+ nxnode = qlink[nxnode];
+ if (nxnode > 0) goto s600;
+ if (rchsze > 0)
+ { /* Update the degrees of the nodes in the reachable set and
+ * identify indistinguishable nodes. */
+ qmdupd(xadj, adjncy, &rchsze, rchset, deg, qsize, qlink,
+ marker, &rchset[rchsze+1], &nbrhd[nhdsze+1]);
+ /* Reset marker value of nodes in reach set. Update threshold
+ * value for cyclic search. Also call qmdqt to form new
+ * quotient graph. */
+ marker[node] = 0;
+ for (irch = 1; irch <= rchsze; irch++)
+ { inode = rchset[irch];
+ if (marker[inode] >= 0)
+ { marker[inode] = 0;
+ ndeg = deg[inode];
+ if (ndeg < mindeg) mindeg = ndeg;
+ if (ndeg <= thresh)
+ { mindeg = thresh;
+ thresh = ndeg;
+ search = invp[inode];
+ }
+ }
+ }
+ if (nhdsze > 0)
+ qmdqt(&node, xadj, adjncy, marker, &rchsze, rchset, nbrhd);
+ }
+ if (num < neqns) goto s300;
+ return;
+# undef neqns
+# undef nofsub
+}
+
+/***********************************************************************
+* NAME
+*
+* qmdrch - Quotient MD ReaCHable set
+*
+* SYNOPSIS
+*
+* #include "qmd.h"
+* void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
+* int marker[], int *rchsze, int rchset[], int *nhdsze,
+* int nbrhd[]);
+*
+* PURPOSE
+*
+* This subroutine determines the reachable set of a node through a
+* given subset. The adjancy structure is assumed to be stored in a
+* quotient graph format.
+*
+* INPUT PARAMETERS
+*
+* root - the given node not in the subset;
+* (xadj, adjncy) -
+* the adjancy structure pair;
+* deg - the degree vector. deg[i] < 0 means the node belongs to the
+* given subset.
+*
+* OUTPUT PARAMETERS
+*
+* (rchsze, rchset) -
+* the reachable set;
+* (nhdsze, nbrhd) -
+* the neighborhood set.
+*
+* UPDATED PARAMETERS
+*
+* marker - the marker vector for reach and nbrhd sets. > 0 means the
+* node is in reach set. < 0 means the node has been merged
+* with others in the quotient or it is in nbrhd set.
+***********************************************************************/
+
+void qmdrch(int *_root, int xadj[], int adjncy[], int deg[],
+ int marker[], int *_rchsze, int rchset[], int *_nhdsze,
+ int nbrhd[])
+{ int i, istop, istrt, j, jstop, jstrt, nabor, node;
+# define root (*_root)
+# define rchsze (*_rchsze)
+# define nhdsze (*_nhdsze)
+ /* Loop through the neighbors of root in the quotient graph. */
+ nhdsze = 0;
+ rchsze = 0;
+ istrt = xadj[root];
+ istop = xadj[root+1] - 1;
+ if (istop < istrt) return;
+ for (i = istrt; i <= istop; i++)
+ { nabor = adjncy[i];
+ if (nabor == 0) return;
+ if (marker[nabor] == 0)
+ { if (deg[nabor] >= 0)
+ { /* Include nabor into the reachable set. */
+ rchsze++;
+ rchset[rchsze] = nabor;
+ marker[nabor] = 1;
+ goto s600;
+ }
+ /* nabor has been eliminated. Find nodes reachable from
+ * it. */
+ marker[nabor] = -1;
+ nhdsze++;
+ nbrhd[nhdsze] = nabor;
+s300: jstrt = xadj[nabor];
+ jstop = xadj[nabor+1] - 1;
+ for (j = jstrt; j <= jstop; j++)
+ { node = adjncy[j];
+ nabor = - node;
+ if (node < 0) goto s300;
+ if (node == 0) goto s600;
+ if (marker[node] == 0)
+ { rchsze++;
+ rchset[rchsze] = node;
+ marker[node] = 1;
+ }
+ }
+ }
+s600: ;
+ }
+ return;
+# undef root
+# undef rchsze
+# undef nhdsze
+}
+
+/***********************************************************************
+* NAME
+*
+* qmdqt - Quotient MD Quotient graph Transformation
+*
+* SYNOPSIS
+*
+* #include "qmd.h"
+* void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
+* int *rchsze, int rchset[], int nbrhd[]);
+*
+* PURPOSE
+*
+* This subroutine performs the quotient graph transformation after a
+* node has been eliminated.
+*
+* INPUT PARAMETERS
+*
+* root - the node just eliminated. It becomes the representative of
+* the new supernode;
+* (xadj, adjncy) -
+* the adjancy structure;
+* (rchsze, rchset) -
+* the reachable set of root in the old quotient graph;
+* nbrhd - the neighborhood set which will be merged with root to form
+* the new supernode;
+* marker - the marker vector.
+*
+* UPDATED PARAMETERS
+*
+* adjncy - becomes the adjncy of the quotient graph.
+***********************************************************************/
+
+void qmdqt(int *_root, int xadj[], int adjncy[], int marker[],
+ int *_rchsze, int rchset[], int nbrhd[])
+{ int inhd, irch, j, jstop, jstrt, link, nabor, node;
+# define root (*_root)
+# define rchsze (*_rchsze)
+ irch = 0;
+ inhd = 0;
+ node = root;
+s100: jstrt = xadj[node];
+ jstop = xadj[node+1] - 2;
+ if (jstop >= jstrt)
+ { /* Place reach nodes into the adjacent list of node. */
+ for (j = jstrt; j <= jstop; j++)
+ { irch++;
+ adjncy[j] = rchset[irch];
+ if (irch >= rchsze) goto s400;
+ }
+ }
+ /* Link to other space provided by the nbrhd set. */
+ link = adjncy[jstop+1];
+ node = - link;
+ if (link >= 0)
+ { inhd++;
+ node = nbrhd[inhd];
+ adjncy[jstop+1] = - node;
+ }
+ goto s100;
+ /* All reachable nodes have been saved. End the adjacent list.
+ * Add root to the neighborhood list of each node in the reach
+ * set. */
+s400: adjncy[j+1] = 0;
+ for (irch = 1; irch <= rchsze; irch++)
+ { node = rchset[irch];
+ if (marker[node] >= 0)
+ { jstrt = xadj[node];
+ jstop = xadj[node+1] - 1;
+ for (j = jstrt; j <= jstop; j++)
+ { nabor = adjncy[j];
+ if (marker[nabor] < 0)
+ { adjncy[j] = root;
+ goto s600;
+ }
+ }
+ }
+s600: ;
+ }
+ return;
+# undef root
+# undef rchsze
+}
+
+/***********************************************************************
+* NAME
+*
+* qmdupd - Quotient MD UPDate
+*
+* SYNOPSIS
+*
+* #include "qmd.h"
+* void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
+* int deg[], int qsize[], int qlink[], int marker[], int rchset[],
+* int nbrhd[]);
+*
+* PURPOSE
+*
+* This routine performs degree update for a set of nodes in the minimum
+* degree algorithm.
+*
+* INPUT PARAMETERS
+*
+* (xadj, adjncy) -
+* the adjancy structure;
+* (nlist, list) -
+* the list of nodes whose degree has to be updated.
+*
+* UPDATED PARAMETERS
+*
+* deg - the degree vector;
+* qsize - size of indistinguishable supernodes;
+* qlink - linked list for indistinguishable nodes;
+* marker - used to mark those nodes in reach/nbrhd sets.
+*
+* WORKING PARAMETERS
+*
+* rchset - the reachable set;
+* nbrhd - the neighborhood set.
+*
+* PROGRAM SUBROUTINES
+*
+* qmdmrg.
+***********************************************************************/
+
+void qmdupd(int xadj[], int adjncy[], int *_nlist, int list[],
+ int deg[], int qsize[], int qlink[], int marker[], int rchset[],
+ int nbrhd[])
+{ int deg0, deg1, il, inhd, inode, irch, j, jstop, jstrt, mark,
+ nabor, nhdsze, node, rchsze;
+# define nlist (*_nlist)
+ /* Find all eliminated supernodes that are adjacent to some nodes
+ * in the given list. Put them into (nhdsze, nbrhd). deg0 contains
+ * the number of nodes in the list. */
+ if (nlist <= 0) return;
+ deg0 = 0;
+ nhdsze = 0;
+ for (il = 1; il <= nlist; il++)
+ { node = list[il];
+ deg0 += qsize[node];
+ jstrt = xadj[node];
+ jstop = xadj[node+1] - 1;
+ for (j = jstrt; j <= jstop; j++)
+ { nabor = adjncy[j];
+ if (marker[nabor] == 0 && deg[nabor] < 0)
+ { marker[nabor] = -1;
+ nhdsze++;
+ nbrhd[nhdsze] = nabor;
+ }
+ }
+ }
+ /* Merge indistinguishable nodes in the list by calling the
+ * subroutine qmdmrg. */
+ if (nhdsze > 0)
+ qmdmrg(xadj, adjncy, deg, qsize, qlink, marker, &deg0, &nhdsze,
+ nbrhd, rchset, &nbrhd[nhdsze+1]);
+ /* Find the new degrees of the nodes that have not been merged. */
+ for (il = 1; il <= nlist; il++)
+ { node = list[il];
+ mark = marker[node];
+ if (mark == 0 || mark == 1)
+ { marker[node] = 2;
+ qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset,
+ &nhdsze, nbrhd);
+ deg1 = deg0;
+ if (rchsze > 0)
+ { for (irch = 1; irch <= rchsze; irch++)
+ { inode = rchset[irch];
+ deg1 += qsize[inode];
+ marker[inode] = 0;
+ }
+ }
+ deg[node] = deg1 - 1;
+ if (nhdsze > 0)
+ { for (inhd = 1; inhd <= nhdsze; inhd++)
+ { inode = nbrhd[inhd];
+ marker[inode] = 0;
+ }
+ }
+ }
+ }
+ return;
+# undef nlist
+}
+
+/***********************************************************************
+* NAME
+*
+* qmdmrg - Quotient MD MeRGe
+*
+* SYNOPSIS
+*
+* #include "qmd.h"
+* void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
+* int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
+* int rchset[], int ovrlp[]);
+*
+* PURPOSE
+*
+* This routine merges indistinguishable nodes in the minimum degree
+* ordering algorithm. It also computes the new degrees of these new
+* supernodes.
+*
+* INPUT PARAMETERS
+*
+* (xadj, adjncy) -
+* the adjancy structure;
+* deg0 - the number of nodes in the given set;
+* (nhdsze, nbrhd) -
+* the set of eliminated supernodes adjacent to some nodes in
+* the set.
+*
+* UPDATED PARAMETERS
+*
+* deg - the degree vector;
+* qsize - size of indistinguishable nodes;
+* qlink - linked list for indistinguishable nodes;
+* marker - the given set is given by those nodes with marker value set
+* to 1. Those nodes with degree updated will have marker value
+* set to 2.
+*
+* WORKING PARAMETERS
+*
+* rchset - the reachable set;
+* ovrlp - temp vector to store the intersection of two reachable sets.
+***********************************************************************/
+
+void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
+ int qlink[], int marker[], int *_deg0, int *_nhdsze, int nbrhd[],
+ int rchset[], int ovrlp[])
+{ int deg1, head, inhd, iov, irch, j, jstop, jstrt, link, lnode,
+ mark, mrgsze, nabor, node, novrlp, rchsze, root;
+# define deg0 (*_deg0)
+# define nhdsze (*_nhdsze)
+ /* Initialization. */
+ if (nhdsze <= 0) return;
+ for (inhd = 1; inhd <= nhdsze; inhd++)
+ { root = nbrhd[inhd];
+ marker[root] = 0;
+ }
+ /* Loop through each eliminated supernode in the set
+ * (nhdsze, nbrhd). */
+ for (inhd = 1; inhd <= nhdsze; inhd++)
+ { root = nbrhd[inhd];
+ marker[root] = -1;
+ rchsze = 0;
+ novrlp = 0;
+ deg1 = 0;
+s200: jstrt = xadj[root];
+ jstop = xadj[root+1] - 1;
+ /* Determine the reachable set and its intersection with the
+ * input reachable set. */
+ for (j = jstrt; j <= jstop; j++)
+ { nabor = adjncy[j];
+ root = - nabor;
+ if (nabor < 0) goto s200;
+ if (nabor == 0) break;
+ mark = marker[nabor];
+ if (mark == 0)
+ { rchsze++;
+ rchset[rchsze] = nabor;
+ deg1 += qsize[nabor];
+ marker[nabor] = 1;
+ }
+ else if (mark == 1)
+ { novrlp++;
+ ovrlp[novrlp] = nabor;
+ marker[nabor] = 2;
+ }
+ }
+ /* From the overlapped set, determine the nodes that can be
+ * merged together. */
+ head = 0;
+ mrgsze = 0;
+ for (iov = 1; iov <= novrlp; iov++)
+ { node = ovrlp[iov];
+ jstrt = xadj[node];
+ jstop = xadj[node+1] - 1;
+ for (j = jstrt; j <= jstop; j++)
+ { nabor = adjncy[j];
+ if (marker[nabor] == 0)
+ { marker[node] = 1;
+ goto s1100;
+ }
+ }
+ /* Node belongs to the new merged supernode. Update the
+ * vectors qlink and qsize. */
+ mrgsze += qsize[node];
+ marker[node] = -1;
+ lnode = node;
+s900: link = qlink[lnode];
+ if (link > 0)
+ { lnode = link;
+ goto s900;
+ }
+ qlink[lnode] = head;
+ head = node;
+s1100: ;
+ }
+ if (head > 0)
+ { qsize[head] = mrgsze;
+ deg[head] = deg0 + deg1 - 1;
+ marker[head] = 2;
+ }
+ /* Reset marker values. */
+ root = nbrhd[inhd];
+ marker[root] = 0;
+ if (rchsze > 0)
+ { for (irch = 1; irch <= rchsze; irch++)
+ { node = rchset[irch];
+ marker[node] = 0;
+ }
+ }
+ }
+ return;
+# undef deg0
+# undef nhdsze
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/qmd.h b/test/monniaux/glpk-4.65/src/misc/qmd.h
new file mode 100644
index 00000000..e55d50f5
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/qmd.h
@@ -0,0 +1,58 @@
+/* qmd.h (quotient minimum degree algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2001-2013 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/>.
+***********************************************************************/
+
+#ifndef QMD_H
+#define QMD_H
+
+#define genqmd _glp_genqmd
+void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
+ int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
+ int qsize[], int qlink[], int *nofsub);
+/* GENeral Quotient Minimum Degree algorithm */
+
+#define qmdrch _glp_qmdrch
+void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
+ int marker[], int *rchsze, int rchset[], int *nhdsze,
+ int nbrhd[]);
+/* Quotient MD ReaCHable set */
+
+#define qmdqt _glp_qmdqt
+void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
+ int *rchsze, int rchset[], int nbrhd[]);
+/* Quotient MD Quotient graph Transformation */
+
+#define qmdupd _glp_qmdupd
+void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
+ int deg[], int qsize[], int qlink[], int marker[], int rchset[],
+ int nbrhd[]);
+/* Quotient MD UPDate */
+
+#define qmdmrg _glp_qmdmrg
+void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
+ int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
+ int rchset[], int ovrlp[]);
+/* Quotient MD MeRGe */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/relax4.c b/test/monniaux/glpk-4.65/src/misc/relax4.c
new file mode 100644
index 00000000..f0a47d6d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/relax4.c
@@ -0,0 +1,2850 @@
+/* relax4.c (relaxation method of Bertsekas and Tseng) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN CODE RELAX4.
+*
+* THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHOR OF
+* THE ORIGINAL FORTRAN CODE PROF. DIMITRI P. BERTSEKAS, MASSACHUSETTS
+* INSTITUTE OF TECHNOLOGY, CAMBRIDGE, MASSACHUSETTS, USA.
+*
+* The translation was made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "relax4.h"
+
+/***********************************************************************
+* WARNING
+*
+* A serious bug was *tentatively* fixed in this code (see #if/#endif
+* marked by 'mao').
+*
+* This bug is inherited from the original Fortran version of the
+* RELAX-IV code. Unfortunately, the code is very intricate, so this
+* bug is still under investigation. Thanks to Sylvain Fournier for bug
+* report.
+*
+* RELAX-IV bug details
+* --------------------
+* In the original RELAX-IV code there are four similar fragments in
+* subroutines ascnt1 and ascnt2 like this:
+*
+* C
+* C DECREASE THE PRICES OF THE SCANNED NODES BY DELPRC.
+* C ADJUST FLOW TO MAINTAIN COMPLEMENTARY SLACKNESS WITH
+* C THE PRICES.
+* C
+* NB = 0
+* DO 6 I=1,NSAVE
+* . . .
+* IF (RC(ARC).EQ.0) THEN
+* DELX=DELX+U(ARC)
+* NB = NB + 1
+* PRDCSR(NB) = ARC
+* END IF
+* . . .
+*
+* On some instances the variable NB becomes greater than N (the number
+* of nodes) that leads to indexing error, because the array PRDCSR is
+* declared as array of N elements (more precisely, as array of MAXNN
+* elements, however, NB becomes even much greater than MAXNN).
+***********************************************************************/
+
+#define false 0
+#define true 1
+
+/***********************************************************************
+* NAME
+*
+* RELAX-IV (version of October 1994)
+*
+* PURPOSE
+*
+* This routine implements the relaxation method of Bertsekas and Tseng
+* (see [1], [2]) for linear cost ordinary network flow problems.
+*
+* [1] Bertsekas, D. P., "A Unified Framework for Primal-Dual Methods"
+* Mathematical Programming, Vol. 32, 1985, pp. 125-145.
+* [2] Bertsekas, D. P., and Tseng, P., "Relaxation Methods for
+* Minimum Cost" Operations Research, Vol. 26, 1988, pp. 93-114.
+*
+* The relaxation method is also described in the books:
+*
+* [3] Bertsekas, D. P., "Linear Network Optimization: Algorithms and
+* Codes" MIT Press, 1991.
+* [4] Bertsekas, D. P. and Tsitsiklis, J. N., "Parallel and Distributed
+* Computation: Numerical Methods", Prentice-Hall, 1989.
+* [5] Bertsekas, D. P., "Network Optimization: Continuous and Discrete
+* Models", Athena Scientific, 1998.
+*
+* RELEASE NOTE
+*
+* This version of relaxation code has option for a special crash
+* procedure for the initial price-flow pair. This is recommended for
+* difficult problems where the default initialization results in long
+* running times. crash = 1 corresponds to an auction/shortest path
+* method
+*
+* These initializations are recommended in the absence of any prior
+* information on a favorable initial flow-price vector pair that
+* satisfies complementary slackness.
+*
+* The relaxation portion of the code differs from the code RELAXT-III
+* and other earlier relaxation codes in that it maintains the set of
+* nodes with nonzero deficit in a fifo queue. Like its predecessor
+* RELAXT-III, this code maintains a linked list of balanced (i.e., of
+* zero reduced cost) arcs so to reduce the work in labeling and
+* scanning. Unlike RELAXT-III, it does not use selectively shortest
+* path iterations for initialization.
+*
+* SOURCE
+*
+* The original Fortran code was written by Dimitri P. Bertsekas and
+* Paul Tseng, with a contribution by Jonathan Eckstein in the phase II
+* initialization. The original Fortran routine AUCTION was written by
+* Dimitri P. Bertsekas and is based on the method described in the
+* paper:
+*
+* [6] Bertsekas, D. P., "An Auction/Sequential Shortest Path Algorithm
+* for the Minimum Cost Flow Problem", LIDS Report P-2146, MIT,
+* Nov. 1992.
+*
+* For inquiries about the original Fortran code, please contact:
+*
+* Dimitri P. Bertsekas
+* Laboratory for information and decision systems
+* Massachusetts Institute of Technology
+* Cambridge, MA 02139
+* (617) 253-7267, dimitrib@mit.edu
+*
+* This code is the result of translation of the original Fortran code.
+* The translation was made by Andrew Makhorin <mao@gnu.org>.
+*
+* USER GUIDELINES
+*
+* This routine is in the public domain to be used only for research
+* purposes. It cannot be used as part of a commercial product, or to
+* satisfy in any part commercial delivery requirements to government
+* or industry, without prior agreement with the authors. Users are
+* requested to acknowledge the authorship of the code, and the
+* relaxation method.
+*
+* No modification should be made to this code other than the minimal
+* necessary to make it compatible with specific platforms.
+*
+* INPUT PARAMETERS (see notes 1, 2, 4)
+*
+* n = number of nodes
+* na = number of arcs
+* large = a very large integer to represent infinity
+* (see note 3)
+* repeat = true if initialization is to be skipped
+* (false otherwise)
+* crash = 0 if default initialization is used
+* 1 if auction initialization is used
+* startn[j] = starting node for arc j, j = 1,...,na
+* endn[j] = ending node for arc j, j = 1,...,na
+* fou[i] = first arc out of node i, i = 1,...,n
+* nxtou[j] = next arc out of the starting node of arc j, j = 1,...,na
+* fin[i] = first arc into node i, i = 1,...,n
+* nxtin[j] = next arc into the ending node of arc j, j = 1,...,na
+*
+* UPDATED PARAMETERS (see notes 1, 3, 4)
+*
+* rc[j] = reduced cost of arc j, j = 1,...,na
+* u[j] = capacity of arc j on input
+* and (capacity of arc j) - x[j] on output, j = 1,...,na
+* dfct[i] = demand at node i on input
+* and zero on output, i = 1,...,n
+*
+* OUTPUT PARAMETERS (see notes 1, 3, 4)
+*
+* x[j] = flow on arc j, j = 1,...,na
+* nmultinode = number of multinode relaxation iterations in RELAX4
+* iter = number of relaxation iterations in RELAX4
+* num_augm = number of flow augmentation steps in RELAX4
+* num_ascnt = number of multinode ascent steps in RELAX4
+* nsp = number of auction/shortest path iterations
+*
+* WORKING PARAMETERS (see notes 1, 4, 5)
+*
+* label[1+n], prdcsr[1+n], save[1+na], tfstou[1+n], tnxtou[1+na],
+* tfstin[1+n], tnxtin[1+na], nxtqueue[1+n], scan[1+n], mark[1+n],
+* extend_arc[1+n], sb_level[1+n], sb_arc[1+n]
+*
+* RETURNS
+*
+* 0 = normal return
+* 1,...,8 = problem is found to be infeasible
+*
+* NOTE 1
+*
+* To run in limited memory systems, declare the arrays startn, endn,
+* nxtin, nxtou, fin, fou, label, prdcsr, save, tfstou, tnxtou, tfstin,
+* tnxtin, ddpos, ddneg, nxtqueue as short instead.
+*
+* NOTE 2
+*
+* This routine makes no effort to initialize with a favorable x from
+* amongst those flow vectors that satisfy complementary slackness with
+* the initial reduced cost vector rc. If a favorable x is known, then
+* it can be passed, together with the corresponding arrays u and dfct,
+* to this routine directly. This, however, requires that the capacity
+* tightening portion and the flow initialization portion of this
+* routine (up to line labeled 90) be skipped.
+*
+* NOTE 3
+*
+* All problem data should be less than large in magnitude, and large
+* should be less than, say, 1/4 the largest int of the machine used.
+* This will guard primarily against overflow in uncapacitated problems
+* where the arc capacities are taken finite but very large. Note,
+* however, that as in all codes operating with integers, overflow may
+* occur if some of the problem data takes very large values.
+*
+* NOTE 4
+*
+* [This note being specific to Fortran was removed.-A.M.]
+*
+* NOTE 5
+*
+* ddpos and ddneg are arrays that give the directional derivatives for
+* all positive and negative single-node price changes. These are used
+* only in phase II of the initialization procedure, before the linked
+* list of balanced arcs comes to play. Therefore, to reduce storage,
+* they are equivalence to tfstou and tfstin, which are of the same size
+* (number of nodes) and are used only after the tree comes into use. */
+
+static void ascnt1(struct relax4_csa *csa, int dm, int *delx,
+ int *nlabel, int *feasbl, int *svitch, int nscan, int curnode,
+ int *prevnode);
+
+static void ascnt2(struct relax4_csa *csa, int dm, int *delx,
+ int *nlabel, int *feasbl, int *svitch, int nscan, int curnode,
+ int *prevnode);
+
+static int auction(struct relax4_csa *csa);
+
+int relax4(struct relax4_csa *csa)
+{ /* input parameters */
+ int n = csa->n;
+ int na = csa->na;
+ int large = csa->large;
+ int repeat = csa->repeat;
+ int crash = csa->crash;
+ int *startn = csa->startn;
+ int *endn = csa->endn;
+ int *fou = csa->fou;
+ int *nxtou = csa->nxtou;
+ int *fin = csa->fin;
+ int *nxtin = csa->nxtin;
+ /* updated parameters */
+ int *rc = csa->rc;
+ int *u = csa->u;
+ int *dfct = csa->dfct;
+ /* output parameters */
+ int *x = csa->x;
+# define nmultinode (csa->nmultinode)
+# define iter (csa->iter)
+# define num_augm (csa->num_augm)
+# define num_ascnt (csa->num_ascnt)
+# define nsp (csa->nsp)
+ /* working parameters */
+ int *label = csa->label;
+ int *prdcsr = csa->prdcsr;
+ int *save = csa->save;
+ int *tfstou = csa->tfstou;
+ int *tnxtou = csa->tnxtou;
+ int *tfstin = csa->tfstin;
+ int *tnxtin = csa->tnxtin;
+ int *nxtqueue = csa->nxtqueue;
+ char *scan = csa->scan;
+ char *mark = csa->mark;
+ int *ddpos = tfstou;
+ int *ddneg = tfstin;
+ /* local variables */
+ int arc, augnod, capin, capout, defcit, delprc, delx, dm, dp,
+ dx, feasbl, i, ib, indef, j, lastqueue, maxcap, narc, nb,
+ nlabel, node, node2, node_def, naugnod, nscan, num_passes,
+ numnz, numnz_new, numpasses, nxtarc, nxtbrk, nxtnode, passes,
+ pchange, posit, prevnode, prvarc, quit, rdcost, scapin,
+ scapou, svitch, t, t1, t2, tmparc, tp, trc, ts;
+ /*--------------------------------------------------------------*/
+ /* Initialization phase I */
+ /* In this phase, we reduce the arc capacities by as much as
+ * possible without changing the problem; then we set the initial
+ * flow array x, together with the corresponding arrays u and
+ * dfct. */
+ /* This phase and phase II (from here up to line labeled 90) can
+ * be skipped (by setting repeat to true) if the calling program
+ * places in common user-chosen values for the arc flows, the
+ * residual arc capacities, and the nodal deficits. When this is
+ * done, it is critical that the flow and the reduced cost for
+ * each arc satisfy complementary slackness and the dfct array
+ * properly correspond to the initial arc/flows. */
+ if (repeat)
+ goto L90;
+ for (node = 1; node <= n; node++)
+ { node_def = dfct[node];
+ ddpos[node] = node_def;
+ ddneg[node] = -node_def;
+ maxcap = 0;
+ scapou = 0;
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { if (scapou <= large - u[arc])
+ scapou += u[arc];
+ else
+ goto L10;
+ }
+ if (scapou <= large - node_def)
+ capout = scapou + node_def;
+ else
+ goto L10;
+ if (capout < 0)
+ { /* problem is infeasible */
+ /* exogenous flow into node exceeds out capacity */
+ return 1;
+ }
+ scapin = 0;
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { if (u[arc] > capout)
+ u[arc] = capout;
+ if (maxcap < u[arc])
+ maxcap = u[arc];
+ if (scapin <= large - u[arc])
+ scapin += u[arc];
+ else
+ goto L10;
+ }
+ if (scapin <= large + node_def)
+ capin = scapin - node_def;
+ else
+ goto L10;
+ if (capin < 0)
+ { /* problem is infeasible */
+ /* exogenous flow out of node exceeds in capacity */
+ return 2;
+ }
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { if (u[arc] > capin)
+ u[arc] = capin;
+ }
+L10: ;
+ }
+ /*--------------------------------------------------------------*/
+ /* Initialization phase II */
+ /* In this phase, we initialize the prices and flows by either
+ * calling the routine auction or by performing only single node
+ * (coordinate) relaxation iterations. */
+ if (crash == 1)
+ { nsp = 0;
+ if (auction(csa) != 0)
+ { /* problem is found to be infeasible */
+ return 3;
+ }
+ goto L70;
+ }
+ /* Initialize the arc flows to satisfy complementary slackness
+ * with the prices. u[arc] is the residual capacity of arc, and
+ * x[arc] is the flow. These two always add up to the total
+ * capacity for arc. Also compute the directional derivatives for
+ * each coordinate and compute the actual deficits. */
+ for (arc = 1; arc <= na; arc++)
+ { x[arc] = 0;
+ if (rc[arc] <= 0)
+ { t = u[arc];
+ t1 = startn[arc];
+ t2 = endn[arc];
+ ddpos[t1] += t;
+ ddneg[t2] += t;
+ if (rc[arc] < 0)
+ { x[arc] = t;
+ u[arc] = 0;
+ dfct[t1] += t;
+ dfct[t2] -= t;
+ ddneg[t1] -= t;
+ ddpos[t2] -= t;
+ }
+ }
+ }
+ /* Make 2 or 3 passes through all nodes, performing only single
+ * node relaxation iterations. The number of passes depends on the
+ * density of the network. */
+ if (na > n * 10)
+ numpasses = 2;
+ else
+ numpasses = 3;
+ for (passes = 1; passes <= numpasses; passes++)
+ for (node = 1; node <= n; node++)
+ { if (dfct[node] == 0)
+ continue;
+ if (ddpos[node] <= 0)
+ { /* Compute delprc, the stepsize to the next breakpoint in
+ * the dual cost as the price of node is increased.
+ * [Since the reduced cost of all outgoing (resp., incoming)
+ * arcs will decrease (resp., increase) as the price of node
+ * is increased, the next breakpoint is the minimum of the
+ * positive reduced cost on outgoing arcs and of the
+ * negative reduced cost on incoming arcs.] */
+ delprc = large;
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { trc = rc[arc];
+ if ((trc > 0) && (trc < delprc))
+ delprc = trc;
+ }
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { trc = rc[arc];
+ if ((trc < 0) && (trc > -delprc))
+ delprc = -trc;
+ }
+ /* If no breakpoint is left and dual ascent is still
+ * possible, the problem is infeasible. */
+ if (delprc >= large)
+ { if (ddpos[node] == 0)
+ continue;
+ return 4;
+ }
+ /* delprc is the stepsize to next breakpoint. Increase
+ * price of node by delprc and compute the stepsize to the
+ * next breakpoint in the dual cost. */
+L53: nxtbrk = large;
+ /* Look at all arcs out of node. */
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { trc = rc[arc];
+ if (trc == 0)
+ { t1 = endn[arc];
+ t = u[arc];
+ if (t > 0)
+ { dfct[node] += t;
+ dfct[t1] -= t;
+ x[arc] = t;
+ u[arc] = 0;
+ }
+ else
+ t = x[arc];
+ ddneg[node] -= t;
+ ddpos[t1] -= t;
+ }
+ /* Decrease the reduced costs on all outgoing arcs. */
+ trc -= delprc;
+ if ((trc > 0) && (trc < nxtbrk))
+ nxtbrk = trc;
+ else if (trc == 0)
+ { /* Arc goes from inactive to balanced. Update the rate
+ * of dual ascent at node and at its neighbor. */
+ ddpos[node] += u[arc];
+ ddneg[endn[arc]] += u[arc];
+ }
+ rc[arc] = trc;
+ }
+ /* Look at all arcs into node. */
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { trc = rc[arc];
+ if (trc == 0)
+ { t1 = startn[arc];
+ t = x[arc];
+ if (t > 0)
+ { dfct[node] += t;
+ dfct[t1] -= t;
+ u[arc] = t;
+ x[arc] = 0;
+ }
+ else
+ t = u[arc];
+ ddpos[t1] -= t;
+ ddneg[node] -= t;
+ }
+ /* Increase the reduced cost on all incoming arcs. */
+ trc += delprc;
+ if ((trc < 0) && (trc > -nxtbrk))
+ nxtbrk = -trc;
+ else if (trc == 0)
+ { /* Arc goes from active to balanced. Update the rate
+ * of dual ascent at node and at its neighbor. */
+ ddneg[startn[arc]] += x[arc];
+ ddpos[node] += x[arc];
+ }
+ rc[arc] = trc;
+ }
+ /* If price of node can be increased further without
+ * decreasing the dual cost (even the dual cost doesn't
+ * increase), return to increase the price further. */
+ if ((ddpos[node] <= 0) && (nxtbrk < large))
+ { delprc = nxtbrk;
+ goto L53;
+ }
+ }
+ else if (ddneg[node] <= 0)
+ { /* Compute delprc, the stepsize to the next breakpoint in
+ * the dual cost as the price of node is decreased.
+ * [Since the reduced cost of all outgoing (resp., incoming)
+ * arcs will increase (resp., decrease) as the price of node
+ * is decreased, the next breakpoint is the minimum of the
+ * negative reduced cost on outgoing arcs and of the
+ * positive reduced cost on incoming arcs.] */
+ delprc = large;
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { trc = rc[arc];
+ if ((trc < 0) && (trc > -delprc))
+ delprc = -trc;
+ }
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { trc = rc[arc];
+ if ((trc > 0) && (trc < delprc))
+ delprc = trc;
+ }
+ /* If no breakpoint is left and dual ascent is still
+ * possible, the problem is infeasible. */
+ if (delprc == large)
+ { if (ddneg[node] == 0)
+ continue;
+ return 5;
+ }
+ /* delprc is the stepsize to next breakpoint. Decrease
+ * price of node by delprc and compute the stepsize to the
+ * next breakpoint in the dual cost. */
+L63: nxtbrk = large;
+ /* Look at all arcs out of node. */
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { trc = rc[arc];
+ if (trc == 0)
+ { t1 = endn[arc];
+ t = x[arc];
+ if (t > 0)
+ { dfct[node] -= t;
+ dfct[t1] += t;
+ u[arc] = t;
+ x[arc] = 0;
+ }
+ else
+ t = u[arc];
+ ddpos[node] -= t;
+ ddneg[t1] -= t;
+ }
+ /* Increase the reduced cost on all outgoing arcs. */
+ trc += delprc;
+ if ((trc < 0) && (trc > -nxtbrk))
+ nxtbrk = -trc;
+ else if (trc == 0)
+ { /* Arc goes from active to balanced. Update the rate
+ * of dual ascent at node and at its neighbor. */
+ ddneg[node] += x[arc];
+ ddpos[endn[arc]] += x[arc];
+ }
+ rc[arc] = trc;
+ }
+ /* Look at all arcs into node. */
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { trc = rc[arc];
+ if (trc == 0)
+ { t1 = startn[arc];
+ t = u[arc];
+ if (t > 0)
+ { dfct[node] -= t;
+ dfct[t1] += t;
+ x[arc] = t;
+ u[arc] = 0;
+ }
+ else
+ t = x[arc];
+ ddneg[t1] -= t;
+ ddpos[node] -= t;
+ }
+ /* Decrease the reduced cost on all incoming arcs. */
+ trc -= delprc;
+ if ((trc > 0) && (trc < nxtbrk))
+ nxtbrk = trc;
+ else if (trc == 0)
+ { /* Arc goes from inactive to balanced. Update the rate
+ * of dual ascent at node and at its neighbor. */
+ ddpos[startn[arc]] += u[arc];
+ ddneg[node] += u[arc];
+ }
+ rc[arc] = trc;
+ }
+ /* If price of node can be decreased further without
+ * decreasing the dual cost (even the dual cost doesn't
+ * increase), return to decrease the price further. */
+ if ((ddneg[node] <= 0) && (nxtbrk < large))
+ { delprc = nxtbrk;
+ goto L63;
+ }
+ }
+ }
+ /*--------------------------------------------------------------*/
+L70: /* Initialize tree data structure. */
+ for (i = 1; i <= n; i++)
+ tfstou[i] = tfstin[i] = 0;
+ for (i = 1; i <= na; i++)
+ { tnxtin[i] = tnxtou[i] = -1;
+ if (rc[i] == 0)
+ { tnxtou[i] = tfstou[startn[i]];
+ tfstou[startn[i]] = i;
+ tnxtin[i] = tfstin[endn[i]];
+ tfstin[endn[i]] = i;
+ }
+ }
+L90: /* Initialize other variables. */
+ feasbl = true;
+ iter = 0;
+ nmultinode = 0;
+ num_augm = 0;
+ num_ascnt = 0;
+ num_passes = 0;
+ numnz = n;
+ numnz_new = 0;
+ svitch = false;
+ for (i = 1; i <= n; i++)
+ mark[i] = scan[i] = false;
+ nlabel = 0;
+ /* RELAX4 uses an adaptive strategy to decide whether to continue
+ * the scanning process after a multinode price change.
+ * The threshold parameter tp and ts that control this strategy
+ * are set in the next two lines. */
+ tp = 10;
+ ts = n / 15;
+ /* Initialize the queue of nodes with nonzero deficit. */
+ for (node = 1; node <= n - 1; node++)
+ nxtqueue[node] = node + 1;
+ nxtqueue[n] = 1;
+ node = lastqueue = n;
+ /*--------------------------------------------------------------*/
+ /* Start the relaxation algorithm. */
+L100: /* Code for advancing the queue of nonzero deficit nodes. */
+ prevnode = node;
+ node = nxtqueue[node];
+ defcit = dfct[node];
+ if (node == lastqueue)
+ { numnz = numnz_new;
+ numnz_new = 0;
+ lastqueue = prevnode;
+ num_passes++;
+ }
+ /* Code for deleting a node from the queue. */
+ if (defcit == 0)
+ { nxtnode = nxtqueue[node];
+ if (node == nxtnode)
+ return 0;
+ else
+ { nxtqueue[prevnode] = nxtnode;
+ nxtqueue[node] = 0;
+ node = nxtnode;
+ goto L100;
+ }
+ }
+ else
+ posit = (defcit > 0);
+ iter++;
+ numnz_new++;
+ if (posit)
+ { /* Attempt a single node iteration from node with positive
+ * deficit. */
+ pchange = false;
+ indef = defcit;
+ delx = 0;
+ nb = 0;
+ /* Check outgoing (probably) balanced arcs from node. */
+ for (arc = tfstou[node]; arc > 0; arc = tnxtou[arc])
+ { if ((rc[arc] == 0) && (x[arc] > 0))
+ { delx += x[arc];
+ nb++;
+ save[nb] = arc;
+ }
+ }
+ /* Check incoming arcs. */
+ for (arc = tfstin[node]; arc > 0; arc = tnxtin[arc])
+ { if ((rc[arc] == 0) && (u[arc] > 0))
+ { delx += u[arc];
+ nb++;
+ save[nb] = -arc;
+ }
+ }
+ /* End of initial node scan. */
+L4018: /* If no price change is possible, exit. */
+ if (delx > defcit)
+ { quit = (defcit < indef);
+ goto L4016;
+ }
+ /* RELAX4 searches along the ascent direction for the best
+ * price by checking the slope of the dual cost at successive
+ * break points. First, we compute the distance to the next
+ * break point. */
+ delprc = large;
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { rdcost = rc[arc];
+ if ((rdcost < 0) && (rdcost > -delprc))
+ delprc = -rdcost;
+ }
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { rdcost = rc[arc];
+ if ((rdcost > 0) && (rdcost < delprc))
+ delprc = rdcost;
+ }
+ /* Check if problem is infeasible. */
+ if ((delx < defcit) && (delprc == large))
+ { /* The dual cost can be decreased without bound. */
+ return 6;
+ }
+ /* Skip flow adjustment if there is no flow to modify. */
+ if (delx == 0)
+ goto L4014;
+ /* Adjust the flow on the balanced arcs incident to node to
+ * maintain complementary slackness after the price change. */
+ for (j = 1; j <= nb; j++)
+ { arc = save[j];
+ if (arc > 0)
+ { node2 = endn[arc];
+ t1 = x[arc];
+ dfct[node2] += t1;
+ if (nxtqueue[node2] == 0)
+ { nxtqueue[prevnode] = node2;
+ nxtqueue[node2] = node;
+ prevnode = node2;
+ }
+ u[arc] += t1;
+ x[arc] = 0;
+ }
+ else
+ { narc = -arc;
+ node2 = startn[narc];
+ t1 = u[narc];
+ dfct[node2] += t1;
+ if (nxtqueue[node2] == 0)
+ { nxtqueue[prevnode] = node2;
+ nxtqueue[node2] = node;
+ prevnode = node2;
+ }
+ x[narc] += t1;
+ u[narc] = 0;
+ }
+ }
+ defcit -= delx;
+L4014: if (delprc == large)
+ { quit = true;
+ goto L4019;
+ }
+ /* Node corresponds to a dual ascent direction. Decrease the
+ * price of node by delprc and compute the stepsize to the next
+ * breakpoint in the dual cost. */
+ nb = 0;
+ pchange = true;
+ dp = delprc;
+ delprc = large;
+ delx = 0;
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { rdcost = rc[arc] + dp;
+ rc[arc] = rdcost;
+ if (rdcost == 0)
+ { nb++;
+ save[nb] = arc;
+ delx += x[arc];
+ }
+ if ((rdcost < 0) && (rdcost > -delprc))
+ delprc = -rdcost;
+ }
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { rdcost = rc[arc] - dp;
+ rc[arc] = rdcost;
+ if (rdcost == 0)
+ { nb++;
+ save[nb] = -arc;
+ delx += u[arc];
+ }
+ if ((rdcost > 0) && (rdcost < delprc))
+ delprc = rdcost;
+ }
+ /* Return to check if another price change is possible. */
+ goto L4018;
+L4016: /* Perform flow augmentation at node. */
+ for (j = 1; j <= nb; j++)
+ { arc = save[j];
+ if (arc > 0)
+ { /* arc is an outgoing arc from node. */
+ node2 = endn[arc];
+ t1 = dfct[node2];
+ if (t1 < 0)
+ { /* Decrease the total deficit by decreasing flow of
+ * arc. */
+ quit = true;
+ t2 = x[arc];
+ dx = defcit;
+ if (dx > -t1) dx = -t1;
+ if (dx > t2) dx = t2;
+ defcit -= dx;
+ dfct[node2] = t1 + dx;
+ if (nxtqueue[node2] == 0)
+ { nxtqueue[prevnode] = node2;
+ nxtqueue[node2] = node;
+ prevnode = node2;
+ }
+ x[arc] = t2 - dx;
+ u[arc] += dx;
+ if (defcit == 0)
+ break;
+ }
+ }
+ else
+ { /* -arc is an incoming arc to node. */
+ narc = -arc;
+ node2 = startn[narc];
+ t1 = dfct[node2];
+ if (t1 < 0)
+ { /* Decrease the total deficit by increasing flow of
+ * -arc. */
+ quit = true;
+ t2 = u[narc];
+ dx = defcit;
+ if (dx > -t1) dx = -t1;
+ if (dx > t2) dx = t2;
+ defcit -= dx;
+ dfct[node2] = t1 + dx;
+ if (nxtqueue[node2] == 0)
+ { nxtqueue[prevnode] = node2;
+ nxtqueue[node2] = node;
+ prevnode = node2;
+ }
+ x[narc] += dx;
+ u[narc] = t2 - dx;
+ if (defcit == 0)
+ break;
+ }
+ }
+ }
+L4019: dfct[node] = defcit;
+ /* Reconstruct the linked list of balance arcs incident to this
+ * node. For each adjacent node, we add any newly balanced arcs
+ * to the list, but do not bother removing formerly balanced
+ * ones (they will be removed the next time each adjacent node
+ * is scanned). */
+ if (pchange)
+ { arc = tfstou[node];
+ tfstou[node] = 0;
+ while (arc > 0)
+ { nxtarc = tnxtou[arc];
+ tnxtou[arc] = -1;
+ arc = nxtarc;
+ }
+ arc = tfstin[node];
+ tfstin[node] = 0;
+ while (arc > 0)
+ { nxtarc = tnxtin[arc];
+ tnxtin[arc] = -1;
+ arc = nxtarc;
+ }
+ /* Now add the currently balanced arcs to the list for this
+ * node (which is now empty), and the appropriate adjacent
+ * ones. */
+ for (j = 1; j <= nb; j++)
+ { arc = save[j];
+ if (arc < 0)
+ arc = -arc;
+ if (tnxtou[arc] < 0)
+ { tnxtou[arc] = tfstou[startn[arc]];
+ tfstou[startn[arc]] = arc;
+ }
+ if (tnxtin[arc] < 0)
+ { tnxtin[arc] = tfstin[endn[arc]];
+ tfstin[endn[arc]] = arc;
+ }
+ }
+ }
+ /* End of single node iteration for positive deficit node. */
+ }
+ else
+ { /* Attempt a single node iteration from node with negative
+ * deficit. */
+ pchange = false;
+ defcit = -defcit;
+ indef = defcit;
+ delx = 0;
+ nb = 0;
+ for (arc = tfstin[node]; arc > 0; arc = tnxtin[arc])
+ { if ((rc[arc] == 0) && (x[arc] > 0))
+ { delx += x[arc];
+ nb++;
+ save[nb] = arc;
+ }
+ }
+ for (arc = tfstou[node]; arc > 0; arc = tnxtou[arc])
+ { if ((rc[arc] == 0) && (u[arc] > 0))
+ { delx += u[arc];
+ nb++;
+ save[nb] = -arc;
+ }
+ }
+L4028: if (delx >= defcit)
+ { quit = (defcit < indef);
+ goto L4026;
+ }
+ /* Compute distance to next breakpoint. */
+ delprc = large;
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { rdcost = rc[arc];
+ if ((rdcost < 0) && (rdcost > -delprc))
+ delprc = -rdcost;
+ }
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { rdcost = rc[arc];
+ if ((rdcost > 0) && (rdcost < delprc))
+ delprc = rdcost;
+ }
+ /* Check if problem is infeasible. */
+ if ((delx < defcit) && (delprc == large))
+ return 7;
+ if (delx == 0)
+ goto L4024;
+ /* Flow augmentation is possible. */
+ for (j = 1; j <= nb; j++)
+ { arc = save[j];
+ if (arc > 0)
+ { node2 = startn[arc];
+ t1 = x[arc];
+ dfct[node2] -= t1;
+ if (nxtqueue[node2] == 0)
+ { nxtqueue[prevnode] = node2;
+ nxtqueue[node2] = node;
+ prevnode = node2;
+ }
+ u[arc] += t1;
+ x[arc] = 0;
+ }
+ else
+ { narc = -arc;
+ node2 = endn[narc];
+ t1 = u[narc];
+ dfct[node2] -= t1;
+ if (nxtqueue[node2] == 0)
+ { nxtqueue[prevnode] = node2;
+ nxtqueue[node2] = node;
+ prevnode = node2;
+ }
+ x[narc] += t1;
+ u[narc] = 0;
+ }
+ }
+ defcit -= delx;
+L4024: if (delprc == large)
+ { quit = true;
+ goto L4029;
+ }
+ /* Price increase at node is possible. */
+ nb = 0;
+ pchange = true;
+ dp = delprc;
+ delprc = large;
+ delx = 0;
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { rdcost = rc[arc] + dp;
+ rc[arc] = rdcost;
+ if (rdcost == 0)
+ { nb++;
+ save[nb] = arc;
+ delx += x[arc];
+ }
+ if ((rdcost < 0) && (rdcost > -delprc))
+ delprc = -rdcost;
+ }
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { rdcost = rc[arc] - dp;
+ rc[arc] = rdcost;
+ if (rdcost == 0)
+ { nb++;
+ save[nb] = -arc;
+ delx += u[arc];
+ }
+ if ((rdcost > 0) && (rdcost < delprc))
+ delprc = rdcost;
+ }
+ goto L4028;
+L4026: /* Perform flow augmentation at node. */
+ for (j = 1; j <= nb; j++)
+ { arc = save[j];
+ if (arc > 0)
+ { /* arc is an incoming arc to node. */
+ node2 = startn[arc];
+ t1 = dfct[node2];
+ if (t1 > 0)
+ { quit = true;
+ t2 = x[arc];
+ dx = defcit;
+ if (dx > t1) dx = t1;
+ if (dx > t2) dx = t2;
+ defcit -= dx;
+ dfct[node2] = t1 - dx;
+ if (nxtqueue[node2] == 0)
+ { nxtqueue[prevnode] = node2;
+ nxtqueue[node2] = node;
+ prevnode = node2;
+ }
+ x[arc] = t2 - dx;
+ u[arc] += dx;
+ if (defcit == 0)
+ break;
+ }
+ }
+ else
+ { /* -arc is an outgoing arc from node. */
+ narc = -arc;
+ node2 = endn[narc];
+ t1 = dfct[node2];
+ if (t1 > 0)
+ { quit = true;
+ t2 = u[narc];
+ dx = defcit;
+ if (dx > t1) dx = t1;
+ if (dx > t2) dx = t2;
+ defcit -= dx;
+ dfct[node2] = t1 - dx;
+ if (nxtqueue[node2] == 0)
+ { nxtqueue[prevnode] = node2;
+ nxtqueue[node2] = node;
+ prevnode = node2;
+ }
+ x[narc] += dx;
+ u[narc] = t2 - dx;
+ if (defcit == 0)
+ break;
+ }
+ }
+ }
+L4029: dfct[node] = -defcit;
+ /* Reconstruct the list of balanced arcs incident to node. */
+ if (pchange)
+ { arc = tfstou[node];
+ tfstou[node] = 0;
+ while (arc > 0)
+ { nxtarc = tnxtou[arc];
+ tnxtou[arc] = -1;
+ arc = nxtarc;
+ }
+ arc = tfstin[node];
+ tfstin[node] = 0;
+ while (arc > 0)
+ { nxtarc = tnxtin[arc];
+ tnxtin[arc] = -1;
+ arc = nxtarc;
+ }
+ /* Now add the currently balanced arcs to the list for this
+ * node (which is now empty), and the appropriate adjacent
+ * ones. */
+ for (j = 1; j <= nb; j++)
+ { arc = save[j];
+ if (arc <= 0)
+ arc = -arc;
+ if (tnxtou[arc] < 0)
+ { tnxtou[arc] = tfstou[startn[arc]];
+ tfstou[startn[arc]] = arc;
+ }
+ if (tnxtin[arc] < 0)
+ { tnxtin[arc] = tfstin[endn[arc]];
+ tfstin[endn[arc]] = arc;
+ }
+ }
+ }
+ /* End of single node iteration for a negative deficit node. */
+ }
+ if (quit || (num_passes <= 3))
+ goto L100;
+ /* Do a multinode iteration from node. */
+ nmultinode++;
+ /* If number of nonzero deficit nodes is small, continue labeling
+ * until a flow augmentation is done. */
+ svitch = (numnz < tp);
+ /* Unmark nodes labeled earlier. */
+ for (j = 1; j <= nlabel; j++)
+ { node2 = label[j];
+ mark[node2] = scan[node2] = false;
+ }
+ /* Initialize labeling. */
+ nlabel = 1;
+ label[1] = node;
+ mark[node] = true;
+ prdcsr[node] = 0;
+ /* Scan starting node. */
+ scan[node] = true;
+ nscan = 1;
+ dm = dfct[node];
+ delx = 0;
+ for (j = 1; j <= nb; j++)
+ { arc = save[j];
+ if (arc > 0)
+ { if (posit)
+ node2 = endn[arc];
+ else
+ node2 = startn[arc];
+ if (!mark[node2])
+ { nlabel++;
+ label[nlabel] = node2;
+ prdcsr[node2] = arc;
+ mark[node2] = true;
+ delx += x[arc];
+ }
+ }
+ else
+ { narc = -arc;
+ if (posit)
+ node2 = startn[narc];
+ else
+ node2 = endn[narc];
+ if (!mark[node2])
+ { nlabel++;
+ label[nlabel] = node2;
+ prdcsr[node2] = arc;
+ mark[node2] = true;
+ delx += u[narc];
+ }
+ }
+ }
+L4120:/* Start scanning a labeled but unscanned node. */
+ nscan++;
+ /* Check to see if switch needs to be set to true so to continue
+ * scanning even after a price change. */
+ svitch = svitch || ((nscan > ts) && (numnz < ts));
+ /* Scanning will continue until either an overestimate of the
+ * residual capacity across the cut corresponding to the scanned
+ * set of nodes (called delx) exceeds the absolute value of the
+ * total deficit of the scanned nodes (called dm), or else an
+ * augmenting path is found. Arcs that are in the tree but are not
+ * balanced are removed as part of the scanning process. */
+ i = label[nscan];
+ scan[i] = true;
+ naugnod = 0;
+ if (posit)
+ { /* Scanning node i in case of positive deficit. */
+ prvarc = 0;
+ arc = tfstou[i];
+ while (arc > 0)
+ { /* arc is an outgoing arc from node. */
+ if (rc[arc] == 0)
+ { if (x[arc] > 0)
+ { node2 = endn[arc];
+ if (!mark[node2])
+ { /* node2 is not labeled, so add node2 to the
+ labeled set. */
+ prdcsr[node2] = arc;
+ if (dfct[node2] < 0)
+ { naugnod++;
+ save[naugnod] = node2;
+ }
+ nlabel++;
+ label[nlabel] = node2;
+ mark[node2] = true;
+ delx += x[arc];
+ }
+ }
+ prvarc = arc;
+ arc = tnxtou[arc];
+ }
+ else
+ { tmparc = arc;
+ arc = tnxtou[arc];
+ tnxtou[tmparc] = -1;
+ if (prvarc == 0)
+ tfstou[i] = arc;
+ else
+ tnxtou[prvarc] = arc;
+ }
+ }
+ prvarc = 0;
+ arc = tfstin[i];
+ while (arc > 0)
+ { /* arc is an incoming arc into node. */
+ if (rc[arc] == 0)
+ { if (u[arc] > 0)
+ { node2 = startn[arc];
+ if (!mark[node2])
+ { /* node2 is not labeled, so add node2 to the
+ * labeled set. */
+ prdcsr[node2] = -arc;
+ if (dfct[node2] < 0)
+ { naugnod++;
+ save[naugnod] = node2;
+ }
+ nlabel++;
+ label[nlabel] = node2;
+ mark[node2] = true;
+ delx += u[arc];
+ }
+ }
+ prvarc = arc;
+ arc = tnxtin[arc];
+ }
+ else
+ { tmparc = arc;
+ arc = tnxtin[arc];
+ tnxtin[tmparc] = -1;
+ if (prvarc == 0)
+ tfstin[i] = arc;
+ else
+ tnxtin[prvarc] = arc;
+ }
+ }
+ /* Correct the residual capacity of the scanned node cut. */
+ arc = prdcsr[i];
+ if (arc > 0)
+ delx -= x[arc];
+ else
+ delx -= u[-arc];
+ /* End of scanning of node i for positive deficit case. */
+ }
+ else
+ { /* Scanning node i for negative deficit case. */
+ prvarc = 0;
+ arc = tfstin[i];
+ while (arc > 0)
+ { if (rc[arc] == 0)
+ { if (x[arc] > 0)
+ { node2 = startn[arc];
+ if (!mark[node2])
+ { prdcsr[node2] = arc;
+ if (dfct[node2] > 0)
+ { naugnod++;
+ save[naugnod] = node2;
+ }
+ nlabel++;
+ label[nlabel] = node2;
+ mark[node2] = true;
+ delx += x[arc];
+ }
+ }
+ prvarc = arc;
+ arc = tnxtin[arc];
+ }
+ else
+ { tmparc = arc;
+ arc = tnxtin[arc];
+ tnxtin[tmparc] = -1;
+ if (prvarc == 0)
+ tfstin[i] = arc;
+ else
+ tnxtin[prvarc] = arc;
+ }
+ }
+ prvarc = 0;
+ arc = tfstou[i];
+ while (arc > 0)
+ { if (rc[arc] == 0)
+ { if (u[arc] > 0)
+ { node2 = endn[arc];
+ if (!mark[node2])
+ { prdcsr[node2] = -arc;
+ if (dfct[node2] > 0)
+ { naugnod++;
+ save[naugnod] = node2;
+ }
+ nlabel++;
+ label[nlabel] = node2;
+ mark[node2] = true;
+ delx += u[arc];
+ }
+ }
+ prvarc = arc;
+ arc = tnxtou[arc];
+ }
+ else
+ { tmparc = arc;
+ arc = tnxtou[arc];
+ tnxtou[tmparc] = -1;
+ if (prvarc == 0)
+ tfstou[i] = arc;
+ else
+ tnxtou[prvarc] = arc;
+ }
+ }
+ arc = prdcsr[i];
+ if (arc > 0)
+ delx -= x[arc];
+ else
+ delx -= u[-arc];
+ }
+ /* Add deficit of node scanned to dm. */
+ dm += dfct[i];
+ /* Check if the set of scanned nodes correspond to a dual ascent
+ * direction; if yes, perform a price adjustment step, otherwise
+ * continue labeling. */
+ if (nscan < nlabel)
+ { if (svitch)
+ goto L4210;
+ if ((delx >= dm) && (delx >= -dm))
+ goto L4210;
+ }
+ /* Try a price change.
+ * [Note that since delx - abs(dm) is an overestimate of ascent
+ * slope, we may occasionally try a direction that is not an
+ * ascent direction. In this case the ascnt routines return with
+ * quit = false, so we continue labeling nodes.] */
+ if (posit)
+ { ascnt1(csa, dm, &delx, &nlabel, &feasbl, &svitch, nscan, node,
+ &prevnode);
+ num_ascnt++;
+ }
+ else
+ { ascnt2(csa, dm, &delx, &nlabel, &feasbl, &svitch, nscan, node,
+ &prevnode);
+ num_ascnt++;
+ }
+ if (!feasbl)
+ return 8;
+ if (!svitch)
+ goto L100;
+ /* Store those newly labeled nodes to which flow augmentation is
+ * possible. */
+ naugnod = 0;
+ for (j = nscan + 1; j <= nlabel; j++)
+ { node2 = label[j];
+ if (posit && (dfct[node2] < 0))
+ { naugnod++;
+ save[naugnod] = node2;
+ }
+ else if ((!posit) && (dfct[node2] > 0))
+ { naugnod++;
+ save[naugnod] = node2;
+ }
+ }
+L4210:/* Check if flow augmentation is possible. If not, return to scan
+ * another node. */
+ if (naugnod == 0)
+ goto L4120;
+ for (j = 1; j <= naugnod; j++)
+ { num_augm++;
+ augnod = save[j];
+ if (posit)
+ { /* Do the augmentation from node with positive deficit. */
+ dx = -dfct[augnod];
+ ib = augnod;
+ while (ib != node)
+ { arc = prdcsr[ib];
+ if (arc > 0)
+ { if (dx > x[arc]) dx = x[arc];
+ ib = startn[arc];
+ }
+ else
+ { if (dx > u[-arc]) dx = u[-arc];
+ ib = endn[-arc];
+ }
+ }
+ if (dx > dfct[node]) dx = dfct[node];
+ if (dx > 0)
+ { /* Increase (decrease) the flow of all forward (backward)
+ * arcs in the flow augmenting path. Adjust node deficit
+ * accordingly. */
+ if (nxtqueue[augnod] == 0)
+ { nxtqueue[prevnode] = augnod;
+ nxtqueue[augnod] = node;
+ prevnode = augnod;
+ }
+ dfct[augnod] += dx;
+ dfct[node] -= dx;
+ ib = augnod;
+ while (ib != node)
+ { arc = prdcsr[ib];
+ if (arc > 0)
+ { x[arc] -= dx;
+ u[arc] += dx;
+ ib = startn[arc];
+ }
+ else
+ { narc = -arc;
+ x[narc] += dx;
+ u[narc] -= dx;
+ ib = endn[narc];
+ }
+ }
+ }
+ }
+ else
+ { /* Do the augmentation from node with negative deficit. */
+ dx = dfct[augnod];
+ ib = augnod;
+ while (ib != node)
+ { arc = prdcsr[ib];
+ if (arc > 0)
+ { if (dx > x[arc]) dx = x[arc];
+ ib = endn[arc];
+ }
+ else
+ { if (dx > u[-arc]) dx = u[-arc];
+ ib = startn[-arc];
+ }
+ }
+ if (dx > -dfct[node]) dx = -dfct[node];
+ if (dx > 0)
+ { /* Update the flow and deficits. */
+ if (nxtqueue[augnod] == 0)
+ { nxtqueue[prevnode] = augnod;
+ nxtqueue[augnod] = node;
+ prevnode = augnod;
+ }
+ dfct[augnod] -= dx;
+ dfct[node] += dx;
+ ib = augnod;
+ while (ib != node)
+ { arc = prdcsr[ib];
+ if (arc > 0)
+ { x[arc] -= dx;
+ u[arc] += dx;
+ ib = endn[arc];
+ }
+ else
+ { narc = -arc;
+ x[narc] += dx;
+ u[narc] -= dx;
+ ib = startn[narc];
+ }
+ }
+ }
+ }
+ if (dfct[node] == 0)
+ goto L100;
+ if (dfct[augnod] != 0)
+ svitch = false;
+ }
+ /* If node still has nonzero deficit and all newly labeled nodes
+ * have same sign for their deficit as node, we can continue
+ * labeling. In this case, continue labeling only when flow
+ * augmentation is done relatively infrequently. */
+ if (svitch && (iter > 8 * num_augm))
+ goto L4120;
+ /* Return to do another relaxation iteration. */
+ goto L100;
+# undef nmultinode
+# undef iter
+# undef num_augm
+# undef num_ascnt
+# undef nsp
+}
+
+/***********************************************************************
+* NAME
+*
+* relax4_inidat - construct linked lists for network topology
+*
+* PURPOSE
+*
+* This routine constructs two linked lists for the network topology:
+* one list (given by fou, nxtou) for the outgoing arcs of nodes and
+* one list (given by fin, nxtin) for the incoming arcs of nodes. These
+* two lists are required by RELAX4.
+*
+* INPUT PARAMETERS
+*
+* n = number of nodes
+* na = number of arcs
+* startn[j] = starting node for arc j, j = 1,...,na
+* endn[j] = ending node for arc j, j = 1,...,na
+*
+* OUTPUT PARAMETERS
+*
+* fou[i] = first arc out of node i, i = 1,...,n
+* nxtou[j] = next arc out of the starting node of arc j, j = 1,...,na
+* fin[i] = first arc into node i, i = 1,...,n
+* nxtin[j] = next arc into the ending node of arc j, j = 1,...,na
+*
+* WORKING PARAMETERS
+*
+* tempin[1+n], tempou[1+n] */
+
+void relax4_inidat(struct relax4_csa *csa)
+{ /* input parameters */
+ int n = csa->n;
+ int na = csa->na;
+ int *startn = csa->startn;
+ int *endn = csa->endn;
+ /* output parameters */
+ int *fou = csa->fou;
+ int *nxtou = csa->nxtou;
+ int *fin = csa->fin;
+ int *nxtin = csa->nxtin;
+ /* working parameters */
+ int *tempin = csa->label;
+ int *tempou = csa->prdcsr;
+ /* local variables */
+ int i, i1, i2;
+ for (i = 1; i <= n; i++)
+ { fin[i] = fou[i] = 0;
+ tempin[i] = tempou[i] = 0;
+ }
+ for (i = 1; i <= na; i++)
+ { nxtin[i] = nxtou[i] = 0;
+ i1 = startn[i];
+ i2 = endn[i];
+ if (fou[i1] != 0)
+ nxtou[tempou[i1]] = i;
+ else
+ fou[i1] = i;
+ tempou[i1] = i;
+ if (fin[i2] != 0)
+ nxtin[tempin[i2]] = i;
+ else
+ fin[i2] = i;
+ tempin[i2] = i;
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* ascnt1 - multi-node price adjustment for positive deficit case
+*
+* PURPOSE
+*
+* This subroutine performs the multi-node price adjustment step for
+* the case where the scanned nodes have positive deficit. It first
+* checks if decreasing the price of the scanned nodes increases the
+* dual cost. If yes, then it decreases the price of all scanned nodes.
+* There are two possibilities for price decrease: if switch = true,
+* then the set of scanned nodes corresponds to an elementary direction
+* of maximal rate of ascent, in which case the price of all scanned
+* nodes are decreased until the next breakpoint in the dual cost is
+* encountered. At this point, some arc becomes balanced and more
+* node(s) are added to the labeled set and the subroutine is exited.
+* If switch = false, then the price of all scanned nodes are decreased
+* until the rate of ascent becomes negative (this corresponds to the
+* price adjustment step in which both the line search and the
+* degenerate ascent iteration are implemented).
+*
+* INPUT PARAMETERS
+*
+* dm = total deficit of scanned nodes
+* switch = true if labeling is to continue after price change
+* nscan = number of scanned nodes
+* curnode = most recently scanned node
+* n = number of nodes
+* na = number of arcs
+* large = a very large integer to represent infinity (see note 3)
+* startn[i] = starting node for the i-th arc, i = 1,...,na
+* endn[i] = ending node for the i-th arc, i = 1,...,na
+* fou[i] = first arc leaving i-th node, i = 1,...,n
+* nxtou[i] = next arc leaving the starting node of j-th arc,
+* i = 1,...,na
+* fin[i] = first arc entering i-th node, i = 1,...,n
+* nxtin[i] = next arc entering the ending node of j-th arc,
+* i = 1,...,na
+*
+* UPDATED PARAMETERS
+*
+* delx = a lower estimate of the total flow on balanced arcs in
+* the scanned-nodes cut
+* nlabel = number of labeled nodes
+* feasbl = false if problem is found to be infeasible
+* prevnode = the node before curnode in queue
+* rc[j] = reduced cost of arc j, j = 1,...,na
+* u[j] = residual capacity of arc j, j = 1,...,na
+* x[j] = flow on arc j, j = 1,...,na
+* dfct[i] = deficit at node i, i = 1,...,n
+* label[k] = k-th node labeled, k = 1,...,nlabel
+* prdcsr[i] = predecessor of node i in tree of labeled nodes (0 if i
+* is unlabeled), i = 1,...,n
+* tfstou[i] = first balanced arc out of node i, i = 1,...,n
+* tnxtou[j] = next balanced arc out of the starting node of arc j,
+* j = 1,...,na
+* tfstin[i] = first balanced arc into node i, i = 1,...,n
+* tnxtin[j] = next balanced arc into the ending node of arc j,
+* j = 1,...,na
+* nxtqueue[i] = node following node i in the fifo queue (0 if node is
+* not in the queue), i = 1,...,n
+* scan[i] = true if node i is scanned, i = 1,...,n
+* mark[i] = true if node i is labeled, i = 1,...,n
+*
+* WORKING PARAMETERS
+*
+* save[1+na] */
+
+static void ascnt1(struct relax4_csa *csa, int dm, int *delx,
+ int *nlabel, int *feasbl, int *svitch, int nscan, int curnode,
+ int *prevnode)
+{ /* input parameters */
+ int n = csa->n;
+ /* int na = csa->na; */
+ int large = csa->large;
+ int *startn = csa->startn;
+ int *endn = csa->endn;
+ int *fou = csa->fou;
+ int *nxtou = csa->nxtou;
+ int *fin = csa->fin;
+ int *nxtin = csa->nxtin;
+ /* updated parameters */
+# define delx (*delx)
+# define nlabel (*nlabel)
+# define feasbl (*feasbl)
+# define svitch (*svitch)
+# define prevnode (*prevnode)
+ int *rc = csa->rc;
+ int *u = csa->u;
+ int *x = csa->x;
+ int *dfct = csa->dfct;
+ int *label = csa->label;
+ int *prdcsr = csa->prdcsr;
+ int *tfstou = csa->tfstou;
+ int *tnxtou = csa->tnxtou;
+ int *tfstin = csa->tfstin;
+ int *tnxtin = csa->tnxtin;
+ int *nxtqueue = csa->nxtqueue;
+ char *scan = csa->scan;
+ char *mark = csa->mark;
+ int *save = csa->save;
+ /* local variables */
+ int arc, delprc, dlx, i, j, nb, node, node2, nsave, rdcost, t1,
+ t2, t3;
+ /* Store the arcs between the set of scanned nodes and its
+ * complement in save and compute delprc, the stepsize to the next
+ * breakpoint in the dual cost in the direction of decreasing
+ * prices of the scanned nodes.
+ * [The arcs are stored into save by looking at the arcs incident
+ * to either the set of scanned nodes or its complement, depending
+ * on whether nscan > n/2 or not. This improves the efficiency of
+ * storing.] */
+ delprc = large;
+ dlx = 0;
+ nsave = 0;
+ if (nscan <= n / 2)
+ { for (i = 1; i <= nscan; i++)
+ { node = label[i];
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { /* arc points from scanned node to an unscanned node. */
+ node2 = endn[arc];
+ if (!scan[node2])
+ { nsave++;
+ save[nsave] = arc;
+ rdcost = rc[arc];
+ if ((rdcost == 0) && (prdcsr[node2] != arc))
+ dlx += x[arc];
+ if ((rdcost < 0) && (rdcost > -delprc))
+ delprc = -rdcost;
+ }
+ }
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { /* arc points from unscanned node to scanned node. */
+ node2 = startn[arc];
+ if (!scan[node2])
+ { nsave++;
+ save[nsave] = -arc;
+ rdcost = rc[arc];
+ if ((rdcost == 0) && (prdcsr[node2] != -arc))
+ dlx += u[arc];
+ if ((rdcost > 0) && (rdcost < delprc))
+ delprc = rdcost;
+ }
+ }
+ }
+ }
+ else
+ { for (node = 1; node <= n; node++)
+ { if (scan[node])
+ continue;
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { node2 = startn[arc];
+ if (scan[node2])
+ { nsave++;
+ save[nsave] = arc;
+ rdcost = rc[arc];
+ if ((rdcost == 0) && (prdcsr[node] != arc))
+ dlx += x[arc];
+ if ((rdcost < 0) && (rdcost > -delprc))
+ delprc = -rdcost;
+ }
+ }
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { node2 = endn[arc];
+ if (scan[node2])
+ { nsave++;
+ save[nsave] = -arc;
+ rdcost = rc[arc];
+ if ((rdcost == 0) && (prdcsr[node] != -arc))
+ dlx += u[arc];
+ if ((rdcost > 0) && (rdcost < delprc))
+ delprc = rdcost;
+ }
+ }
+ }
+ }
+ /* Check if the set of scanned nodes truly corresponds to a dual
+ * ascent direction. [Here delx + dlx is the exact sum of the flow
+ * on arcs from the scanned set to the unscanned set plus the
+ * (capacity - flow) on arcs from the unscanned set to the scanned
+ * set.] If this were not the case, set switch to true and exit
+ * subroutine. */
+ if ((!svitch) && (delx + dlx >= dm))
+ { svitch = true;
+ return;
+ }
+ delx += dlx;
+L4: /* Check that the problem is feasible. */
+ if (delprc == large)
+ { /* We can increase the dual cost without bound, so the primal
+ * problem is infeasible. */
+ feasbl = false;
+ return;
+ }
+ /* Decrease the prices of the scanned nodes, add more nodes to
+ * the labeled set and check if a newly labeled node has negative
+ * deficit. */
+ if (svitch)
+ { for (i = 1; i <= nsave; i++)
+ { arc = save[i];
+ if (arc > 0)
+ { rc[arc] += delprc;
+ if (rc[arc] == 0)
+ { node2 = endn[arc];
+ if (tnxtou[arc] < 0)
+ { tnxtou[arc] = tfstou[startn[arc]];
+ tfstou[startn[arc]] = arc;
+ }
+ if (tnxtin[arc] < 0)
+ { tnxtin[arc] = tfstin[node2];
+ tfstin[node2] = arc;
+ }
+ if (!mark[node2])
+ { prdcsr[node2] = arc;
+ nlabel++;
+ label[nlabel] = node2;
+ mark[node2] = true;
+ }
+ }
+ }
+ else
+ { arc = -arc;
+ rc[arc] -= delprc;
+ if (rc[arc] == 0)
+ { node2 = startn[arc];
+ if (tnxtou[arc] < 0)
+ { tnxtou[arc] = tfstou[node2];
+ tfstou[node2] = arc;
+ }
+ if (tnxtin[arc] < 0)
+ { tnxtin[arc] = tfstin[endn[arc]];
+ tfstin[endn[arc]] = arc;
+ }
+ if (!mark[node2])
+ { prdcsr[node2] = -arc;
+ nlabel++;
+ label[nlabel] = node2;
+ mark[node2] = true;
+ }
+ }
+ }
+ }
+ return;
+ }
+ else
+ { /* Decrease the prices of the scanned nodes by delprc. Adjust
+ * flow to maintain complementary slackness with the prices. */
+ nb = 0;
+ for (i = 1; i <= nsave; i++)
+ { arc = save[i];
+ if (arc > 0)
+ { t1 = rc[arc];
+ if (t1 == 0)
+ { t2 = x[arc];
+ t3 = startn[arc];
+ dfct[t3] -= t2;
+ if (nxtqueue[t3] == 0)
+ { nxtqueue[prevnode] = t3;
+ nxtqueue[t3] = curnode;
+ prevnode = t3;
+ }
+ t3 = endn[arc];
+ dfct[t3] += t2;
+ if (nxtqueue[t3] == 0)
+ { nxtqueue[prevnode] = t3;
+ nxtqueue[t3] = curnode;
+ prevnode = t3;
+ }
+ u[arc] += t2;
+ x[arc] = 0;
+ }
+ rc[arc] = t1 + delprc;
+#if 0 /* by mao; 26/IV-2013 */
+ if (rc[arc] == 0)
+#else
+ if (rc[arc] == 0 && nb < n)
+#endif
+ { delx += x[arc];
+ nb++;
+ prdcsr[nb] = arc;
+ }
+ }
+ else
+ { arc = -arc;
+ t1 = rc[arc];
+ if (t1 == 0)
+ { t2 = u[arc];
+ t3 = startn[arc];
+ dfct[t3] += t2;
+ if (nxtqueue[t3] == 0)
+ { nxtqueue[prevnode] = t3;
+ nxtqueue[t3] = curnode;
+ prevnode = t3;
+ }
+ t3 = endn[arc];
+ dfct[t3] -= t2;
+ if (nxtqueue[t3] == 0)
+ { nxtqueue[prevnode] = t3;
+ nxtqueue[t3] = curnode;
+ prevnode = t3;
+ }
+ x[arc] += t2;
+ u[arc] = 0;
+ }
+ rc[arc] = t1 - delprc;
+#if 0 /* by mao; 26/IV-2013 */
+ if (rc[arc] == 0)
+#else
+ if (rc[arc] == 0 && nb < n)
+#endif
+ { delx += u[arc];
+ nb++;
+ prdcsr[nb] = arc;
+ }
+ }
+ }
+ }
+ if (delx <= dm)
+ { /* The set of scanned nodes still corresponds to a dual
+ * (possibly degenerate) ascent direction. Compute the stepsize
+ * delprc to the next breakpoint in the dual cost. */
+ delprc = large;
+ for (i = 1; i <= nsave; i++)
+ { arc = save[i];
+ if (arc > 0)
+ { rdcost = rc[arc];
+ if ((rdcost < 0) && (rdcost > -delprc))
+ delprc = -rdcost;
+ }
+ else
+ { arc = -arc;
+ rdcost = rc[arc];
+ if ((rdcost > 0) && (rdcost < delprc))
+ delprc = rdcost;
+ }
+ }
+ if ((delprc != large) || (delx < dm))
+ goto L4;
+ }
+ /* Add new balanced arcs to the superset of balanced arcs. */
+ for (i = 1; i <= nb; i++)
+ { arc = prdcsr[i];
+ if (tnxtin[arc] == -1)
+ { j = endn[arc];
+ tnxtin[arc] = tfstin[j];
+ tfstin[j] = arc;
+ }
+ if (tnxtou[arc] == -1)
+ { j = startn[arc];
+ tnxtou[arc] = tfstou[j];
+ tfstou[j] = arc;
+ }
+ }
+ return;
+# undef delx
+# undef nlabel
+# undef feasbl
+# undef svitch
+# undef prevnode
+}
+
+/***********************************************************************
+* NAME
+*
+* ascnt2 - multi-node price adjustment for negative deficit case
+*
+* PURPOSE
+*
+* This routine is analogous to ascnt1 but for the case where the
+* scanned nodes have negative deficit. */
+
+static void ascnt2(struct relax4_csa *csa, int dm, int *delx,
+ int *nlabel, int *feasbl, int *svitch, int nscan, int curnode,
+ int *prevnode)
+{ /* input parameters */
+ int n = csa->n;
+ /* int na = csa->na; */
+ int large = csa->large;
+ int *startn = csa->startn;
+ int *endn = csa->endn;
+ int *fou = csa->fou;
+ int *nxtou = csa->nxtou;
+ int *fin = csa->fin;
+ int *nxtin = csa->nxtin;
+ /* updated parameters */
+# define delx (*delx)
+# define nlabel (*nlabel)
+# define feasbl (*feasbl)
+# define svitch (*svitch)
+# define prevnode (*prevnode)
+ int *rc = csa->rc;
+ int *u = csa->u;
+ int *x = csa->x;
+ int *dfct = csa->dfct;
+ int *label = csa->label;
+ int *prdcsr = csa->prdcsr;
+ int *tfstou = csa->tfstou;
+ int *tnxtou = csa->tnxtou;
+ int *tfstin = csa->tfstin;
+ int *tnxtin = csa->tnxtin;
+ int *nxtqueue = csa->nxtqueue;
+ char *scan = csa->scan;
+ char *mark = csa->mark;
+ int *save = csa->save;
+ /* local variables */
+ int arc, delprc, dlx, i, j, nb, node, node2, nsave, rdcost, t1,
+ t2, t3;
+ /* Store the arcs between the set of scanned nodes and its
+ * complement in save and compute delprc, the stepsize to the next
+ * breakpoint in the dual cost in the direction of increasing
+ * prices of the scanned nodes. */
+ delprc = large;
+ dlx = 0;
+ nsave = 0;
+ if (nscan <= n / 2)
+ { for (i = 1; i <= nscan; i++)
+ { node = label[i];
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { node2 = startn[arc];
+ if (!scan[node2])
+ { nsave++;
+ save[nsave] = arc;
+ rdcost = rc[arc];
+ if ((rdcost == 0) && (prdcsr[node2] != arc))
+ dlx += x[arc];
+ if ((rdcost < 0) && (rdcost > -delprc))
+ delprc = -rdcost;
+ }
+ }
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { node2 = endn[arc];
+ if (!scan[node2])
+ { nsave++;
+ save[nsave] = -arc;
+ rdcost = rc[arc];
+ if ((rdcost == 0) && (prdcsr[node2] != -arc))
+ dlx += u[arc];
+ if ((rdcost > 0) && (rdcost < delprc))
+ delprc = rdcost;
+ }
+ }
+ }
+ }
+ else
+ { for (node = 1; node <= n; node++)
+ { if (scan[node])
+ continue;
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { node2 = endn[arc];
+ if (scan[node2])
+ { nsave++;
+ save[nsave] = arc;
+ rdcost = rc[arc];
+ if ((rdcost == 0) && (prdcsr[node] != arc))
+ dlx += x[arc];
+ if ((rdcost < 0) && (rdcost > -delprc))
+ delprc = -rdcost;
+ }
+ }
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { node2 = startn[arc];
+ if (scan[node2])
+ { nsave++;
+ save[nsave] = -arc;
+ rdcost = rc[arc];
+ if ((rdcost == 0) && (prdcsr[node] != -arc))
+ dlx += u[arc];
+ if ((rdcost > 0) && (rdcost < delprc))
+ delprc = rdcost;
+ }
+ }
+ }
+ }
+ if ((!svitch) && (delx + dlx >= -dm))
+ { svitch = true;
+ return;
+ }
+ delx += dlx;
+ /* Check that the problem is feasible. */
+L4: if (delprc == large)
+ { feasbl = false;
+ return;
+ }
+ /* Increase the prices of the scanned nodes, add more nodes to
+ * the labeled set and check if a newly labeled node has positive
+ * deficit. */
+ if (svitch)
+ { for (i = 1; i <= nsave; i++)
+ { arc = save[i];
+ if (arc > 0)
+ { rc[arc] += delprc;
+ if (rc[arc] == 0)
+ { node2 = startn[arc];
+ if (tnxtou[arc] < 0)
+ { tnxtou[arc] = tfstou[node2];
+ tfstou[node2] = arc;
+ }
+ if (tnxtin[arc] < 0)
+ { tnxtin[arc] = tfstin[endn[arc]];
+ tfstin[endn[arc]] = arc;
+ }
+ if (!mark[node2])
+ { prdcsr[node2] = arc;
+ nlabel++;
+ label[nlabel] = node2;
+ mark[node2] = true;
+ }
+ }
+ }
+ else
+ { arc = -arc;
+ rc[arc] -= delprc;
+ if (rc[arc] == 0)
+ { node2 = endn[arc];
+ if (tnxtou[arc] < 0)
+ { tnxtou[arc] = tfstou[startn[arc]];
+ tfstou[startn[arc]] = arc;
+ }
+ if (tnxtin[arc] < 0)
+ { tnxtin[arc] = tfstin[node2];
+ tfstin[node2] = arc;
+ }
+ if (!mark[node2])
+ { prdcsr[node2] = -arc;
+ nlabel++;
+ label[nlabel] = node2;
+ mark[node2] = true;
+ }
+ }
+ }
+ }
+ return;
+ }
+ else
+ { nb = 0;
+ for (i = 1; i <= nsave; i++)
+ { arc = save[i];
+ if (arc > 0)
+ { t1 = rc[arc];
+ if (t1 == 0)
+ { t2 = x[arc];
+ t3 = startn[arc];
+ dfct[t3] -= t2;
+ if (nxtqueue[t3] == 0)
+ { nxtqueue[prevnode] = t3;
+ nxtqueue[t3] = curnode;
+ prevnode = t3;
+ }
+ t3 = endn[arc];
+ dfct[t3] += t2;
+ if (nxtqueue[t3] == 0)
+ { nxtqueue[prevnode] = t3;
+ nxtqueue[t3] = curnode;
+ prevnode = t3;
+ }
+ u[arc] += t2;
+ x[arc] = 0;
+ }
+ rc[arc] = t1 + delprc;
+#if 0 /* by mao; 26/IV-2013 */
+ if (rc[arc] == 0)
+#else
+ if (rc[arc] == 0 && nb < n)
+#endif
+ { delx += x[arc];
+ nb++;
+ prdcsr[nb] = arc;
+ }
+ }
+ else
+ { arc = -arc;
+ t1 = rc[arc];
+ if (t1 == 0)
+ { t2 = u[arc];
+ t3 = startn[arc];
+ dfct[t3] += t2;
+ if (nxtqueue[t3] == 0)
+ { nxtqueue[prevnode] = t3;
+ nxtqueue[t3] = curnode;
+ prevnode = t3;
+ }
+ t3 = endn[arc];
+ dfct[t3] -= t2;
+ if (nxtqueue[t3] == 0)
+ { nxtqueue[prevnode] = t3;
+ nxtqueue[t3] = curnode;
+ prevnode = t3;
+ }
+ x[arc] += t2;
+ u[arc] = 0;
+ }
+ rc[arc] = t1 - delprc;
+#if 0 /* by mao; 26/IV-2013 */
+ if (rc[arc] == 0)
+#else
+ if (rc[arc] == 0 && nb < n)
+#endif
+ { delx += u[arc];
+ nb++;
+ prdcsr[nb] = arc;
+ }
+ }
+ }
+ }
+ if (delx <= -dm)
+ { delprc = large;
+ for (i = 1; i <= nsave; i++)
+ { arc = save[i];
+ if (arc > 0)
+ { rdcost = rc[arc];
+ if ((rdcost < 0) && (rdcost > -delprc))
+ delprc = -rdcost;
+ }
+ else
+ { arc = -arc;
+ rdcost = rc[arc];
+ if ((rdcost > 0) && (rdcost < delprc))
+ delprc = rdcost;
+ }
+ }
+ if ((delprc != large) || (delx < -dm))
+ goto L4;
+ }
+ /* Add new balanced arcs to the superset of balanced arcs. */
+ for (i = 1; i <= nb; i++)
+ { arc = prdcsr[i];
+ if (tnxtin[arc] == -1)
+ { j = endn[arc];
+ tnxtin[arc] = tfstin[j];
+ tfstin[j] = arc;
+ }
+ if (tnxtou[arc] == -1)
+ { j = startn[arc];
+ tnxtou[arc] = tfstou[j];
+ tfstou[j] = arc;
+ }
+ }
+ return;
+# undef delx
+# undef nlabel
+# undef feasbl
+# undef svitch
+# undef prevnode
+}
+
+/***********************************************************************
+* NAME
+*
+* auction - compute good initial flow and prices
+*
+* PURPOSE
+*
+* This subroutine uses a version of the auction algorithm for min
+* cost network flow to compute a good initial flow and prices for the
+* problem.
+*
+* INPUT PARAMETERS
+*
+* n = number of nodes
+* na = number of arcs
+* large = a very large integer to represent infinity (see note 3)
+* startn[i] = starting node for the i-th arc, i = 1,...,na
+* endn[i] = ending node for the i-th arc, i = 1,...,na
+* fou[i] = first arc leaving i-th node, i = 1,...,n
+* nxtou[i] = next arc leaving the starting node of j-th arc,
+* i = 1,...,na
+* fin[i] = first arc entering i-th node, i = 1,...,n
+* nxtin[i] = next arc entering the ending node of j-th arc,
+* i = 1,...,na
+*
+* UPDATED PARAMETERS
+*
+* rc[j] = reduced cost of arc j, j = 1,...,na
+* u[j] = residual capacity of arc j, j = 1,...,na
+* x[j] = flow on arc j, j = 1,...,na
+* dfct[i] = deficit at node i, i = 1,...,n
+*
+* OUTPUT PARAMETERS
+*
+* nsp = number of auction/shortest path iterations
+*
+* WORKING PARAMETERS
+*
+* p[1+n], prdcsr[1+n], save[1+na], fpushf[1+n], nxtpushf[1+na],
+* fpushb[1+n], nxtpushb[1+na], nxtqueue[1+n], extend_arc[1+n],
+* sb_level[1+n], sb_arc[1+n], path_id[1+n]
+*
+* RETURNS
+*
+* 0 = normal return
+* 1 = problem is found to be infeasible */
+
+static int auction(struct relax4_csa *csa)
+{ /* input parameters */
+ int n = csa->n;
+ int na = csa->na;
+ int large = csa->large;
+ int *startn = csa->startn;
+ int *endn = csa->endn;
+ int *fou = csa->fou;
+ int *nxtou = csa->nxtou;
+ int *fin = csa->fin;
+ int *nxtin = csa->nxtin;
+ /* updated parameters */
+# define crash (csa->crash)
+ int *rc = csa->rc;
+ int *u = csa->u;
+ int *x = csa->x;
+ int *dfct = csa->dfct;
+ /* output parameters */
+# define nsp (csa->nsp)
+ /* working parameters */
+ int *p = csa->label;
+ int *prdcsr = csa->prdcsr;
+ int *save = csa->save;
+ int *fpushf = csa->tfstou;
+ int *nxtpushf = csa->tnxtou;
+ int *fpushb = csa->tfstin;
+ int *nxtpushb = csa->tnxtin;
+ int *nxtqueue = csa->nxtqueue;
+ int *extend_arc = csa->extend_arc;
+ int *sb_level = csa->sb_level;
+ int *sb_arc = csa->sb_arc;
+ char *path_id = csa->mark;
+ /* local variables */
+ int arc, bstlevel, end, eps, extarc, factor, flow, i, incr,
+ last, lastqueue, maxcost, mincost, nas, naug, new_level, node,
+ nolist, num_passes, nxtnode, pass, pend, pr_term, prd,
+ prevarc, prevlevel, prevnode, pstart, pterm, rdcost, red_cost,
+ resid, root, secarc, seclevel, start, term, thresh_dfct;
+ /* start initialization using auction */
+ naug = 0;
+ pass = 0;
+ thresh_dfct = 0;
+ /* factor determines by how much epsilon is reduced at each
+ * minimization */
+ factor = 3;
+ /* num_passes determines how many auction scaling phases are
+ * performed */
+ num_passes = 1;
+ /* set arc flows to satisfy cs and calculate maxcost and
+ * mincost */
+ maxcost = -large;
+ mincost = large;
+ for (arc = 1; arc <= na; arc++)
+ { start = startn[arc];
+ end = endn[arc];
+ rdcost = rc[arc];
+ if (maxcost < rdcost)
+ maxcost = rdcost;
+ if (mincost > rdcost)
+ mincost = rdcost;
+ if (rdcost < 0)
+ { dfct[start] += u[arc];
+ dfct[end] -= u[arc];
+ x[arc] = u[arc];
+ u[arc] = 0;
+ }
+ else
+ x[arc] = 0;
+ }
+ /* set initial epsilon */
+ if ((maxcost - mincost) >= 8)
+ eps = (maxcost - mincost) / 8;
+ else
+ eps = 1;
+ /* set initial prices to zero */
+ for (node = 1; node <= n; node++)
+ p[node] = 0;
+ /* Initialization using auction/shortest paths. */
+L100: /* Start of the first scaling phase. */
+ pass++;
+ if ((pass == num_passes) || (eps == 1))
+ crash = 0;
+ nolist = 0;
+ /* construct list of positive surplus nodes and queue of negative
+ * surplus nodes */
+ for (node = 1; node <= n; node++)
+ { prdcsr[node] = 0;
+ path_id[node] = false;
+ extend_arc[node] = 0;
+ sb_level[node] = -large;
+ nxtqueue[node] = node + 1;
+ if (dfct[node] > 0)
+ { nolist++;
+ save[nolist] = node;
+ }
+ }
+ nxtqueue[n] = 1;
+ root = 1;
+ prevnode = lastqueue = n;
+ /* initialization with down iterations for negative surplus
+ * nodes */
+ for (i = 1; i <= nolist; i++)
+ { node = save[i];
+ nsp++;
+ /* build the list of arcs w/ room for pushing flow and find
+ * proper price for down iteration */
+ bstlevel = -large;
+ fpushf[node] = 0;
+ for (arc = fou[node]; arc > 0; arc = nxtou[arc])
+ { if (u[arc] > 0)
+ { if (fpushf[node] == 0)
+ { fpushf[node] = arc;
+ nxtpushf[arc] = 0;
+ last = arc;
+ }
+ else
+ { nxtpushf[last] = arc;
+ nxtpushf[arc] = 0;
+ last = arc;
+ }
+ }
+ if (x[arc] > 0)
+ { new_level = p[endn[arc]] + rc[arc];
+ if (new_level > bstlevel)
+ { bstlevel = new_level;
+ extarc = arc;
+ }
+ }
+ }
+ fpushb[node] = 0;
+ for (arc = fin[node]; arc > 0; arc = nxtin[arc])
+ { if (x[arc] > 0)
+ { if (fpushb[node] == 0)
+ { fpushb[node] = arc;
+ nxtpushb[arc] = 0;
+ last = arc;
+ }
+ else
+ { nxtpushb[last] = arc;
+ nxtpushb[arc] = 0;
+ last = arc;
+ }
+ }
+ if (u[arc] > 0)
+ { new_level = p[startn[arc]] - rc[arc];
+ if (new_level > bstlevel)
+ { bstlevel = new_level;
+ extarc = -arc;
+ }
+ }
+ }
+ extend_arc[node] = extarc;
+ p[node] = bstlevel - eps;
+ }
+L200: /* Start the augmentation cycles of the new scaling phase. */
+ if (dfct[root] >= thresh_dfct)
+ goto L3000;
+ term = root;
+ path_id[root] = true;
+L500: /* Main forward algorithm with root as origin. */
+ /* start of a new forward iteration */
+ pterm = p[term];
+ extarc = extend_arc[term];
+ if (extarc == 0)
+ { /* build the list of arcs w/ room for pushing flow */
+ fpushf[term] = 0;
+ for (arc = fou[term]; arc > 0; arc = nxtou[arc])
+ { if (u[arc] > 0)
+ { if (fpushf[term] == 0)
+ { fpushf[term] = arc;
+ nxtpushf[arc] = 0;
+ last = arc;
+ }
+ else
+ { nxtpushf[last] = arc;
+ nxtpushf[arc] = 0;
+ last = arc;
+ }
+ }
+ }
+ fpushb[term] = 0;
+ for (arc = fin[term]; arc > 0; arc = nxtin[arc])
+ { if (x[arc] > 0)
+ { if (fpushb[term] == 0)
+ { fpushb[term] = arc;
+ nxtpushb[arc] = 0;
+ last = arc;
+ }
+ else
+ { nxtpushb[last] = arc;
+ nxtpushb[arc] = 0;
+ last = arc;
+ }
+ }
+ }
+ goto L600;
+ }
+ /* speculative path extension attempt */
+ /* note: arc > 0 means that arc is oriented from the root to the
+ * destinations
+ * arc < 0 means that arc is oriented from the destinations to the
+ * root
+ * extarc = 0 or prdarc = 0, means the extension arc or the
+ * predecessor arc, respectively, has not been established */
+ if (extarc > 0)
+ { if (u[extarc] == 0)
+ { seclevel = sb_level[term];
+ goto L580;
+ }
+ end = endn[extarc];
+ bstlevel = p[end] + rc[extarc];
+ if (pterm >= bstlevel)
+ { if (path_id[end])
+ goto L1200;
+ term = end;
+ prdcsr[term] = extarc;
+ path_id[term] = true;
+ /* if negative surplus node is found, do an augmentation */
+ if (dfct[term] > 0)
+ goto L2000;
+ /* return for another iteration */
+ goto L500;
+ }
+ }
+ else
+ { extarc = -extarc;
+ if (x[extarc] == 0)
+ { seclevel = sb_level[term];
+ goto L580;
+ }
+ start = startn[extarc];
+ bstlevel = p[start] - rc[extarc];
+ if (pterm >= bstlevel)
+ { if (path_id[start])
+ goto L1200;
+ term = start;
+ prdcsr[term] = -extarc;
+ path_id[term] = true;
+ /* if negative surplus node is found, do an augmentation */
+ if (dfct[term] > 0)
+ goto L2000;
+ /* return for another iteration */
+ goto L500;
+ }
+ }
+L550: /* second best logic test applied to save a full node scan
+ * if old best level continues to be best go for another
+ * contraction */
+ seclevel = sb_level[term];
+ if (bstlevel <= seclevel)
+ goto L800;
+L580: /* if second best can be used do either a contraction or start
+ * over with a speculative extension */
+ if (seclevel > -large)
+ { extarc = sb_arc[term];
+ if (extarc > 0)
+ { if (u[extarc] == 0)
+ goto L600;
+ bstlevel = p[endn[extarc]] + rc[extarc];
+ }
+ else
+ { if (x[-extarc] == 0)
+ goto L600;
+ bstlevel = p[startn[-extarc]] - rc[-extarc];
+ }
+ if (bstlevel == seclevel)
+ { sb_level[term] = -large;
+ extend_arc[term] = extarc;
+ goto L800;
+ }
+ }
+L600: /* extension/contraction attempt was unsuccessful, so scan
+ * terminal node */
+ nsp++;
+ bstlevel = seclevel = large;
+ for (arc = fpushf[term]; arc > 0; arc = nxtpushf[arc])
+ { new_level = p[endn[arc]] + rc[arc];
+ if (new_level < seclevel)
+ { if (new_level < bstlevel)
+ { seclevel = bstlevel;
+ bstlevel = new_level;
+ secarc = extarc;
+ extarc = arc;
+ }
+ else
+ { seclevel = new_level;
+ secarc = arc;
+ }
+ }
+ }
+ for (arc = fpushb[term]; arc > 0; arc = nxtpushb[arc])
+ { new_level = p[startn[arc]] - rc[arc];
+ if (new_level < seclevel)
+ { if (new_level < bstlevel)
+ { seclevel = bstlevel;
+ bstlevel = new_level;
+ secarc = extarc;
+ extarc = -arc;
+ }
+ else
+ { seclevel = new_level;
+ secarc = -arc;
+ }
+ }
+ }
+ sb_level[term] = seclevel;
+ sb_arc[term] = secarc;
+ extend_arc[term] = extarc;
+L800: /* End of node scan. */
+ /* if the terminal node is the root, adjust its price and change
+ * root */
+ if (term == root)
+ { p[term] = bstlevel + eps;
+ if (p[term] >= large)
+ { /* no path to the destination */
+ /* problem is found to be infeasible */
+ return 1;
+ }
+ path_id[root] = false;
+ prevnode = root;
+ root = nxtqueue[root];
+ goto L200;
+ }
+ /* check whether extension or contraction */
+ prd = prdcsr[term];
+ if (prd > 0)
+ { pr_term = startn[prd];
+ prevlevel = p[pr_term] - rc[prd];
+ }
+ else
+ { pr_term = endn[-prd];
+ prevlevel = p[pr_term] + rc[-prd];
+ }
+ if (prevlevel > bstlevel)
+ { /* path extension */
+ if (prevlevel >= bstlevel + eps)
+ p[term] = bstlevel + eps;
+ else
+ p[term] = prevlevel;
+ if (extarc > 0)
+ { end = endn[extarc];
+ if (path_id[end])
+ goto L1200;
+ term = end;
+ }
+ else
+ { start = startn[-extarc];
+ if (path_id[start])
+ goto L1200;
+ term = start;
+ }
+ prdcsr[term] = extarc;
+ path_id[term] = true;
+ /* if negative surplus node is found, do an augmentation */
+ if (dfct[term] > 0)
+ goto L2000;
+ /* return for another iteration */
+ goto L500;
+ }
+ else
+ { /* path contraction */
+ p[term] = bstlevel + eps;
+ path_id[term] = false;
+ term = pr_term;
+ if (pr_term != root)
+ { if (bstlevel <= pterm + eps)
+ goto L2000;
+ }
+ pterm = p[term];
+ extarc = prd;
+ if (prd > 0)
+ bstlevel += eps + rc[prd];
+ else
+ bstlevel += eps - rc[-prd];
+ /* do a second best test and if that fails, do a full node
+ * scan */
+ goto L550;
+ }
+L1200:/* A cycle is about to form; do a retreat sequence. */
+ node = term;
+L1600:if (node != root)
+ { path_id[node] = false;
+ prd = prdcsr[node];
+ if (prd > 0)
+ { pr_term = startn[prd];
+ if (p[pr_term] == p[node] + rc[prd] + eps)
+ { node = pr_term;
+ goto L1600;
+ }
+ }
+ else
+ { pr_term = endn[-prd];
+ if (p[pr_term] == p[node] - rc[-prd] + eps)
+ { node = pr_term;
+ goto L1600;
+ }
+ }
+ /* do a full scan and price rise at pr_term */
+ nsp++;
+ bstlevel = seclevel = large;
+ for (arc = fpushf[pr_term]; arc > 0; arc = nxtpushf[arc])
+ { new_level = p[endn[arc]] + rc[arc];
+ if (new_level < seclevel)
+ { if (new_level < bstlevel)
+ { seclevel = bstlevel;
+ bstlevel = new_level;
+ secarc = extarc;
+ extarc = arc;
+ }
+ else
+ { seclevel = new_level;
+ secarc = arc;
+ }
+ }
+ }
+ for (arc = fpushb[pr_term]; arc > 0; arc = nxtpushb[arc])
+ { new_level = p[startn[arc]] - rc[arc];
+ if (new_level < seclevel)
+ { if (new_level < bstlevel)
+ { seclevel = bstlevel;
+ bstlevel = new_level;
+ secarc = extarc;
+ extarc = -arc;
+ }
+ else
+ { seclevel = new_level;
+ secarc = -arc;
+ }
+ }
+ }
+ sb_level[pr_term] = seclevel;
+ sb_arc[pr_term] = secarc;
+ extend_arc[pr_term] = extarc;
+ p[pr_term] = bstlevel + eps;
+ if (pr_term == root)
+ { prevnode = root;
+ path_id[root] = false;
+ root = nxtqueue[root];
+ goto L200;
+ }
+ path_id[pr_term] = false;
+ prd = prdcsr[pr_term];
+ if (prd > 0)
+ term = startn[prd];
+ else
+ term = endn[-prd];
+ if (term == root)
+ { prevnode = root;
+ path_id[root] = false;
+ root = nxtqueue[root];
+ goto L200;
+ }
+ else
+ goto L2000;
+ }
+L2000:/* End of auction/shortest path routine. */
+ /* do augmentation from root and correct the push lists */
+ incr = -dfct[root];
+ for (node = root;;)
+ { extarc = extend_arc[node];
+ path_id[node] = false;
+ if (extarc > 0)
+ { node = endn[extarc];
+ if (incr > u[extarc])
+ incr = u[extarc];
+ }
+ else
+ { node = startn[-extarc];
+ if (incr > x[-extarc])
+ incr = x[-extarc];
+ }
+ if (node == term)
+ break;
+ }
+ path_id[term] = false;
+ if (dfct[term] > 0)
+ { if (incr > dfct[term])
+ incr = dfct[term];
+ }
+ for (node = root;;)
+ { extarc = extend_arc[node];
+ if (extarc > 0)
+ { end = endn[extarc];
+ /* add arc to the reduced graph */
+ if (x[extarc] == 0)
+ { nxtpushb[extarc] = fpushb[end];
+ fpushb[end] = extarc;
+ new_level = p[node] - rc[extarc];
+ if (sb_level[end] > new_level)
+ { sb_level[end] = new_level;
+ sb_arc[end] = -extarc;
+ }
+ }
+ x[extarc] += incr;
+ u[extarc] -= incr;
+ /* remove arc from the reduced graph */
+ if (u[extarc] == 0)
+ { nas++;
+ arc = fpushf[node];
+ if (arc == extarc)
+ fpushf[node] = nxtpushf[arc];
+ else
+ { prevarc = arc;
+ arc = nxtpushf[arc];
+ while (arc > 0)
+ { if (arc == extarc)
+ { nxtpushf[prevarc] = nxtpushf[arc];
+ break;
+ }
+ prevarc = arc;
+ arc = nxtpushf[arc];
+ }
+ }
+ }
+ node = end;
+ }
+ else
+ { extarc = -extarc;
+ start = startn[extarc];
+ /* add arc to the reduced graph */
+ if (u[extarc] == 0)
+ { nxtpushf[extarc] = fpushf[start];
+ fpushf[start] = extarc;
+ new_level = p[node] + rc[extarc];
+ if (sb_level[start] > new_level)
+ { sb_level[start] = new_level;
+ sb_arc[start] = extarc;
+ }
+ }
+ u[extarc] += incr;
+ x[extarc] -= incr;
+ /* remove arc from the reduced graph */
+ if (x[extarc] == 0)
+ { nas++;
+ arc = fpushb[node];
+ if (arc == extarc)
+ fpushb[node] = nxtpushb[arc];
+ else
+ { prevarc = arc;
+ arc = nxtpushb[arc];
+ while (arc > 0)
+ { if (arc == extarc)
+ { nxtpushb[prevarc] = nxtpushb[arc];
+ break;
+ }
+ prevarc = arc;
+ arc = nxtpushb[arc];
+ }
+ }
+ }
+ node = start;
+ }
+ if (node == term)
+ break;
+ }
+ dfct[term] -= incr;
+ dfct[root] += incr;
+ /* insert term in the queue if it has a large enough surplus */
+ if (dfct[term] < thresh_dfct)
+ { if (nxtqueue[term] == 0)
+ { nxtnode = nxtqueue[root];
+ if ((p[term] >= p[nxtnode]) && (root != nxtnode))
+ { nxtqueue[root] = term;
+ nxtqueue[term] = nxtnode;
+ }
+ else
+ { nxtqueue[prevnode] = term;
+ nxtqueue[term] = root;
+ prevnode = term;
+ }
+ }
+ }
+ /* if root has a large enough surplus, keep it in the queue and
+ * return for another iteration */
+ if (dfct[root] < thresh_dfct)
+ { prevnode = root;
+ root = nxtqueue[root];
+ goto L200;
+ }
+L3000:/* end of augmentation cycle */
+ /* Check for termination of scaling phase. If scaling phase is not
+ * finished, advance the queue and return to take another node. */
+ nxtnode = nxtqueue[root];
+ if (root != nxtnode)
+ { nxtqueue[root] = 0;
+ nxtqueue[prevnode] = nxtnode;
+ root = nxtnode;
+ goto L200;
+ }
+ /* End of subproblem (scaling phase). */
+ /* Reduce epsilon. */
+ eps /= factor;
+ if (eps < 1) eps = 1;
+ thresh_dfct /= factor;
+ if (eps == 1) thresh_dfct = 0;
+ /* if another auction scaling phase remains, reset the flows &
+ * the push lists; else reset arc flows to satisfy cs and compute
+ * reduced costs */
+ if (crash == 1)
+ { for (arc = 1; arc <= na; arc++)
+ { start = startn[arc];
+ end = endn[arc];
+ pstart = p[start];
+ pend = p[end];
+ if (pstart > pend + eps + rc[arc])
+ { resid = u[arc];
+ if (resid > 0)
+ { dfct[start] += resid;
+ dfct[end] -= resid;
+ x[arc] += resid;
+ u[arc] = 0;
+ }
+ }
+ else if (pstart < pend - eps + rc[arc])
+ { flow = x[arc];
+ if (flow > 0)
+ { dfct[start] -= flow;
+ dfct[end] += flow;
+ x[arc] = 0;
+ u[arc] += flow;
+ }
+ }
+ }
+ /* return for another phase */
+ goto L100;
+ }
+ else
+ { crash = 1;
+ for (arc = 1; arc <= na; arc++)
+ { start = startn[arc];
+ end = endn[arc];
+ red_cost = rc[arc] + p[end] - p[start];
+ if (red_cost < 0)
+ { resid = u[arc];
+ if (resid > 0)
+ { dfct[start] += resid;
+ dfct[end] -= resid;
+ x[arc] += resid;
+ u[arc] = 0;
+ }
+ }
+ else if (red_cost > 0)
+ { flow = x[arc];
+ if (flow > 0)
+ { dfct[start] -= flow;
+ dfct[end] += flow;
+ x[arc] = 0;
+ u[arc] += flow;
+ }
+ }
+ rc[arc] = red_cost;
+ }
+ }
+ return 0;
+# undef crash
+# undef nsp
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/relax4.h b/test/monniaux/glpk-4.65/src/misc/relax4.h
new file mode 100644
index 00000000..f48b8508
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/relax4.h
@@ -0,0 +1,102 @@
+/* relax4.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#ifndef RELAX4_H
+#define RELAX4_H
+
+struct relax4_csa
+{ /* common storage area */
+ /* input parameters --------------------------------------------*/
+ int n;
+ /* number of nodes */
+ int na;
+ /* number of arcs */
+ int large;
+ /* very large int to represent infinity */
+ int repeat;
+ /* true if initialization is to be skipped (false otherwise) */
+ int crash;
+ /* 0 if default initialization is used
+ * 1 if auction initialization is used */
+ int *startn; /* int startn[1+na]; */
+ /* startn[j] = starting node for arc j, j = 1,...,na */
+ int *endn; /* int endn[1+na] */
+ /* endn[j] = ending node for arc j, j = 1,...,na */
+ int *fou; /* int fou[1+n]; */
+ /* fou[i] = first arc out of node i, i = 1,...,n */
+ int *nxtou; /* int nxtou[1+na]; */
+ /* nxtou[j] = next arc out of the starting node of arc j,
+ * j = 1,...,na */
+ int *fin; /* int fin[1+n]; */
+ /* fin[i] = first arc into node i, i = 1,...,n */
+ int *nxtin; /* int nxtin[1+na]; */
+ /* nxtin[j] = next arc into the ending node of arc j,
+ * j = 1,...,na */
+ /* updated parameters ------------------------------------------*/
+ int *rc; /* int rc[1+na]; */
+ /* rc[j] = reduced cost of arc j, j = 1,...,na */
+ int *u; /* int u[1+na]; */
+ /* u[j] = capacity of arc j on input
+ * and (capacity of arc j) - x(j) on output, j = 1,...,na */
+ int *dfct; /* int dfct[1+n]; */
+ /* dfct[i] = demand at node i on input
+ * and zero on output, i = 1,...,n */
+ /* output parameters -------------------------------------------*/
+ int *x; /* int x[1+na]; */
+ /* x[j] = flow on arc j, j = 1,...,na */
+ int nmultinode;
+ /* number of multinode relaxation iterations in RELAX4 */
+ int iter;
+ /* number of relaxation iterations in RELAX4 */
+ int num_augm;
+ /* number of flow augmentation steps in RELAX4 */
+ int num_ascnt;
+ /* number of multinode ascent steps in RELAX4 */
+ int nsp;
+ /* number of auction/shortest path iterations */
+ /* working parameters ------------------------------------------*/
+ int *label; /* int label, tempin, p[1+n]; */
+ int *prdcsr; /* int prdcsr, tempou, price[1+n]; */
+ int *save; /* int save[1+na]; */
+ int *tfstou; /* int tfstou, fpushf[1+n]; */
+ int *tnxtou; /* int tnxtou, nxtpushf[1+na]; */
+ int *tfstin; /* int tfstin, fpushb[1+n]; */
+ int *tnxtin; /* int tnxtin, nxtpushb[1+na]; */
+ int *nxtqueue; /* int nxtqueue[1+n]; */
+ char *scan; /* bool scan[1+n]; */
+ char *mark; /* bool mark, path_id[1+n]; */
+ /* working parameters used by routine auction only -------------*/
+ int *extend_arc; /* int extend_arc[1+n]; */
+ int *sb_level; /* int sb_level[1+n]; */
+ int *sb_arc; /* int sb_arc[1+n]; */
+};
+
+#define relax4 _glp_relax4
+int relax4(struct relax4_csa *csa);
+
+#define relax4_inidat _glp_relax4_inidat
+void relax4_inidat(struct relax4_csa *csa);
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/rng.c b/test/monniaux/glpk-4.65/src/misc/rng.c
new file mode 100644
index 00000000..e0acb53a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/rng.c
@@ -0,0 +1,227 @@
+/* rng.c (pseudo-random number generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* This code is a modified version of the module GB_FLIP, a portable
+* pseudo-random number generator. The original version of GB_FLIP is
+* a part of The Stanford GraphBase developed by Donald E. Knuth (see
+* http://www-cs-staff.stanford.edu/~knuth/sgb.html).
+*
+* Note that all changes concern only external names, so this modified
+* version produces exactly the same results as the original version.
+*
+* Changes were made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "rng.h"
+
+#if 0
+int A[56] = { -1 };
+#else
+#define A (rand->A)
+#endif
+/* pseudo-random values */
+
+#if 0
+int *fptr = A;
+#else
+#define fptr (rand->fptr)
+#endif
+/* the next A value to be exported */
+
+#define mod_diff(x, y) (((x) - (y)) & 0x7FFFFFFF)
+/* difference modulo 2^31 */
+
+static int flip_cycle(RNG *rand)
+{ /* this is an auxiliary routine to do 55 more steps of the basic
+ * recurrence, at high speed, and to reset fptr */
+ int *ii, *jj;
+ for (ii = &A[1], jj = &A[32]; jj <= &A[55]; ii++, jj++)
+ *ii = mod_diff(*ii, *jj);
+ for (jj = &A[1]; ii <= &A[55]; ii++, jj++)
+ *ii = mod_diff(*ii, *jj);
+ fptr = &A[54];
+ return A[55];
+}
+
+/***********************************************************************
+* NAME
+*
+* rng_create_rand - create pseudo-random number generator
+*
+* SYNOPSIS
+*
+* #include "rng.h"
+* RNG *rng_create_rand(void);
+*
+* DESCRIPTION
+*
+* The routine rng_create_rand creates and initializes a pseudo-random
+* number generator.
+*
+* RETURNS
+*
+* The routine returns a pointer to the generator created. */
+
+RNG *rng_create_rand(void)
+{ RNG *rand;
+ int i;
+ rand = talloc(1, RNG);
+ A[0] = -1;
+ for (i = 1; i <= 55; i++) A[i] = 0;
+ fptr = A;
+ rng_init_rand(rand, 1);
+ return rand;
+}
+
+/***********************************************************************
+* NAME
+*
+* rng_init_rand - initialize pseudo-random number generator
+*
+* SYNOPSIS
+*
+* #include "rng.h"
+* void rng_init_rand(RNG *rand, int seed);
+*
+* DESCRIPTION
+*
+* The routine rng_init_rand initializes the pseudo-random number
+* generator. The parameter seed may be any integer number. Note that
+* on creating the generator this routine is called with the parameter
+* seed equal to 1. */
+
+void rng_init_rand(RNG *rand, int seed)
+{ int i;
+ int prev = seed, next = 1;
+ seed = prev = mod_diff(prev, 0);
+ A[55] = prev;
+ for (i = 21; i; i = (i + 21) % 55)
+ { A[i] = next;
+ next = mod_diff(prev, next);
+ if (seed & 1)
+ seed = 0x40000000 + (seed >> 1);
+ else
+ seed >>= 1;
+ next = mod_diff(next, seed);
+ prev = A[i];
+ }
+ flip_cycle(rand);
+ flip_cycle(rand);
+ flip_cycle(rand);
+ flip_cycle(rand);
+ flip_cycle(rand);
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* rng_next_rand - obtain pseudo-random integer in the range [0, 2^31-1]
+*
+* SYNOPSIS
+*
+* #include "rng.h"
+* int rng_next_rand(RNG *rand);
+*
+* RETURNS
+*
+* The routine rng_next_rand returns a next pseudo-random integer which
+* is uniformly distributed between 0 and 2^31-1, inclusive. The period
+* length of the generated numbers is 2^85 - 2^30. The low order bits of
+* the generated numbers are just as random as the high-order bits. */
+
+int rng_next_rand(RNG *rand)
+{ return
+ *fptr >= 0 ? *fptr-- : flip_cycle(rand);
+}
+
+/***********************************************************************
+* NAME
+*
+* rng_unif_rand - obtain pseudo-random integer in the range [0, m-1]
+*
+* SYNOPSIS
+*
+* #include "rng.h"
+* int rng_unif_rand(RNG *rand, int m);
+*
+* RETURNS
+*
+* The routine rng_unif_rand returns a next pseudo-random integer which
+* is uniformly distributed between 0 and m-1, inclusive, where m is any
+* positive integer less than 2^31. */
+
+#define two_to_the_31 ((unsigned int)0x80000000)
+
+int rng_unif_rand(RNG *rand, int m)
+{ unsigned int t = two_to_the_31 - (two_to_the_31 % m);
+ int r;
+ xassert(m > 0);
+ do { r = rng_next_rand(rand); } while (t <= (unsigned int)r);
+ return r % m;
+}
+
+/***********************************************************************
+* NAME
+*
+* rng_delete_rand - delete pseudo-random number generator
+*
+* SYNOPSIS
+*
+* #include "rng.h"
+* void rng_delete_rand(RNG *rand);
+*
+* DESCRIPTION
+*
+* The routine rng_delete_rand frees all the memory allocated to the
+* specified pseudo-random number generator. */
+
+void rng_delete_rand(RNG *rand)
+{ tfree(rand);
+ return;
+}
+
+/**********************************************************************/
+
+#ifdef GLP_TEST
+/* To be sure that this modified version produces the same results as
+ * the original version, run this validation program. */
+
+int main(void)
+{ RNG *rand;
+ int j;
+ rand = rng_create_rand();
+ rng_init_rand(rand, -314159);
+ if (rng_next_rand(rand) != 119318998)
+ { fprintf(stderr, "Failure on the first try!\n");
+ return -1;
+ }
+ for (j = 1; j <= 133; j++) rng_next_rand(rand);
+ if (rng_unif_rand(rand, 0x55555555) != 748103812)
+ { fprintf(stderr, "Failure on the second try!\n");
+ return -2;
+ }
+ fprintf(stderr, "OK, the random-number generator routines seem to"
+ " work!\n");
+ rng_delete_rand(rand);
+ return 0;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/rng.h b/test/monniaux/glpk-4.65/src/misc/rng.h
new file mode 100644
index 00000000..49725e05
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/rng.h
@@ -0,0 +1,67 @@
+/* rng.h (pseudo-random number generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2003-2013 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/>.
+***********************************************************************/
+
+#ifndef RNG_H
+#define RNG_H
+
+typedef struct RNG RNG;
+
+struct RNG
+{ /* Knuth's portable pseudo-random number generator */
+ int A[56];
+ /* pseudo-random values */
+ int *fptr;
+ /* the next A value to be exported */
+};
+
+#define rng_create_rand _glp_rng_create_rand
+RNG *rng_create_rand(void);
+/* create pseudo-random number generator */
+
+#define rng_init_rand _glp_rng_init_rand
+void rng_init_rand(RNG *rand, int seed);
+/* initialize pseudo-random number generator */
+
+#define rng_next_rand _glp_rng_next_rand
+int rng_next_rand(RNG *rand);
+/* obtain pseudo-random integer in the range [0, 2^31-1] */
+
+#define rng_unif_rand _glp_rng_unif_rand
+int rng_unif_rand(RNG *rand, int m);
+/* obtain pseudo-random integer in the range [0, m-1] */
+
+#define rng_delete_rand _glp_rng_delete_rand
+void rng_delete_rand(RNG *rand);
+/* delete pseudo-random number generator */
+
+#define rng_unif_01 _glp_rng_unif_01
+double rng_unif_01(RNG *rand);
+/* obtain pseudo-random number in the range [0, 1] */
+
+#define rng_uniform _glp_rng_uniform
+double rng_uniform(RNG *rand, double a, double b);
+/* obtain pseudo-random number in the range [a, b] */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/rng1.c b/test/monniaux/glpk-4.65/src/misc/rng1.c
new file mode 100644
index 00000000..b89f676f
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/rng1.c
@@ -0,0 +1,73 @@
+/* rng1.c (pseudo-random number generator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2003-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "rng.h"
+
+/***********************************************************************
+* NAME
+*
+* rng_unif_01 - obtain pseudo-random number in the range [0, 1]
+*
+* SYNOPSIS
+*
+* #include "rng.h"
+* double rng_unif_01(RNG *rand);
+*
+* RETURNS
+*
+* The routine rng_unif_01 returns a next pseudo-random number which is
+* uniformly distributed in the range [0, 1]. */
+
+double rng_unif_01(RNG *rand)
+{ double x;
+ x = (double)rng_next_rand(rand) / 2147483647.0;
+ xassert(0.0 <= x && x <= 1.0);
+ return x;
+}
+
+/***********************************************************************
+* NAME
+*
+* rng_uniform - obtain pseudo-random number in the range [a, b]
+*
+* SYNOPSIS
+*
+* #include "rng.h"
+* double rng_uniform(RNG *rand, double a, double b);
+*
+* RETURNS
+*
+* The routine rng_uniform returns a next pseudo-random number which is
+* uniformly distributed in the range [a, b]. */
+
+double rng_uniform(RNG *rand, double a, double b)
+{ double x;
+ xassert(a < b);
+ x = rng_unif_01(rand);
+ x = a * (1.0 - x) + b * x;
+ xassert(a <= x && x <= b);
+ return x;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/round2n.c b/test/monniaux/glpk-4.65/src/misc/round2n.c
new file mode 100644
index 00000000..8a94c616
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/round2n.c
@@ -0,0 +1,64 @@
+/* round2n.c (round floating-point number to nearest power of two) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "misc.h"
+
+/***********************************************************************
+* NAME
+*
+* round2n - round floating-point number to nearest power of two
+*
+* SYNOPSIS
+*
+* #include "misc.h"
+* double round2n(double x);
+*
+* RETURNS
+*
+* Given a positive floating-point value x the routine round2n returns
+* 2^n such that |x - 2^n| is minimal.
+*
+* EXAMPLES
+*
+* round2n(10.1) = 2^3 = 8
+* round2n(15.3) = 2^4 = 16
+* round2n(0.01) = 2^(-7) = 0.0078125
+*
+* BACKGROUND
+*
+* Let x = f * 2^e, where 0.5 <= f < 1 is a normalized fractional part,
+* e is an integer exponent. Then, obviously, 0.5 * 2^e <= x < 2^e, so
+* if x - 0.5 * 2^e <= 2^e - x, we choose 0.5 * 2^e = 2^(e-1), and 2^e
+* otherwise. The latter condition can be written as 2 * x <= 1.5 * 2^e
+* or 2 * f * 2^e <= 1.5 * 2^e or, finally, f <= 0.75. */
+
+double round2n(double x)
+{ int e;
+ double f;
+ xassert(x > 0.0);
+ f = frexp(x, &e);
+ return ldexp(1.0, f <= 0.75 ? e-1 : e);
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/str2int.c b/test/monniaux/glpk-4.65/src/misc/str2int.c
new file mode 100644
index 00000000..cbd6e953
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/str2int.c
@@ -0,0 +1,92 @@
+/* str2int.c (convert string to int) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "misc.h"
+#include "stdc.h"
+
+/***********************************************************************
+* NAME
+*
+* str2int - convert character string to value of int type
+*
+* SYNOPSIS
+*
+* #include "misc.h"
+* int str2int(const char *str, int *val);
+*
+* DESCRIPTION
+*
+* The routine str2int converts the character string str to a value of
+* integer type and stores the value into location, which the parameter
+* val points to (in the case of error content of this location is not
+* changed).
+*
+* RETURNS
+*
+* The routine returns one of the following error codes:
+*
+* 0 - no error;
+* 1 - value out of range;
+* 2 - character string is syntactically incorrect. */
+
+int str2int(const char *str, int *val_)
+{ int d, k, s, val = 0;
+ /* scan optional sign */
+ if (str[0] == '+')
+ s = +1, k = 1;
+ else if (str[0] == '-')
+ s = -1, k = 1;
+ else
+ s = +1, k = 0;
+ /* check for the first digit */
+ if (!isdigit((unsigned char)str[k]))
+ return 2;
+ /* scan digits */
+ while (isdigit((unsigned char)str[k]))
+ { d = str[k++] - '0';
+ if (s > 0)
+ { if (val > INT_MAX / 10)
+ return 1;
+ val *= 10;
+ if (val > INT_MAX - d)
+ return 1;
+ val += d;
+ }
+ else /* s < 0 */
+ { if (val < INT_MIN / 10)
+ return 1;
+ val *= 10;
+ if (val < INT_MIN + d)
+ return 1;
+ val -= d;
+ }
+ }
+ /* check for terminator */
+ if (str[k] != '\0')
+ return 2;
+ /* conversion has been done */
+ *val_ = val;
+ return 0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/str2num.c b/test/monniaux/glpk-4.65/src/misc/str2num.c
new file mode 100644
index 00000000..26c2f68f
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/str2num.c
@@ -0,0 +1,110 @@
+/* str2num.c (convert string to double) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "misc.h"
+#include "stdc.h"
+
+/***********************************************************************
+* NAME
+*
+* str2num - convert character string to value of double type
+*
+* SYNOPSIS
+*
+* #include "misc.h"
+* int str2num(const char *str, double *val);
+*
+* DESCRIPTION
+*
+* The routine str2num converts the character string str to a value of
+* double type and stores the value into location, which the parameter
+* val points to (in the case of error content of this location is not
+* changed).
+*
+* RETURNS
+*
+* The routine returns one of the following error codes:
+*
+* 0 - no error;
+* 1 - value out of range;
+* 2 - character string is syntactically incorrect. */
+
+int str2num(const char *str, double *val_)
+{ int k;
+ double val;
+ /* scan optional sign */
+ k = (str[0] == '+' || str[0] == '-' ? 1 : 0);
+ /* check for decimal point */
+ if (str[k] == '.')
+ { k++;
+ /* a digit should follow it */
+ if (!isdigit((unsigned char)str[k]))
+ return 2;
+ k++;
+ goto frac;
+ }
+ /* integer part should start with a digit */
+ if (!isdigit((unsigned char)str[k]))
+ return 2;
+ /* scan integer part */
+ while (isdigit((unsigned char)str[k]))
+ k++;
+ /* check for decimal point */
+ if (str[k] == '.') k++;
+frac: /* scan optional fraction part */
+ while (isdigit((unsigned char)str[k]))
+ k++;
+ /* check for decimal exponent */
+ if (str[k] == 'E' || str[k] == 'e')
+ { k++;
+ /* scan optional sign */
+ if (str[k] == '+' || str[k] == '-')
+ k++;
+ /* a digit should follow E, E+ or E- */
+ if (!isdigit((unsigned char)str[k]))
+ return 2;
+ }
+ /* scan optional exponent part */
+ while (isdigit((unsigned char)str[k]))
+ k++;
+ /* check for terminator */
+ if (str[k] != '\0')
+ return 2;
+ /* perform conversion */
+ { char *endptr;
+ val = strtod(str, &endptr);
+ if (*endptr != '\0')
+ return 2;
+ }
+ /* check for overflow */
+ if (!(-DBL_MAX <= val && val <= +DBL_MAX))
+ return 1;
+ /* check for underflow */
+ if (-DBL_MIN < val && val < +DBL_MIN)
+ val = 0.0;
+ /* conversion has been done */
+ *val_ = val;
+ return 0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/strspx.c b/test/monniaux/glpk-4.65/src/misc/strspx.c
new file mode 100644
index 00000000..fe8a2a10
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/strspx.c
@@ -0,0 +1,60 @@
+/* strspx.c (remove all spaces from string) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "misc.h"
+
+/***********************************************************************
+* NAME
+*
+* strspx - remove all spaces from character string
+*
+* SYNOPSIS
+*
+* #include "misc.h"
+* char *strspx(char *str);
+*
+* DESCRIPTION
+*
+* The routine strspx removes all spaces from the character string str.
+*
+* RETURNS
+*
+* The routine returns a pointer to the character string.
+*
+* EXAMPLES
+*
+* strspx(" Errare humanum est ") => "Errarehumanumest"
+*
+* strspx(" ") => "" */
+
+char *strspx(char *str)
+{ char *s, *t;
+ for (s = t = str; *s; s++)
+ { if (*s != ' ')
+ *t++ = *s;
+ }
+ *t = '\0';
+ return str;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/strtrim.c b/test/monniaux/glpk-4.65/src/misc/strtrim.c
new file mode 100644
index 00000000..9992c4b0
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/strtrim.c
@@ -0,0 +1,62 @@
+/* strtrim.c (remove trailing spaces from string) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2000-2013 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/>.
+***********************************************************************/
+
+#include "misc.h"
+#include "stdc.h"
+
+/***********************************************************************
+* NAME
+*
+* strtrim - remove trailing spaces from character string
+*
+* SYNOPSIS
+*
+* #include "misc.h"
+* char *strtrim(char *str);
+*
+* DESCRIPTION
+*
+* The routine strtrim removes trailing spaces from the character
+* string str.
+*
+* RETURNS
+*
+* The routine returns a pointer to the character string.
+*
+* EXAMPLES
+*
+* strtrim("Errare humanum est ") => "Errare humanum est"
+*
+* strtrim(" ") => "" */
+
+char *strtrim(char *str)
+{ char *t;
+ for (t = strrchr(str, '\0') - 1; t >= str; t--)
+ { if (*t != ' ')
+ break;
+ *t = '\0';
+ }
+ return str;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/triang.c b/test/monniaux/glpk-4.65/src/misc/triang.c
new file mode 100644
index 00000000..99ba4d60
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/triang.c
@@ -0,0 +1,311 @@
+/* triang.c (find maximal triangular part of rectangular matrix) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "triang.h"
+
+/***********************************************************************
+* triang - find maximal triangular part of rectangular matrix
+*
+* Given a mxn sparse matrix A this routine finds permutation matrices
+* P and Q such that matrix A' = P * A * Q has the following structure:
+*
+* 1 s n
+* 1 * . . . . . x x x x x
+* * * . . . . x x x x x
+* * * * . . . x x x x x
+* * * * * . . x x x x x
+* * * * * * . x x x x x
+* s * * * * * * x x x x x
+* x x x x x x x x x x x
+* x x x x x x x x x x x
+* m x x x x x x x x x x x
+*
+* where '*' are elements of the triangular part, '.' are structural
+* zeros, 'x' are other elements.
+*
+* The formal routine mat specifies the original matrix A in both row-
+* and column-wise format. If the routine mat is called with k = +i,
+* 1 <= i <= m, it should store column indices and values of non-zero
+* elements of i-th row of A in locations ind[1], ..., ind[len] and
+* val[1], ..., val[len], resp., where len is the returned number of
+* non-zeros in the row, 0 <= len <= n. Similarly, if the routine mat
+* is called with k = -j, 1 <= j <= n, it should store row indices and
+* values of non-zero elements of j-th column of A and return len, the
+* number of non-zeros in the column, 0 <= len <= m. Should note that
+* duplicate indices are not allowed.
+*
+* The parameter info is a transit pointer passed to the routine mat.
+*
+* The parameter tol is a tolerance. The routine triang guarantees that
+* each diagonal element in the triangular part of matrix A' is not
+* less in magnitude than tol * max, where max is the maximal magnitude
+* of elements in corresponding column.
+*
+* On exit the routine triang stores information on the triangular part
+* found in the arrays rn and cn. Elements rn[1], ..., rn[s] specify
+* row numbers and elements cn[1], ..., cn[s] specify column numbers
+* of the original matrix A, which correspond to rows/columns 1, ..., s
+* of matrix A', where s is the size of the triangular part returned by
+* the routine, 0 <= s <= min(m, n). The order of rows and columns that
+* are not included in the triangular part remains unspecified.
+*
+* ALGORITHM
+*
+* The routine triang uses a simple greedy heuristic.
+*
+* At some step the matrix A' = P * A * Q has the following structure:
+*
+* 1 n
+* 1 * . . . . . . . x x x
+* * * . . . . . . x x x
+* * * * . . . . . x x x
+* * * * * . . . . x x x
+* x x x x # # # # x x x
+* x x x x # # # # x x x
+* x x x x # # # # x x x
+* x x x x # # # # x x x
+* m x x x x # # # # x x x
+*
+* where '#' are elements of active submatrix. Initially P = Q = I, so
+* the active submatrix is the original matrix A = A'.
+*
+* If some row has exactly one non-zero in the active submatrix (row
+* singleton), the routine includes this row and corresponding column
+* in the triangular part, and removes the column from the active
+* submatrix. Otherwise, the routine simply removes a column having
+* maximal number of non-zeros from the active submatrix in the hope
+* that new row singleton(s) will appear.
+*
+* COMPLEXITY
+*
+* The time complexity of the routine triang is O(nnz), where nnz is
+* number of non-zeros in the original matrix A. */
+
+int triang(int m, int n, int (*mat)(void *info, int k, int ind[],
+ double val[]), void *info, double tol, int rn[], int cn[])
+{ int head, i, j, jj, k, kk, ks, len, len2, next_j, ns, size;
+ int *cind, *rind, *cnt, *ptr, *list, *prev, *next;
+ double *cval, *rval, *big;
+ char *flag;
+ /* allocate working arrays */
+ cind = talloc(1+m, int);
+ cval = talloc(1+m, double);
+ rind = talloc(1+n, int);
+ rval = talloc(1+n, double);
+ cnt = ptr = talloc(1+m, int);
+ list = talloc(1+n, int);
+ prev = talloc(1+n, int);
+ next = talloc(1+n, int);
+ big = talloc(1+n, double);
+ flag = talloc(1+n, char);
+ /*--------------------------------------------------------------*/
+ /* build linked lists of columns having equal lengths */
+ /*--------------------------------------------------------------*/
+ /* ptr[len], 0 <= len <= m, is number of first column of length
+ * len;
+ * next[j], 1 <= j <= n, is number of next column having the same
+ * length as column j;
+ * big[j], 1 <= j <= n, is maximal magnitude of elements in j-th
+ * column */
+ for (len = 0; len <= m; len++)
+ ptr[len] = 0;
+ for (j = 1; j <= n; j++)
+ { /* get j-th column */
+ len = mat(info, -j, cind, cval);
+ xassert(0 <= len && len <= m);
+ /* add this column to beginning of list ptr[len] */
+ next[j] = ptr[len];
+ ptr[len] = j;
+ /* determine maximal magnitude of elements in this column */
+ big[j] = 0.0;
+ for (k = 1; k <= len; k++)
+ { if (big[j] < fabs(cval[k]))
+ big[j] = fabs(cval[k]);
+ }
+ }
+ /*--------------------------------------------------------------*/
+ /* build doubly linked list of columns ordered by decreasing */
+ /* column lengths */
+ /*--------------------------------------------------------------*/
+ /* head is number of first column in the list;
+ * prev[j], 1 <= j <= n, is number of column that precedes j-th
+ * column in the list;
+ * next[j], 1 <= j <= n, is number of column that follows j-th
+ * column in the list */
+ head = 0;
+ for (len = 0; len <= m; len++)
+ { /* walk thru list of columns of length len */
+ for (j = ptr[len]; j != 0; j = next_j)
+ { next_j = next[j];
+ /* add j-th column to beginning of the column list */
+ prev[j] = 0;
+ next[j] = head;
+ if (head != 0)
+ prev[head] = j;
+ head = j;
+ }
+ }
+ /*--------------------------------------------------------------*/
+ /* build initial singleton list */
+ /*--------------------------------------------------------------*/
+ /* there are used two list of columns:
+ * 1) doubly linked list of active columns, in which all columns
+ * are ordered by decreasing column lengths;
+ * 2) singleton list; an active column is included in this list
+ * if it has at least one row singleton in active submatrix */
+ /* flag[j], 1 <= j <= n, is a flag of j-th column:
+ * 0 j-th column is inactive;
+ * 1 j-th column is active;
+ * 2 j-th column is active and has row singleton(s) */
+ /* initially all columns are active */
+ for (j = 1; j <= n; j++)
+ flag[j] = 1;
+ /* initialize row counts and build initial singleton list */
+ /* cnt[i], 1 <= i <= m, is number of non-zeros, which i-th row
+ * has in active submatrix;
+ * ns is size of singleton list;
+ * list[1], ..., list[ns] are numbers of active columns included
+ * in the singleton list */
+ ns = 0;
+ for (i = 1; i <= m; i++)
+ { /* get i-th row */
+ len = cnt[i] = mat(info, +i, rind, rval);
+ xassert(0 <= len && len <= n);
+ if (len == 1)
+ { /* a[i,j] is row singleton */
+ j = rind[1];
+ xassert(1 <= j && j <= n);
+ if (flag[j] != 2)
+ { /* include j-th column in singleton list */
+ flag[j] = 2;
+ list[++ns] = j;
+ }
+ }
+ }
+ /*--------------------------------------------------------------*/
+ /* main loop */
+ /*--------------------------------------------------------------*/
+ size = 0; /* size of triangular part */
+ /* loop until active column list is non-empty, i.e. until the
+ * active submatrix has at least one column */
+ while (head != 0)
+ { if (ns == 0)
+ { /* singleton list is empty */
+ /* remove from the active submatrix a column of maximal
+ * length in the hope that some row singletons appear */
+ j = head;
+ len = mat(info, -j, cind, cval);
+ xassert(0 <= len && len <= m);
+ goto drop;
+ }
+ /* take column j from the singleton list */
+ j = list[ns--];
+ xassert(flag[j] == 2);
+ /* j-th column has at least one row singleton in the active
+ * submatrix; choose one having maximal magnitude */
+ len = mat(info, -j, cind, cval);
+ xassert(0 <= len && len <= m);
+ kk = 0;
+ for (k = 1; k <= len; k++)
+ { i = cind[k];
+ xassert(1 <= i && i <= m);
+ if (cnt[i] == 1)
+ { /* a[i,j] is row singleton */
+ if (kk == 0 || fabs(cval[kk]) < fabs(cval[k]))
+ kk = k;
+ }
+ }
+ xassert(kk > 0);
+ /* check magnitude of the row singleton chosen */
+ if (fabs(cval[kk]) < tol * big[j])
+ { /* all row singletons are too small in magnitude; drop j-th
+ * column */
+ goto drop;
+ }
+ /* row singleton a[i,j] is ok; add i-th row and j-th column to
+ * the triangular part */
+ size++;
+ rn[size] = cind[kk];
+ cn[size] = j;
+drop: /* remove j-th column from the active submatrix */
+ xassert(flag[j]);
+ flag[j] = 0;
+ if (prev[j] == 0)
+ head = next[j];
+ else
+ next[prev[j]] = next[j];
+ if (next[j] == 0)
+ ;
+ else
+ prev[next[j]] = prev[j];
+ /* decrease row counts */
+ for (k = 1; k <= len; k++)
+ { i = cind[k];
+ xassert(1 <= i && i <= m);
+ xassert(cnt[i] > 0);
+ cnt[i]--;
+ if (cnt[i] == 1)
+ { /* new singleton appeared in i-th row; determine number
+ * of corresponding column (it is the only active column
+ * in this row) */
+ len2 = mat(info, +i, rind, rval);
+ xassert(0 <= len2 && len2 <= n);
+ ks = 0;
+ for (kk = 1; kk <= len2; kk++)
+ { jj = rind[kk];
+ xassert(1 <= jj && jj <= n);
+ if (flag[jj])
+ { xassert(ks == 0);
+ ks = kk;
+ }
+ }
+ xassert(ks > 0);
+ /* a[i,jj] is new row singleton */
+ jj = rind[ks];
+ if (flag[jj] != 2)
+ { /* include jj-th column in the singleton list */
+ flag[jj] = 2;
+ list[++ns] = jj;
+ }
+ }
+ }
+ }
+ /* now all row counts should be zero */
+ for (i = 1; i <= m; i++)
+ xassert(cnt[i] == 0);
+ /* deallocate working arrays */
+ tfree(cind);
+ tfree(cval);
+ tfree(rind);
+ tfree(rval);
+ tfree(ptr);
+ tfree(list);
+ tfree(prev);
+ tfree(next);
+ tfree(big);
+ tfree(flag);
+ return size;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/triang.h b/test/monniaux/glpk-4.65/src/misc/triang.h
new file mode 100644
index 00000000..1e50d44d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/triang.h
@@ -0,0 +1,34 @@
+/* triang.h (find maximal triangular part of rectangular matrix) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#ifndef TRIANG_H
+#define TRIANG_H
+
+#define triang _glp_triang
+int triang(int m, int n, int (*mat)(void *info, int k, int ind[],
+ double val[]), void *info, double tol, int rn[], int cn[]);
+/* find maximal triangular part of rectangular matrix */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/wclique.c b/test/monniaux/glpk-4.65/src/misc/wclique.c
new file mode 100644
index 00000000..5daa69cf
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/wclique.c
@@ -0,0 +1,242 @@
+/* wclique.c (maximum weight clique, Ostergard's algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Two subroutines sub() and wclique() below are intended to find a
+* maximum weight clique in a given undirected graph. These subroutines
+* are slightly modified version of the program WCLIQUE developed by
+* Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based
+* on ideas from the article "P. R. J. Ostergard, A new algorithm for
+* the maximum-weight clique problem, submitted for publication", which
+* in turn is a generalization of the algorithm for unweighted graphs
+* presented in "P. R. J. Ostergard, A fast algorithm for the maximum
+* clique problem, submitted for publication".
+*
+* USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE.
+*
+* Changes were made by Andrew Makhorin <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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "wclique.h"
+
+/***********************************************************************
+* NAME
+*
+* wclique - find maximum weight clique with Ostergard's algorithm
+*
+* SYNOPSIS
+*
+* #include "wclique.h"
+* int wclique(int n, const int w[], const unsigned char a[],
+* int ind[]);
+*
+* DESCRIPTION
+*
+* The routine wclique finds a maximum weight clique in an undirected
+* graph with Ostergard's algorithm.
+*
+* INPUT PARAMETERS
+*
+* n is the number of vertices, n > 0.
+*
+* w[i], i = 1,...,n, is a weight of vertex i.
+*
+* a[*] is the strict (without main diagonal) lower triangle of the
+* graph adjacency matrix in packed format.
+*
+* OUTPUT PARAMETER
+*
+* ind[k], k = 1,...,size, is the number of a vertex included in the
+* clique found, 1 <= ind[k] <= n, where size is the number of vertices
+* in the clique returned on exit.
+*
+* RETURNS
+*
+* The routine returns the clique size, i.e. the number of vertices in
+* the clique. */
+
+struct csa
+{ /* common storage area */
+ int n;
+ /* number of vertices */
+ const int *wt; /* int wt[0:n-1]; */
+ /* weights */
+ const unsigned char *a;
+ /* adjacency matrix (packed lower triangle without main diag.) */
+ int record;
+ /* weight of best clique */
+ int rec_level;
+ /* number of vertices in best clique */
+ int *rec; /* int rec[0:n-1]; */
+ /* best clique so far */
+ int *clique; /* int clique[0:n-1]; */
+ /* table for pruning */
+ int *set; /* int set[0:n-1]; */
+ /* current clique */
+};
+
+#define n (csa->n)
+#define wt (csa->wt)
+#define a (csa->a)
+#define record (csa->record)
+#define rec_level (csa->rec_level)
+#define rec (csa->rec)
+#define clique (csa->clique)
+#define set (csa->set)
+
+#if 0
+static int is_edge(struct csa *csa, int i, int j)
+{ /* if there is arc (i,j), the routine returns true; otherwise
+ * false; 0 <= i, j < n */
+ int k;
+ xassert(0 <= i && i < n);
+ xassert(0 <= j && j < n);
+ if (i == j) return 0;
+ if (i < j) k = i, i = j, j = k;
+ k = (i * (i - 1)) / 2 + j;
+ return a[k / CHAR_BIT] &
+ (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
+}
+#else
+#define is_edge(csa, i, j) ((i) == (j) ? 0 : \
+ (i) > (j) ? is_edge1(i, j) : is_edge1(j, i))
+#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j))
+#define is_edge2(k) (a[(k) / CHAR_BIT] & \
+ (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT)))
+#endif
+
+static void sub(struct csa *csa, int ct, int table[], int level,
+ int weight, int l_weight)
+{ int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable;
+ newtable = xcalloc(n, sizeof(int));
+ if (ct <= 0)
+ { /* 0 or 1 elements left; include these */
+ if (ct == 0)
+ { set[level++] = table[0];
+ weight += l_weight;
+ }
+ if (weight > record)
+ { record = weight;
+ rec_level = level;
+ for (i = 0; i < level; i++) rec[i] = set[i];
+ }
+ goto done;
+ }
+ for (i = ct; i >= 0; i--)
+ { if ((level == 0) && (i < ct)) goto done;
+ k = table[i];
+ if ((level > 0) && (clique[k] <= (record - weight)))
+ goto done; /* prune */
+ set[level] = k;
+ curr_weight = weight + wt[k];
+ l_weight -= wt[k];
+ if (l_weight <= (record - curr_weight))
+ goto done; /* prune */
+ p1 = newtable;
+ p2 = table;
+ left_weight = 0;
+ while (p2 < table + i)
+ { j = *p2++;
+ if (is_edge(csa, j, k))
+ { *p1++ = j;
+ left_weight += wt[j];
+ }
+ }
+ if (left_weight <= (record - curr_weight)) continue;
+ sub(csa, p1 - newtable - 1, newtable, level + 1, curr_weight,
+ left_weight);
+ }
+done: xfree(newtable);
+ return;
+}
+
+int wclique(int n_, const int w[], const unsigned char a_[], int ind[])
+{ struct csa csa_, *csa = &csa_;
+ int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos;
+ double timer;
+ n = n_;
+ xassert(n > 0);
+ wt = &w[1];
+ a = a_;
+ record = 0;
+ rec_level = 0;
+ rec = &ind[1];
+ clique = xcalloc(n, sizeof(int));
+ set = xcalloc(n, sizeof(int));
+ used = xcalloc(n, sizeof(int));
+ nwt = xcalloc(n, sizeof(int));
+ pos = xcalloc(n, sizeof(int));
+ /* start timer */
+ timer = xtime();
+ /* order vertices */
+ for (i = 0; i < n; i++)
+ { nwt[i] = 0;
+ for (j = 0; j < n; j++)
+ if (is_edge(csa, i, j)) nwt[i] += wt[j];
+ }
+ for (i = 0; i < n; i++)
+ used[i] = 0;
+ for (i = n-1; i >= 0; i--)
+ { max_wt = -1;
+ max_nwt = -1;
+ for (j = 0; j < n; j++)
+ { if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt
+ && nwt[j] > max_nwt)))
+ { max_wt = wt[j];
+ max_nwt = nwt[j];
+ p = j;
+ }
+ }
+ pos[i] = p;
+ used[p] = 1;
+ for (j = 0; j < n; j++)
+ if ((!used[j]) && (j != p) && (is_edge(csa, p, j)))
+ nwt[j] -= wt[p];
+ }
+ /* main routine */
+ wth = 0;
+ for (i = 0; i < n; i++)
+ { wth += wt[pos[i]];
+ sub(csa, i, pos, 0, 0, wth);
+ clique[pos[i]] = record;
+ if (xdifftime(xtime(), timer) >= 5.0 - 0.001)
+ { /* print current record and reset timer */
+ xprintf("level = %d (%d); best = %d\n", i+1, n, record);
+ timer = xtime();
+ }
+ }
+ xfree(clique);
+ xfree(set);
+ xfree(used);
+ xfree(nwt);
+ xfree(pos);
+ /* return the solution found */
+ for (i = 1; i <= rec_level; i++) ind[i]++;
+ return rec_level;
+}
+
+#undef n
+#undef wt
+#undef a
+#undef record
+#undef rec_level
+#undef rec
+#undef clique
+#undef set
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/wclique.h b/test/monniaux/glpk-4.65/src/misc/wclique.h
new file mode 100644
index 00000000..d52dc805
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/wclique.h
@@ -0,0 +1,33 @@
+/* wclique.h (maximum weight clique, Ostergard's algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2013 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/>.
+***********************************************************************/
+
+#ifndef WCLIQUE_H
+#define WCLIQUE_H
+
+#define wclique _glp_wclique
+int wclique(int n, const int w[], const unsigned char a[], int ind[]);
+/* find maximum weight clique with Ostergard's algorithm */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/wclique1.c b/test/monniaux/glpk-4.65/src/misc/wclique1.c
new file mode 100644
index 00000000..a3d89542
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/wclique1.c
@@ -0,0 +1,317 @@
+/* wclique1.c (maximum weight clique, greedy heuristic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "wclique1.h"
+
+/***********************************************************************
+* NAME
+*
+* wclique1 - find maximum weight clique with greedy heuristic
+*
+* SYNOPSIS
+*
+* #include "wclique1.h"
+* int wclique1(int n, const double w[],
+* int (*func)(void *info, int i, int ind[]), void *info, int c[]);
+*
+* DESCRIPTION
+*
+* The routine wclique1 implements a sequential greedy heuristic to
+* find maximum weight clique in a given (undirected) graph G = (V, E).
+*
+* The parameter n specifies the number of vertices |V| in the graph,
+* n >= 0.
+*
+* The array w specifies vertex weights in locations w[i], i = 1,...,n.
+* All weights must be non-negative.
+*
+* The formal routine func specifies the graph. For a given vertex i,
+* 1 <= i <= n, it stores indices of all vertices adjacent to vertex i
+* in locations ind[1], ..., ind[deg], where deg is the degree of
+* vertex i, 0 <= deg < n, returned on exit. Note that self-loops and
+* multiple edges are not allowed.
+*
+* The parameter info is a cookie passed to the routine func.
+*
+* On exit the routine wclique1 stores vertex indices included in
+* the clique found to locations c[1], ..., c[size], where size is the
+* clique size returned by the routine, 0 <= size <= n.
+*
+* RETURNS
+*
+* The routine wclique1 returns the size of the clique found. */
+
+struct vertex { int i; double cw; };
+
+static int CDECL fcmp(const void *xx, const void *yy)
+{ const struct vertex *x = xx, *y = yy;
+ if (x->cw > y->cw) return -1;
+ if (x->cw < y->cw) return +1;
+ return 0;
+}
+
+int wclique1(int n, const double w[],
+ int (*func)(void *info, int i, int ind[]), void *info, int c[])
+{ struct vertex *v_list;
+ int deg, c_size, d_size, i, j, k, kk, l, *ind, *c_list, *d_list,
+ size = 0;
+ double c_wght, d_wght, *sw, best = 0.0;
+ char *d_flag, *skip;
+ /* perform sanity checks */
+ xassert(n >= 0);
+ for (i = 1; i <= n; i++)
+ xassert(w[i] >= 0.0);
+ /* if the graph is empty, nothing to do */
+ if (n == 0) goto done;
+ /* allocate working arrays */
+ ind = xcalloc(1+n, sizeof(int));
+ v_list = xcalloc(1+n, sizeof(struct vertex));
+ c_list = xcalloc(1+n, sizeof(int));
+ d_list = xcalloc(1+n, sizeof(int));
+ d_flag = xcalloc(1+n, sizeof(char));
+ skip = xcalloc(1+n, sizeof(char));
+ sw = xcalloc(1+n, sizeof(double));
+ /* build the vertex list */
+ for (i = 1; i <= n; i++)
+ { v_list[i].i = i;
+ /* compute the cumulative weight of each vertex i, which is
+ * cw[i] = w[i] + sum{j : (i,j) in E} w[j] */
+ v_list[i].cw = w[i];
+ deg = func(info, i, ind);
+ xassert(0 <= deg && deg < n);
+ for (k = 1; k <= deg; k++)
+ { j = ind[k];
+ xassert(1 <= j && j <= n && j != i);
+ v_list[i].cw += w[j];
+ }
+ }
+ /* sort the vertex list to access vertices in descending order of
+ * cumulative weights */
+ qsort(&v_list[1], n, sizeof(struct vertex), fcmp);
+ /* initially all vertices are unmarked */
+ memset(&skip[1], 0, sizeof(char) * n);
+ /* clear flags of all vertices */
+ memset(&d_flag[1], 0, sizeof(char) * n);
+ /* look through all vertices of the graph */
+ for (l = 1; l <= n; l++)
+ { /* take vertex i */
+ i = v_list[l].i;
+ /* if this vertex was already included in one of previosuly
+ * constructed cliques, skip it */
+ if (skip[i]) continue;
+ /* use vertex i as the initial clique vertex */
+ c_size = 1; /* size of current clique */
+ c_list[1] = i; /* list of vertices in current clique */
+ c_wght = w[i]; /* weight of current clique */
+ /* determine the candidate set D = { j : (i,j) in E } */
+ d_size = func(info, i, d_list);
+ xassert(0 <= d_size && d_size < n);
+ d_wght = 0.0; /* weight of set D */
+ for (k = 1; k <= d_size; k++)
+ { j = d_list[k];
+ xassert(1 <= j && j <= n && j != i);
+ xassert(!d_flag[j]);
+ d_flag[j] = 1;
+ d_wght += w[j];
+ }
+ /* check an upper bound to the final clique weight */
+ if (c_wght + d_wght < best + 1e-5 * (1.0 + fabs(best)))
+ { /* skip constructing the current clique */
+ goto next;
+ }
+ /* compute the summary weight of each vertex i in D, which is
+ * sw[i] = w[i] + sum{j in D and (i,j) in E} w[j] */
+ for (k = 1; k <= d_size; k++)
+ { i = d_list[k];
+ sw[i] = w[i];
+ /* consider vertices adjacent to vertex i */
+ deg = func(info, i, ind);
+ xassert(0 <= deg && deg < n);
+ for (kk = 1; kk <= deg; kk++)
+ { j = ind[kk];
+ xassert(1 <= j && j <= n && j != i);
+ if (d_flag[j]) sw[i] += w[j];
+ }
+ }
+ /* grow the current clique by adding vertices from D */
+ while (d_size > 0)
+ { /* check an upper bound to the final clique weight */
+ if (c_wght + d_wght < best + 1e-5 * (1.0 + fabs(best)))
+ { /* skip constructing the current clique */
+ goto next;
+ }
+ /* choose vertex i in D having maximal summary weight */
+ i = d_list[1];
+ for (k = 2; k <= d_size; k++)
+ { j = d_list[k];
+ if (sw[i] < sw[j]) i = j;
+ }
+ /* include vertex i in the current clique */
+ c_size++;
+ c_list[c_size] = i;
+ c_wght += w[i];
+ /* remove all vertices not adjacent to vertex i, including
+ * vertex i itself, from the candidate set D */
+ deg = func(info, i, ind);
+ xassert(0 <= deg && deg < n);
+ for (k = 1; k <= deg; k++)
+ { j = ind[k];
+ xassert(1 <= j && j <= n && j != i);
+ /* vertex j is adjacent to vertex i */
+ if (d_flag[j])
+ { xassert(d_flag[j] == 1);
+ /* mark vertex j to keep it in D */
+ d_flag[j] = 2;
+ }
+ }
+ kk = d_size, d_size = 0;
+ for (k = 1; k <= kk; k++)
+ { j = d_list[k];
+ if (d_flag[j] == 1)
+ { /* remove vertex j from D */
+ d_flag[j] = 0;
+ d_wght -= w[j];
+ }
+ else if (d_flag[j] == 2)
+ { /* keep vertex j in D */
+ d_list[++d_size] = j;
+ d_flag[j] = 1;
+ }
+ else
+ xassert(d_flag != d_flag);
+ }
+ }
+ /* the current clique has been completely constructed */
+ if (best < c_wght)
+ { best = c_wght;
+ size = c_size;
+ xassert(1 <= size && size <= n);
+ memcpy(&c[1], &c_list[1], size * sizeof(int));
+ }
+next: /* mark the current clique vertices in order not to use them
+ * as initial vertices anymore */
+ for (k = 1; k <= c_size; k++)
+ skip[c_list[k]] = 1;
+ /* set D can be non-empty, so clean up vertex flags */
+ for (k = 1; k <= d_size; k++)
+ d_flag[d_list[k]] = 0;
+ }
+ /* free working arrays */
+ xfree(ind);
+ xfree(v_list);
+ xfree(c_list);
+ xfree(d_list);
+ xfree(d_flag);
+ xfree(skip);
+ xfree(sw);
+done: /* return to the calling program */
+ return size;
+}
+
+/**********************************************************************/
+
+#ifdef GLP_TEST
+#include "glpk.h"
+#include "rng.h"
+
+typedef struct { double w; } v_data;
+
+#define weight(v) (((v_data *)((v)->data))->w)
+
+glp_graph *G;
+
+char *flag;
+
+int func(void *info, int i, int ind[])
+{ glp_arc *e;
+ int j, k, deg = 0;
+ xassert(info == NULL);
+ xassert(1 <= i && i <= G->nv);
+ /* look through incoming arcs */
+ for (e = G->v[i]->in; e != NULL; e = e->h_next)
+ { j = e->tail->i; /* j->i */
+ if (j != i && !flag[j]) ind[++deg] = j, flag[j] = 1;
+ }
+ /* look through outgoing arcs */
+ for (e = G->v[i]->out; e != NULL; e = e->t_next)
+ { j = e->head->i; /* i->j */
+ if (j != i && !flag[j]) ind[++deg] = j, flag[j] = 1;
+ }
+ /* clear the flag array */
+ xassert(deg < G->nv);
+ for (k = 1; k <= deg; k++) flag[ind[k]] = 0;
+ return deg;
+}
+
+int main(int argc, char *argv[])
+{ RNG *rand;
+ int i, k, kk, size, *c, *ind, deg;
+ double *w, sum, t;
+ /* read graph in DIMACS format */
+ G = glp_create_graph(sizeof(v_data), 0);
+ xassert(argc == 2);
+ xassert(glp_read_ccdata(G, offsetof(v_data, w), argv[1]) == 0);
+ /* print the number of connected components */
+ xprintf("nc = %d\n", glp_weak_comp(G, -1));
+ /* assign random weights unformly distributed in [1,100] */
+ w = xcalloc(1+G->nv, sizeof(double));
+ rand = rng_create_rand();
+ for (i = 1; i <= G->nv; i++)
+#if 0
+ w[i] = weight(G->v[i]) = 1.0;
+#else
+ w[i] = weight(G->v[i]) = rng_unif_rand(rand, 100) + 1;
+#endif
+ /* write graph in DIMACS format */
+ xassert(glp_write_ccdata(G, offsetof(v_data, w), "graph") == 0);
+ /* find maximum weight clique */
+ c = xcalloc(1+G->nv, sizeof(int));
+ flag = xcalloc(1+G->nv, sizeof(char));
+ memset(&flag[1], 0, G->nv);
+ t = xtime();
+ size = wclique1(G->nv, w, func, NULL, c);
+ xprintf("Time used: %.1f s\n", xdifftime(xtime(), t));
+ /* check the clique found */
+ ind = xcalloc(1+G->nv, sizeof(int));
+ for (k = 1; k <= size; k++)
+ { i = c[k];
+ deg = func(NULL, i, ind);
+ for (kk = 1; kk <= size; kk++)
+ flag[c[kk]] = 1;
+ flag[i] = 0;
+ for (kk = 1; kk <= deg; kk++)
+ flag[ind[kk]] = 0;
+ for (kk = 1; kk <= size; kk++)
+ xassert(flag[c[kk]] == 0);
+ }
+ /* compute the clique weight */
+ sum = 0.0;
+ for (i = 1; i <= size; i++)
+ sum += w[c[i]];
+ xprintf("size = %d; sum = %g\n", size, sum);
+ return 0;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/misc/wclique1.h b/test/monniaux/glpk-4.65/src/misc/wclique1.h
new file mode 100644
index 00000000..588f3257
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/misc/wclique1.h
@@ -0,0 +1,34 @@
+/* wclique1.h (maximum weight clique, greedy heuristic) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2012-2013 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/>.
+***********************************************************************/
+
+#ifndef WCLIQUE1_H
+#define WCLIQUE1_H
+
+#define wclique1 _glp_wclique1
+int wclique1(int n, const double w[],
+ int (*func)(void *info, int i, int ind[]), void *info, int c[]);
+/* find maximum weight clique with greedy heuristic */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/mpl/mpl.h b/test/monniaux/glpk-4.65/src/mpl/mpl.h
new file mode 100644
index 00000000..ddd31543
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/mpl/mpl.h
@@ -0,0 +1,2598 @@
+/* mpl.h (GNU MathProg translator) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2003-2016 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/>.
+***********************************************************************/
+
+#ifndef MPL_H
+#define MPL_H
+
+#include "avl.h"
+#include "dmp.h"
+#include "env.h"
+#include "misc.h"
+#include "rng.h"
+
+#if 0 /* 22/I-2013 */
+typedef struct MPL MPL;
+#else
+typedef struct glp_tran MPL;
+#endif
+typedef char STRING;
+typedef struct SYMBOL SYMBOL;
+typedef struct TUPLE TUPLE;
+typedef struct ARRAY ELEMSET;
+typedef struct ELEMVAR ELEMVAR;
+typedef struct FORMULA FORMULA;
+typedef struct ELEMCON ELEMCON;
+typedef union VALUE VALUE;
+typedef struct ARRAY ARRAY;
+typedef struct MEMBER MEMBER;
+#if 1
+/* many C compilers have DOMAIN declared in <math.h> :( */
+#undef DOMAIN
+#define DOMAIN DOMAIN1
+#endif
+typedef struct DOMAIN DOMAIN;
+typedef struct DOMAIN_BLOCK DOMAIN_BLOCK;
+typedef struct DOMAIN_SLOT DOMAIN_SLOT;
+typedef struct SET SET;
+typedef struct WITHIN WITHIN;
+typedef struct GADGET GADGET;
+typedef struct PARAMETER PARAMETER;
+typedef struct CONDITION CONDITION;
+typedef struct VARIABLE VARIABLE;
+typedef struct CONSTRAINT CONSTRAINT;
+typedef struct TABLE TABLE;
+typedef struct TABARG TABARG;
+typedef struct TABFLD TABFLD;
+typedef struct TABIN TABIN;
+typedef struct TABOUT TABOUT;
+typedef struct TABDCA TABDCA;
+typedef union OPERANDS OPERANDS;
+typedef struct ARG_LIST ARG_LIST;
+typedef struct CODE CODE;
+typedef struct CHECK CHECK;
+typedef struct DISPLAY DISPLAY;
+typedef struct DISPLAY1 DISPLAY1;
+typedef struct PRINTF PRINTF;
+typedef struct PRINTF1 PRINTF1;
+typedef struct FOR FOR;
+typedef struct STATEMENT STATEMENT;
+typedef struct TUPLE SLICE;
+
+/**********************************************************************/
+/* * * TRANSLATOR DATABASE * * */
+/**********************************************************************/
+
+#define A_BINARY 101 /* something binary */
+#define A_CHECK 102 /* check statement */
+#define A_CONSTRAINT 103 /* model constraint */
+#define A_DISPLAY 104 /* display statement */
+#define A_ELEMCON 105 /* elemental constraint/objective */
+#define A_ELEMSET 106 /* elemental set */
+#define A_ELEMVAR 107 /* elemental variable */
+#define A_EXPRESSION 108 /* expression */
+#define A_FOR 109 /* for statement */
+#define A_FORMULA 110 /* formula */
+#define A_INDEX 111 /* dummy index */
+#define A_INPUT 112 /* input table */
+#define A_INTEGER 113 /* something integer */
+#define A_LOGICAL 114 /* something logical */
+#define A_MAXIMIZE 115 /* objective has to be maximized */
+#define A_MINIMIZE 116 /* objective has to be minimized */
+#define A_NONE 117 /* nothing */
+#define A_NUMERIC 118 /* something numeric */
+#define A_OUTPUT 119 /* output table */
+#define A_PARAMETER 120 /* model parameter */
+#define A_PRINTF 121 /* printf statement */
+#define A_SET 122 /* model set */
+#define A_SOLVE 123 /* solve statement */
+#define A_SYMBOLIC 124 /* something symbolic */
+#define A_TABLE 125 /* data table */
+#define A_TUPLE 126 /* n-tuple */
+#define A_VARIABLE 127 /* model variable */
+
+#define MAX_LENGTH 100
+/* maximal length of any symbolic value (this includes symbolic names,
+ numeric and string literals, and all symbolic values that may appear
+ during the evaluation phase) */
+
+#define CONTEXT_SIZE 60
+/* size of the context queue, in characters */
+
+#define OUTBUF_SIZE 1024
+/* size of the output buffer, in characters */
+
+#if 0 /* 22/I-2013 */
+struct MPL
+#else
+struct glp_tran
+#endif
+{ /* translator database */
+ /*--------------------------------------------------------------*/
+ /* scanning segment */
+ int line;
+ /* number of the current text line */
+ int c;
+ /* the current character or EOF */
+ int token;
+ /* the current token: */
+#define T_EOF 201 /* end of file */
+#define T_NAME 202 /* symbolic name (model section only) */
+#define T_SYMBOL 203 /* symbol (data section only) */
+#define T_NUMBER 204 /* numeric literal */
+#define T_STRING 205 /* string literal */
+#define T_AND 206 /* and && */
+#define T_BY 207 /* by */
+#define T_CROSS 208 /* cross */
+#define T_DIFF 209 /* diff */
+#define T_DIV 210 /* div */
+#define T_ELSE 211 /* else */
+#define T_IF 212 /* if */
+#define T_IN 213 /* in */
+#define T_INFINITY 214 /* Infinity */
+#define T_INTER 215 /* inter */
+#define T_LESS 216 /* less */
+#define T_MOD 217 /* mod */
+#define T_NOT 218 /* not ! */
+#define T_OR 219 /* or || */
+#define T_SPTP 220 /* s.t. */
+#define T_SYMDIFF 221 /* symdiff */
+#define T_THEN 222 /* then */
+#define T_UNION 223 /* union */
+#define T_WITHIN 224 /* within */
+#define T_PLUS 225 /* + */
+#define T_MINUS 226 /* - */
+#define T_ASTERISK 227 /* * */
+#define T_SLASH 228 /* / */
+#define T_POWER 229 /* ^ ** */
+#define T_LT 230 /* < */
+#define T_LE 231 /* <= */
+#define T_EQ 232 /* = == */
+#define T_GE 233 /* >= */
+#define T_GT 234 /* > */
+#define T_NE 235 /* <> != */
+#define T_CONCAT 236 /* & */
+#define T_BAR 237 /* | */
+#define T_POINT 238 /* . */
+#define T_COMMA 239 /* , */
+#define T_COLON 240 /* : */
+#define T_SEMICOLON 241 /* ; */
+#define T_ASSIGN 242 /* := */
+#define T_DOTS 243 /* .. */
+#define T_LEFT 244 /* ( */
+#define T_RIGHT 245 /* ) */
+#define T_LBRACKET 246 /* [ */
+#define T_RBRACKET 247 /* ] */
+#define T_LBRACE 248 /* { */
+#define T_RBRACE 249 /* } */
+#define T_APPEND 250 /* >> */
+#define T_TILDE 251 /* ~ */
+#define T_INPUT 252 /* <- */
+ int imlen;
+ /* length of the current token */
+ char *image; /* char image[MAX_LENGTH+1]; */
+ /* image of the current token */
+ double value;
+ /* value of the current token (for T_NUMBER only) */
+ int b_token;
+ /* the previous token */
+ int b_imlen;
+ /* length of the previous token */
+ char *b_image; /* char b_image[MAX_LENGTH+1]; */
+ /* image of the previous token */
+ double b_value;
+ /* value of the previous token (if token is T_NUMBER) */
+ int f_dots;
+ /* if this flag is set, the next token should be recognized as
+ T_DOTS, not as T_POINT */
+ int f_scan;
+ /* if this flag is set, the next token is already scanned */
+ int f_token;
+ /* the next token */
+ int f_imlen;
+ /* length of the next token */
+ char *f_image; /* char f_image[MAX_LENGTH+1]; */
+ /* image of the next token */
+ double f_value;
+ /* value of the next token (if token is T_NUMBER) */
+ char *context; /* char context[CONTEXT_SIZE]; */
+ /* context circular queue (not null-terminated!) */
+ int c_ptr;
+ /* pointer to the current position in the context queue */
+ int flag_d;
+ /* if this flag is set, the data section is being processed */
+ /*--------------------------------------------------------------*/
+ /* translating segment */
+ DMP *pool;
+ /* memory pool used to allocate all data instances created during
+ the translation phase */
+ AVL *tree;
+ /* symbolic name table:
+ node.type = A_INDEX => node.link -> DOMAIN_SLOT
+ node.type = A_SET => node.link -> SET
+ node.type = A_PARAMETER => node.link -> PARAMETER
+ node.type = A_VARIABLE => node.link -> VARIABLE
+ node.type = A_CONSTRANT => node.link -> CONSTRAINT */
+ STATEMENT *model;
+ /* linked list of model statements in the original order */
+ int flag_x;
+ /* if this flag is set, the current token being left parenthesis
+ begins a slice that allows recognizing any undeclared symbolic
+ names as dummy indices; this flag is automatically reset once
+ the next token has been scanned */
+ int as_within;
+ /* the warning "in understood as within" has been issued */
+ int as_in;
+ /* the warning "within understood as in" has been issued */
+ int as_binary;
+ /* the warning "logical understood as binary" has been issued */
+ int flag_s;
+ /* if this flag is set, the solve statement has been parsed */
+ /*--------------------------------------------------------------*/
+ /* common segment */
+ DMP *strings;
+ /* memory pool to allocate STRING data structures */
+ DMP *symbols;
+ /* memory pool to allocate SYMBOL data structures */
+ DMP *tuples;
+ /* memory pool to allocate TUPLE data structures */
+ DMP *arrays;
+ /* memory pool to allocate ARRAY data structures */
+ DMP *members;
+ /* memory pool to allocate MEMBER data structures */
+ DMP *elemvars;
+ /* memory pool to allocate ELEMVAR data structures */
+ DMP *formulae;
+ /* memory pool to allocate FORMULA data structures */
+ DMP *elemcons;
+ /* memory pool to allocate ELEMCON data structures */
+ ARRAY *a_list;
+ /* linked list of all arrays in the database */
+ char *sym_buf; /* char sym_buf[255+1]; */
+ /* working buffer used by the routine format_symbol */
+ char *tup_buf; /* char tup_buf[255+1]; */
+ /* working buffer used by the routine format_tuple */
+ /*--------------------------------------------------------------*/
+ /* generating/postsolving segment */
+ RNG *rand;
+ /* pseudo-random number generator */
+ int flag_p;
+ /* if this flag is set, the postsolving phase is in effect */
+ STATEMENT *stmt;
+ /* model statement being currently executed */
+ TABDCA *dca;
+ /* pointer to table driver communication area for table statement
+ currently executed */
+ int m;
+ /* number of rows in the problem, m >= 0 */
+ int n;
+ /* number of columns in the problem, n >= 0 */
+ ELEMCON **row; /* ELEMCON *row[1+m]; */
+ /* row[0] is not used;
+ row[i] is elemental constraint or objective, which corresponds
+ to i-th row of the problem, 1 <= i <= m */
+ ELEMVAR **col; /* ELEMVAR *col[1+n]; */
+ /* col[0] is not used;
+ col[j] is elemental variable, which corresponds to j-th column
+ of the problem, 1 <= j <= n */
+ /*--------------------------------------------------------------*/
+ /* input/output segment */
+ glp_file *in_fp;
+ /* stream assigned to the input text file */
+ char *in_file;
+ /* name of the input text file */
+ glp_file *out_fp;
+ /* stream assigned to the output text file used to write all data
+ produced by display and printf statements; NULL means the data
+ should be sent to stdout via the routine xprintf */
+ char *out_file;
+ /* name of the output text file */
+#if 0 /* 08/XI-2009 */
+ char *out_buf; /* char out_buf[OUTBUF_SIZE] */
+ /* buffer to accumulate output data */
+ int out_cnt;
+ /* count of data bytes stored in the output buffer */
+#endif
+ glp_file *prt_fp;
+ /* stream assigned to the print text file; may be NULL */
+ char *prt_file;
+ /* name of the output print file */
+ /*--------------------------------------------------------------*/
+ /* solver interface segment */
+ jmp_buf jump;
+ /* jump address for non-local go to in case of error */
+ int phase;
+ /* phase of processing:
+ 0 - database is being or has been initialized
+ 1 - model section is being or has been read
+ 2 - data section is being or has been read
+ 3 - model is being or has been generated/postsolved
+ 4 - model processing error has occurred */
+ char *mod_file;
+ /* name of the input text file, which contains model section */
+ char *mpl_buf; /* char mpl_buf[255+1]; */
+ /* working buffer used by some interface routines */
+};
+
+/**********************************************************************/
+/* * * PROCESSING MODEL SECTION * * */
+/**********************************************************************/
+
+#define alloc(type) ((type *)dmp_get_atomv(mpl->pool, sizeof(type)))
+/* allocate atom of given type */
+
+#define enter_context _glp_mpl_enter_context
+void enter_context(MPL *mpl);
+/* enter current token into context queue */
+
+#define print_context _glp_mpl_print_context
+void print_context(MPL *mpl);
+/* print current content of context queue */
+
+#define get_char _glp_mpl_get_char
+void get_char(MPL *mpl);
+/* scan next character from input text file */
+
+#define append_char _glp_mpl_append_char
+void append_char(MPL *mpl);
+/* append character to current token */
+
+#define get_token _glp_mpl_get_token
+void get_token(MPL *mpl);
+/* scan next token from input text file */
+
+#define unget_token _glp_mpl_unget_token
+void unget_token(MPL *mpl);
+/* return current token back to input stream */
+
+#define is_keyword _glp_mpl_is_keyword
+int is_keyword(MPL *mpl, char *keyword);
+/* check if current token is given non-reserved keyword */
+
+#define is_reserved _glp_mpl_is_reserved
+int is_reserved(MPL *mpl);
+/* check if current token is reserved keyword */
+
+#define make_code _glp_mpl_make_code
+CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim);
+/* generate pseudo-code (basic routine) */
+
+#define make_unary _glp_mpl_make_unary
+CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim);
+/* generate pseudo-code for unary operation */
+
+#define make_binary _glp_mpl_make_binary
+CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
+ int dim);
+/* generate pseudo-code for binary operation */
+
+#define make_ternary _glp_mpl_make_ternary
+CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
+ int type, int dim);
+/* generate pseudo-code for ternary operation */
+
+#define numeric_literal _glp_mpl_numeric_literal
+CODE *numeric_literal(MPL *mpl);
+/* parse reference to numeric literal */
+
+#define string_literal _glp_mpl_string_literal
+CODE *string_literal(MPL *mpl);
+/* parse reference to string literal */
+
+#define create_arg_list _glp_mpl_create_arg_list
+ARG_LIST *create_arg_list(MPL *mpl);
+/* create empty operands list */
+
+#define expand_arg_list _glp_mpl_expand_arg_list
+ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x);
+/* append operand to operands list */
+
+#define arg_list_len _glp_mpl_arg_list_len
+int arg_list_len(MPL *mpl, ARG_LIST *list);
+/* determine length of operands list */
+
+#define subscript_list _glp_mpl_subscript_list
+ARG_LIST *subscript_list(MPL *mpl);
+/* parse subscript list */
+
+#define object_reference _glp_mpl_object_reference
+CODE *object_reference(MPL *mpl);
+/* parse reference to named object */
+
+#define numeric_argument _glp_mpl_numeric_argument
+CODE *numeric_argument(MPL *mpl, char *func);
+/* parse argument passed to built-in function */
+
+#define symbolic_argument _glp_mpl_symbolic_argument
+CODE *symbolic_argument(MPL *mpl, char *func);
+
+#define elemset_argument _glp_mpl_elemset_argument
+CODE *elemset_argument(MPL *mpl, char *func);
+
+#define function_reference _glp_mpl_function_reference
+CODE *function_reference(MPL *mpl);
+/* parse reference to built-in function */
+
+#define create_domain _glp_mpl_create_domain
+DOMAIN *create_domain(MPL *mpl);
+/* create empty domain */
+
+#define create_block _glp_mpl_create_block
+DOMAIN_BLOCK *create_block(MPL *mpl);
+/* create empty domain block */
+
+#define append_block _glp_mpl_append_block
+void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block);
+/* append domain block to specified domain */
+
+#define append_slot _glp_mpl_append_slot
+DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
+ CODE *code);
+/* create and append new slot to domain block */
+
+#define expression_list _glp_mpl_expression_list
+CODE *expression_list(MPL *mpl);
+/* parse expression list */
+
+#define literal_set _glp_mpl_literal_set
+CODE *literal_set(MPL *mpl, CODE *code);
+/* parse literal set */
+
+#define indexing_expression _glp_mpl_indexing_expression
+DOMAIN *indexing_expression(MPL *mpl);
+/* parse indexing expression */
+
+#define close_scope _glp_mpl_close_scope
+void close_scope(MPL *mpl, DOMAIN *domain);
+/* close scope of indexing expression */
+
+#define iterated_expression _glp_mpl_iterated_expression
+CODE *iterated_expression(MPL *mpl);
+/* parse iterated expression */
+
+#define domain_arity _glp_mpl_domain_arity
+int domain_arity(MPL *mpl, DOMAIN *domain);
+/* determine arity of domain */
+
+#define set_expression _glp_mpl_set_expression
+CODE *set_expression(MPL *mpl);
+/* parse set expression */
+
+#define branched_expression _glp_mpl_branched_expression
+CODE *branched_expression(MPL *mpl);
+/* parse conditional expression */
+
+#define primary_expression _glp_mpl_primary_expression
+CODE *primary_expression(MPL *mpl);
+/* parse primary expression */
+
+#define error_preceding _glp_mpl_error_preceding
+void error_preceding(MPL *mpl, char *opstr);
+/* raise error if preceding operand has wrong type */
+
+#define error_following _glp_mpl_error_following
+void error_following(MPL *mpl, char *opstr);
+/* raise error if following operand has wrong type */
+
+#define error_dimension _glp_mpl_error_dimension
+void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2);
+/* raise error if operands have different dimension */
+
+#define expression_0 _glp_mpl_expression_0
+CODE *expression_0(MPL *mpl);
+/* parse expression of level 0 */
+
+#define expression_1 _glp_mpl_expression_1
+CODE *expression_1(MPL *mpl);
+/* parse expression of level 1 */
+
+#define expression_2 _glp_mpl_expression_2
+CODE *expression_2(MPL *mpl);
+/* parse expression of level 2 */
+
+#define expression_3 _glp_mpl_expression_3
+CODE *expression_3(MPL *mpl);
+/* parse expression of level 3 */
+
+#define expression_4 _glp_mpl_expression_4
+CODE *expression_4(MPL *mpl);
+/* parse expression of level 4 */
+
+#define expression_5 _glp_mpl_expression_5
+CODE *expression_5(MPL *mpl);
+/* parse expression of level 5 */
+
+#define expression_6 _glp_mpl_expression_6
+CODE *expression_6(MPL *mpl);
+/* parse expression of level 6 */
+
+#define expression_7 _glp_mpl_expression_7
+CODE *expression_7(MPL *mpl);
+/* parse expression of level 7 */
+
+#define expression_8 _glp_mpl_expression_8
+CODE *expression_8(MPL *mpl);
+/* parse expression of level 8 */
+
+#define expression_9 _glp_mpl_expression_9
+CODE *expression_9(MPL *mpl);
+/* parse expression of level 9 */
+
+#define expression_10 _glp_mpl_expression_10
+CODE *expression_10(MPL *mpl);
+/* parse expression of level 10 */
+
+#define expression_11 _glp_mpl_expression_11
+CODE *expression_11(MPL *mpl);
+/* parse expression of level 11 */
+
+#define expression_12 _glp_mpl_expression_12
+CODE *expression_12(MPL *mpl);
+/* parse expression of level 12 */
+
+#define expression_13 _glp_mpl_expression_13
+CODE *expression_13(MPL *mpl);
+/* parse expression of level 13 */
+
+#define set_statement _glp_mpl_set_statement
+SET *set_statement(MPL *mpl);
+/* parse set statement */
+
+#define parameter_statement _glp_mpl_parameter_statement
+PARAMETER *parameter_statement(MPL *mpl);
+/* parse parameter statement */
+
+#define variable_statement _glp_mpl_variable_statement
+VARIABLE *variable_statement(MPL *mpl);
+/* parse variable statement */
+
+#define constraint_statement _glp_mpl_constraint_statement
+CONSTRAINT *constraint_statement(MPL *mpl);
+/* parse constraint statement */
+
+#define objective_statement _glp_mpl_objective_statement
+CONSTRAINT *objective_statement(MPL *mpl);
+/* parse objective statement */
+
+#define table_statement _glp_mpl_table_statement
+TABLE *table_statement(MPL *mpl);
+/* parse table statement */
+
+#define solve_statement _glp_mpl_solve_statement
+void *solve_statement(MPL *mpl);
+/* parse solve statement */
+
+#define check_statement _glp_mpl_check_statement
+CHECK *check_statement(MPL *mpl);
+/* parse check statement */
+
+#define display_statement _glp_mpl_display_statement
+DISPLAY *display_statement(MPL *mpl);
+/* parse display statement */
+
+#define printf_statement _glp_mpl_printf_statement
+PRINTF *printf_statement(MPL *mpl);
+/* parse printf statement */
+
+#define for_statement _glp_mpl_for_statement
+FOR *for_statement(MPL *mpl);
+/* parse for statement */
+
+#define end_statement _glp_mpl_end_statement
+void end_statement(MPL *mpl);
+/* parse end statement */
+
+#define simple_statement _glp_mpl_simple_statement
+STATEMENT *simple_statement(MPL *mpl, int spec);
+/* parse simple statement */
+
+#define model_section _glp_mpl_model_section
+void model_section(MPL *mpl);
+/* parse model section */
+
+/**********************************************************************/
+/* * * PROCESSING DATA SECTION * * */
+/**********************************************************************/
+
+#if 2 + 2 == 5
+struct SLICE /* see TUPLE */
+{ /* component of slice; the slice itself is associated with its
+ first component; slices are similar to n-tuples with exception
+ that some slice components (which are indicated by asterisks)
+ don't refer to any symbols */
+ SYMBOL *sym;
+ /* symbol, which this component refers to; can be NULL */
+ SLICE *next;
+ /* the next component of slice */
+};
+#endif
+
+#define create_slice _glp_mpl_create_slice
+SLICE *create_slice(MPL *mpl);
+/* create slice */
+
+#define expand_slice _glp_mpl_expand_slice
+SLICE *expand_slice
+( MPL *mpl,
+ SLICE *slice, /* destroyed */
+ SYMBOL *sym /* destroyed */
+);
+/* append new component to slice */
+
+#define slice_dimen _glp_mpl_slice_dimen
+int slice_dimen
+( MPL *mpl,
+ SLICE *slice /* not changed */
+);
+/* determine dimension of slice */
+
+#define slice_arity _glp_mpl_slice_arity
+int slice_arity
+( MPL *mpl,
+ SLICE *slice /* not changed */
+);
+/* determine arity of slice */
+
+#define fake_slice _glp_mpl_fake_slice
+SLICE *fake_slice(MPL *mpl, int dim);
+/* create fake slice of all asterisks */
+
+#define delete_slice _glp_mpl_delete_slice
+void delete_slice
+( MPL *mpl,
+ SLICE *slice /* destroyed */
+);
+/* delete slice */
+
+#define is_number _glp_mpl_is_number
+int is_number(MPL *mpl);
+/* check if current token is number */
+
+#define is_symbol _glp_mpl_is_symbol
+int is_symbol(MPL *mpl);
+/* check if current token is symbol */
+
+#define is_literal _glp_mpl_is_literal
+int is_literal(MPL *mpl, char *literal);
+/* check if current token is given symbolic literal */
+
+#define read_number _glp_mpl_read_number
+double read_number(MPL *mpl);
+/* read number */
+
+#define read_symbol _glp_mpl_read_symbol
+SYMBOL *read_symbol(MPL *mpl);
+/* read symbol */
+
+#define read_slice _glp_mpl_read_slice
+SLICE *read_slice
+( MPL *mpl,
+ char *name, /* not changed */
+ int dim
+);
+/* read slice */
+
+#define select_set _glp_mpl_select_set
+SET *select_set
+( MPL *mpl,
+ char *name /* not changed */
+);
+/* select set to saturate it with elemental sets */
+
+#define simple_format _glp_mpl_simple_format
+void simple_format
+( MPL *mpl,
+ SET *set, /* not changed */
+ MEMBER *memb, /* modified */
+ SLICE *slice /* not changed */
+);
+/* read set data block in simple format */
+
+#define matrix_format _glp_mpl_matrix_format
+void matrix_format
+( MPL *mpl,
+ SET *set, /* not changed */
+ MEMBER *memb, /* modified */
+ SLICE *slice, /* not changed */
+ int tr
+);
+/* read set data block in matrix format */
+
+#define set_data _glp_mpl_set_data
+void set_data(MPL *mpl);
+/* read set data */
+
+#define select_parameter _glp_mpl_select_parameter
+PARAMETER *select_parameter
+( MPL *mpl,
+ char *name /* not changed */
+);
+/* select parameter to saturate it with data */
+
+#define set_default _glp_mpl_set_default
+void set_default
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ SYMBOL *altval /* destroyed */
+);
+/* set default parameter value */
+
+#define read_value _glp_mpl_read_value
+MEMBER *read_value
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple /* destroyed */
+);
+/* read value and assign it to parameter member */
+
+#define plain_format _glp_mpl_plain_format
+void plain_format
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ SLICE *slice /* not changed */
+);
+/* read parameter data block in plain format */
+
+#define tabular_format _glp_mpl_tabular_format
+void tabular_format
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ SLICE *slice, /* not changed */
+ int tr
+);
+/* read parameter data block in tabular format */
+
+#define tabbing_format _glp_mpl_tabbing_format
+void tabbing_format
+( MPL *mpl,
+ SYMBOL *altval /* not changed */
+);
+/* read parameter data block in tabbing format */
+
+#define parameter_data _glp_mpl_parameter_data
+void parameter_data(MPL *mpl);
+/* read parameter data */
+
+#define data_section _glp_mpl_data_section
+void data_section(MPL *mpl);
+/* read data section */
+
+/**********************************************************************/
+/* * * FLOATING-POINT NUMBERS * * */
+/**********************************************************************/
+
+#define fp_add _glp_mpl_fp_add
+double fp_add(MPL *mpl, double x, double y);
+/* floating-point addition */
+
+#define fp_sub _glp_mpl_fp_sub
+double fp_sub(MPL *mpl, double x, double y);
+/* floating-point subtraction */
+
+#define fp_less _glp_mpl_fp_less
+double fp_less(MPL *mpl, double x, double y);
+/* floating-point non-negative subtraction */
+
+#define fp_mul _glp_mpl_fp_mul
+double fp_mul(MPL *mpl, double x, double y);
+/* floating-point multiplication */
+
+#define fp_div _glp_mpl_fp_div
+double fp_div(MPL *mpl, double x, double y);
+/* floating-point division */
+
+#define fp_idiv _glp_mpl_fp_idiv
+double fp_idiv(MPL *mpl, double x, double y);
+/* floating-point quotient of exact division */
+
+#define fp_mod _glp_mpl_fp_mod
+double fp_mod(MPL *mpl, double x, double y);
+/* floating-point remainder of exact division */
+
+#define fp_power _glp_mpl_fp_power
+double fp_power(MPL *mpl, double x, double y);
+/* floating-point exponentiation (raise to power) */
+
+#define fp_exp _glp_mpl_fp_exp
+double fp_exp(MPL *mpl, double x);
+/* floating-point base-e exponential */
+
+#define fp_log _glp_mpl_fp_log
+double fp_log(MPL *mpl, double x);
+/* floating-point natural logarithm */
+
+#define fp_log10 _glp_mpl_fp_log10
+double fp_log10(MPL *mpl, double x);
+/* floating-point common (decimal) logarithm */
+
+#define fp_sqrt _glp_mpl_fp_sqrt
+double fp_sqrt(MPL *mpl, double x);
+/* floating-point square root */
+
+#define fp_sin _glp_mpl_fp_sin
+double fp_sin(MPL *mpl, double x);
+/* floating-point trigonometric sine */
+
+#define fp_cos _glp_mpl_fp_cos
+double fp_cos(MPL *mpl, double x);
+/* floating-point trigonometric cosine */
+
+#define fp_tan _glp_mpl_fp_tan
+double fp_tan(MPL *mpl, double x);
+/* floating-point trigonometric tangent */
+
+#define fp_atan _glp_mpl_fp_atan
+double fp_atan(MPL *mpl, double x);
+/* floating-point trigonometric arctangent */
+
+#define fp_atan2 _glp_mpl_fp_atan2
+double fp_atan2(MPL *mpl, double y, double x);
+/* floating-point trigonometric arctangent */
+
+#define fp_round _glp_mpl_fp_round
+double fp_round(MPL *mpl, double x, double n);
+/* round floating-point value to n fractional digits */
+
+#define fp_trunc _glp_mpl_fp_trunc
+double fp_trunc(MPL *mpl, double x, double n);
+/* truncate floating-point value to n fractional digits */
+
+/**********************************************************************/
+/* * * PSEUDO-RANDOM NUMBER GENERATORS * * */
+/**********************************************************************/
+
+#define fp_irand224 _glp_mpl_fp_irand224
+double fp_irand224(MPL *mpl);
+/* pseudo-random integer in the range [0, 2^24) */
+
+#define fp_uniform01 _glp_mpl_fp_uniform01
+double fp_uniform01(MPL *mpl);
+/* pseudo-random number in the range [0, 1) */
+
+#define fp_uniform _glp_mpl_uniform
+double fp_uniform(MPL *mpl, double a, double b);
+/* pseudo-random number in the range [a, b) */
+
+#define fp_normal01 _glp_mpl_fp_normal01
+double fp_normal01(MPL *mpl);
+/* Gaussian random variate with mu = 0 and sigma = 1 */
+
+#define fp_normal _glp_mpl_fp_normal
+double fp_normal(MPL *mpl, double mu, double sigma);
+/* Gaussian random variate with specified mu and sigma */
+
+/**********************************************************************/
+/* * * DATE/TIME * * */
+/**********************************************************************/
+
+#define fn_gmtime _glp_mpl_fn_gmtime
+double fn_gmtime(MPL *mpl);
+/* obtain the current calendar time (UTC) */
+
+#define fn_str2time _glp_mpl_fn_str2time
+double fn_str2time(MPL *mpl, const char *str, const char *fmt);
+/* convert character string to the calendar time */
+
+#define fn_time2str _glp_mpl_fn_time2str
+void fn_time2str(MPL *mpl, char *str, double t, const char *fmt);
+/* convert the calendar time to character string */
+
+/**********************************************************************/
+/* * * CHARACTER STRINGS * * */
+/**********************************************************************/
+
+#define create_string _glp_mpl_create_string
+STRING *create_string
+( MPL *mpl,
+ char buf[MAX_LENGTH+1] /* not changed */
+);
+/* create character string */
+
+#define copy_string _glp_mpl_copy_string
+STRING *copy_string
+( MPL *mpl,
+ STRING *str /* not changed */
+);
+/* make copy of character string */
+
+#define compare_strings _glp_mpl_compare_strings
+int compare_strings
+( MPL *mpl,
+ STRING *str1, /* not changed */
+ STRING *str2 /* not changed */
+);
+/* compare one character string with another */
+
+#define fetch_string _glp_mpl_fetch_string
+char *fetch_string
+( MPL *mpl,
+ STRING *str, /* not changed */
+ char buf[MAX_LENGTH+1] /* modified */
+);
+/* extract content of character string */
+
+#define delete_string _glp_mpl_delete_string
+void delete_string
+( MPL *mpl,
+ STRING *str /* destroyed */
+);
+/* delete character string */
+
+/**********************************************************************/
+/* * * SYMBOLS * * */
+/**********************************************************************/
+
+struct SYMBOL
+{ /* symbol (numeric or abstract quantity) */
+ double num;
+ /* numeric value of symbol (used only if str == NULL) */
+ STRING *str;
+ /* abstract value of symbol (used only if str != NULL) */
+};
+
+#define create_symbol_num _glp_mpl_create_symbol_num
+SYMBOL *create_symbol_num(MPL *mpl, double num);
+/* create symbol of numeric type */
+
+#define create_symbol_str _glp_mpl_create_symbol_str
+SYMBOL *create_symbol_str
+( MPL *mpl,
+ STRING *str /* destroyed */
+);
+/* create symbol of abstract type */
+
+#define copy_symbol _glp_mpl_copy_symbol
+SYMBOL *copy_symbol
+( MPL *mpl,
+ SYMBOL *sym /* not changed */
+);
+/* make copy of symbol */
+
+#define compare_symbols _glp_mpl_compare_symbols
+int compare_symbols
+( MPL *mpl,
+ SYMBOL *sym1, /* not changed */
+ SYMBOL *sym2 /* not changed */
+);
+/* compare one symbol with another */
+
+#define delete_symbol _glp_mpl_delete_symbol
+void delete_symbol
+( MPL *mpl,
+ SYMBOL *sym /* destroyed */
+);
+/* delete symbol */
+
+#define format_symbol _glp_mpl_format_symbol
+char *format_symbol
+( MPL *mpl,
+ SYMBOL *sym /* not changed */
+);
+/* format symbol for displaying or printing */
+
+#define concat_symbols _glp_mpl_concat_symbols
+SYMBOL *concat_symbols
+( MPL *mpl,
+ SYMBOL *sym1, /* destroyed */
+ SYMBOL *sym2 /* destroyed */
+);
+/* concatenate one symbol with another */
+
+/**********************************************************************/
+/* * * N-TUPLES * * */
+/**********************************************************************/
+
+struct TUPLE
+{ /* component of n-tuple; the n-tuple itself is associated with
+ its first component; (note that 0-tuple has no components) */
+ SYMBOL *sym;
+ /* symbol, which the component refers to; cannot be NULL */
+ TUPLE *next;
+ /* the next component of n-tuple */
+};
+
+#define create_tuple _glp_mpl_create_tuple
+TUPLE *create_tuple(MPL *mpl);
+/* create n-tuple */
+
+#define expand_tuple _glp_mpl_expand_tuple
+TUPLE *expand_tuple
+( MPL *mpl,
+ TUPLE *tuple, /* destroyed */
+ SYMBOL *sym /* destroyed */
+);
+/* append symbol to n-tuple */
+
+#define tuple_dimen _glp_mpl_tuple_dimen
+int tuple_dimen
+( MPL *mpl,
+ TUPLE *tuple /* not changed */
+);
+/* determine dimension of n-tuple */
+
+#define copy_tuple _glp_mpl_copy_tuple
+TUPLE *copy_tuple
+( MPL *mpl,
+ TUPLE *tuple /* not changed */
+);
+/* make copy of n-tuple */
+
+#define compare_tuples _glp_mpl_compare_tuples
+int compare_tuples
+( MPL *mpl,
+ TUPLE *tuple1, /* not changed */
+ TUPLE *tuple2 /* not changed */
+);
+/* compare one n-tuple with another */
+
+#define build_subtuple _glp_mpl_build_subtuple
+TUPLE *build_subtuple
+( MPL *mpl,
+ TUPLE *tuple, /* not changed */
+ int dim
+);
+/* build subtuple of given n-tuple */
+
+#define delete_tuple _glp_mpl_delete_tuple
+void delete_tuple
+( MPL *mpl,
+ TUPLE *tuple /* destroyed */
+);
+/* delete n-tuple */
+
+#define format_tuple _glp_mpl_format_tuple
+char *format_tuple
+( MPL *mpl,
+ int c,
+ TUPLE *tuple /* not changed */
+);
+/* format n-tuple for displaying or printing */
+
+/**********************************************************************/
+/* * * ELEMENTAL SETS * * */
+/**********************************************************************/
+
+#if 2 + 2 == 5
+struct ELEMSET /* see ARRAY */
+{ /* elemental set of n-tuples; formally it is a "value" assigned
+ to members of model sets (like numbers and symbols, which are
+ values assigned to members of model parameters); note that a
+ simple model set is not an elemental set, it is 0-dimensional
+ array, the only member of which (if it exists) is assigned an
+ elemental set */
+#endif
+
+#define create_elemset _glp_mpl_create_elemset
+ELEMSET *create_elemset(MPL *mpl, int dim);
+/* create elemental set */
+
+#define find_tuple _glp_mpl_find_tuple
+MEMBER *find_tuple
+( MPL *mpl,
+ ELEMSET *set, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* check if elemental set contains given n-tuple */
+
+#define add_tuple _glp_mpl_add_tuple
+MEMBER *add_tuple
+( MPL *mpl,
+ ELEMSET *set, /* modified */
+ TUPLE *tuple /* destroyed */
+);
+/* add new n-tuple to elemental set */
+
+#define check_then_add _glp_mpl_check_then_add
+MEMBER *check_then_add
+( MPL *mpl,
+ ELEMSET *set, /* modified */
+ TUPLE *tuple /* destroyed */
+);
+/* check and add new n-tuple to elemental set */
+
+#define copy_elemset _glp_mpl_copy_elemset
+ELEMSET *copy_elemset
+( MPL *mpl,
+ ELEMSET *set /* not changed */
+);
+/* make copy of elemental set */
+
+#define delete_elemset _glp_mpl_delete_elemset
+void delete_elemset
+( MPL *mpl,
+ ELEMSET *set /* destroyed */
+);
+/* delete elemental set */
+
+#define arelset_size _glp_mpl_arelset_size
+int arelset_size(MPL *mpl, double t0, double tf, double dt);
+/* compute size of "arithmetic" elemental set */
+
+#define arelset_member _glp_mpl_arelset_member
+double arelset_member(MPL *mpl, double t0, double tf, double dt, int j);
+/* compute member of "arithmetic" elemental set */
+
+#define create_arelset _glp_mpl_create_arelset
+ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt);
+/* create "arithmetic" elemental set */
+
+#define set_union _glp_mpl_set_union
+ELEMSET *set_union
+( MPL *mpl,
+ ELEMSET *X, /* destroyed */
+ ELEMSET *Y /* destroyed */
+);
+/* union of two elemental sets */
+
+#define set_diff _glp_mpl_set_diff
+ELEMSET *set_diff
+( MPL *mpl,
+ ELEMSET *X, /* destroyed */
+ ELEMSET *Y /* destroyed */
+);
+/* difference between two elemental sets */
+
+#define set_symdiff _glp_mpl_set_symdiff
+ELEMSET *set_symdiff
+( MPL *mpl,
+ ELEMSET *X, /* destroyed */
+ ELEMSET *Y /* destroyed */
+);
+/* symmetric difference between two elemental sets */
+
+#define set_inter _glp_mpl_set_inter
+ELEMSET *set_inter
+( MPL *mpl,
+ ELEMSET *X, /* destroyed */
+ ELEMSET *Y /* destroyed */
+);
+/* intersection of two elemental sets */
+
+#define set_cross _glp_mpl_set_cross
+ELEMSET *set_cross
+( MPL *mpl,
+ ELEMSET *X, /* destroyed */
+ ELEMSET *Y /* destroyed */
+);
+/* cross (Cartesian) product of two elemental sets */
+
+/**********************************************************************/
+/* * * ELEMENTAL VARIABLES * * */
+/**********************************************************************/
+
+struct ELEMVAR
+{ /* elemental variable; formally it is a "value" assigned to
+ members of model variables (like numbers and symbols, which
+ are values assigned to members of model parameters) */
+ int j;
+ /* LP column number assigned to this elemental variable */
+ VARIABLE *var;
+ /* model variable, which contains this elemental variable */
+ MEMBER *memb;
+ /* array member, which is assigned this elemental variable */
+ double lbnd;
+ /* lower bound */
+ double ubnd;
+ /* upper bound */
+ double temp;
+ /* working quantity used in operations on linear forms; normally
+ it contains floating-point zero */
+#if 1 /* 15/V-2010 */
+ int stat;
+ double prim, dual;
+ /* solution components provided by the solver */
+#endif
+};
+
+/**********************************************************************/
+/* * * LINEAR FORMS * * */
+/**********************************************************************/
+
+struct FORMULA
+{ /* term of linear form c * x, where c is a coefficient, x is an
+ elemental variable; the linear form itself is the sum of terms
+ and is associated with its first term; (note that the linear
+ form may be empty that means the sum is equal to zero) */
+ double coef;
+ /* coefficient at elemental variable or constant term */
+ ELEMVAR *var;
+ /* reference to elemental variable; NULL means constant term */
+ FORMULA *next;
+ /* the next term of linear form */
+};
+
+#define constant_term _glp_mpl_constant_term
+FORMULA *constant_term(MPL *mpl, double coef);
+/* create constant term */
+
+#define single_variable _glp_mpl_single_variable
+FORMULA *single_variable
+( MPL *mpl,
+ ELEMVAR *var /* referenced */
+);
+/* create single variable */
+
+#define copy_formula _glp_mpl_copy_formula
+FORMULA *copy_formula
+( MPL *mpl,
+ FORMULA *form /* not changed */
+);
+/* make copy of linear form */
+
+#define delete_formula _glp_mpl_delete_formula
+void delete_formula
+( MPL *mpl,
+ FORMULA *form /* destroyed */
+);
+/* delete linear form */
+
+#define linear_comb _glp_mpl_linear_comb
+FORMULA *linear_comb
+( MPL *mpl,
+ double a, FORMULA *fx, /* destroyed */
+ double b, FORMULA *fy /* destroyed */
+);
+/* linear combination of two linear forms */
+
+#define remove_constant _glp_mpl_remove_constant
+FORMULA *remove_constant
+( MPL *mpl,
+ FORMULA *form, /* destroyed */
+ double *coef /* modified */
+);
+/* remove constant term from linear form */
+
+#define reduce_terms _glp_mpl_reduce_terms
+FORMULA *reduce_terms
+( MPL *mpl,
+ FORMULA *form /* destroyed */
+);
+/* reduce identical terms in linear form */
+
+/**********************************************************************/
+/* * * ELEMENTAL CONSTRAINTS * * */
+/**********************************************************************/
+
+struct ELEMCON
+{ /* elemental constraint; formally it is a "value" assigned to
+ members of model constraints (like numbers or symbols, which
+ are values assigned to members of model parameters) */
+ int i;
+ /* LP row number assigned to this elemental constraint */
+ CONSTRAINT *con;
+ /* model constraint, which contains this elemental constraint */
+ MEMBER *memb;
+ /* array member, which is assigned this elemental constraint */
+ FORMULA *form;
+ /* linear form */
+ double lbnd;
+ /* lower bound */
+ double ubnd;
+ /* upper bound */
+#if 1 /* 15/V-2010 */
+ int stat;
+ double prim, dual;
+ /* solution components provided by the solver */
+#endif
+};
+
+/**********************************************************************/
+/* * * GENERIC VALUES * * */
+/**********************************************************************/
+
+union VALUE
+{ /* generic value, which can be assigned to object member or be a
+ result of evaluation of expression */
+ /* indicator that specifies the particular type of generic value
+ is stored in the corresponding array or pseudo-code descriptor
+ and can be one of the following:
+ A_NONE - no value
+ A_NUMERIC - floating-point number
+ A_SYMBOLIC - symbol
+ A_LOGICAL - logical value
+ A_TUPLE - n-tuple
+ A_ELEMSET - elemental set
+ A_ELEMVAR - elemental variable
+ A_FORMULA - linear form
+ A_ELEMCON - elemental constraint */
+ void *none; /* null */
+ double num; /* value */
+ SYMBOL *sym; /* value */
+ int bit; /* value */
+ TUPLE *tuple; /* value */
+ ELEMSET *set; /* value */
+ ELEMVAR *var; /* reference */
+ FORMULA *form; /* value */
+ ELEMCON *con; /* reference */
+};
+
+#define delete_value _glp_mpl_delete_value
+void delete_value
+( MPL *mpl,
+ int type,
+ VALUE *value /* content destroyed */
+);
+/* delete generic value */
+
+/**********************************************************************/
+/* * * SYMBOLICALLY INDEXED ARRAYS * * */
+/**********************************************************************/
+
+struct ARRAY
+{ /* multi-dimensional array, a set of members indexed over simple
+ or compound sets of symbols; arrays are used to represent the
+ contents of model objects (i.e. sets, parameters, variables,
+ constraints, and objectives); arrays also are used as "values"
+ that are assigned to members of set objects, in which case the
+ array itself represents an elemental set */
+ int type;
+ /* type of generic values assigned to the array members:
+ A_NONE - none (members have no assigned values)
+ A_NUMERIC - floating-point numbers
+ A_SYMBOLIC - symbols
+ A_ELEMSET - elemental sets
+ A_ELEMVAR - elemental variables
+ A_ELEMCON - elemental constraints */
+ int dim;
+ /* dimension of the array that determines number of components in
+ n-tuples for all members of the array, dim >= 0; dim = 0 means
+ the array is 0-dimensional */
+ int size;
+ /* size of the array, i.e. number of its members */
+ MEMBER *head;
+ /* the first array member; NULL means the array is empty */
+ MEMBER *tail;
+ /* the last array member; NULL means the array is empty */
+ AVL *tree;
+ /* the search tree intended to find array members for logarithmic
+ time; NULL means the search tree doesn't exist */
+ ARRAY *prev;
+ /* the previous array in the translator database */
+ ARRAY *next;
+ /* the next array in the translator database */
+};
+
+struct MEMBER
+{ /* array member */
+ TUPLE *tuple;
+ /* n-tuple, which identifies the member; number of its components
+ is the same for all members within the array and determined by
+ the array dimension; duplicate members are not allowed */
+ MEMBER *next;
+ /* the next array member */
+ VALUE value;
+ /* generic value assigned to the member */
+};
+
+#define create_array _glp_mpl_create_array
+ARRAY *create_array(MPL *mpl, int type, int dim);
+/* create array */
+
+#define find_member _glp_mpl_find_member
+MEMBER *find_member
+( MPL *mpl,
+ ARRAY *array, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* find array member with given n-tuple */
+
+#define add_member _glp_mpl_add_member
+MEMBER *add_member
+( MPL *mpl,
+ ARRAY *array, /* modified */
+ TUPLE *tuple /* destroyed */
+);
+/* add new member to array */
+
+#define delete_array _glp_mpl_delete_array
+void delete_array
+( MPL *mpl,
+ ARRAY *array /* destroyed */
+);
+/* delete array */
+
+/**********************************************************************/
+/* * * DOMAINS AND DUMMY INDICES * * */
+/**********************************************************************/
+
+struct DOMAIN
+{ /* domain (a simple or compound set); syntactically domain looks
+ like '{ i in I, (j,k) in S, t in T : <predicate> }'; domains
+ are used to define sets, over which model objects are indexed,
+ and also as constituents of iterated operators */
+ DOMAIN_BLOCK *list;
+ /* linked list of domain blocks (in the example above such blocks
+ are 'i in I', '(j,k) in S', and 't in T'); this list cannot be
+ empty */
+ CODE *code;
+ /* pseudo-code for computing the logical predicate, which follows
+ the colon; NULL means no predicate is specified */
+};
+
+struct DOMAIN_BLOCK
+{ /* domain block; syntactically domain blocks look like 'i in I',
+ '(j,k) in S', and 't in T' in the example above (in the sequel
+ sets like I, S, and T are called basic sets) */
+ DOMAIN_SLOT *list;
+ /* linked list of domain slots (i.e. indexing positions); number
+ of slots in this list is the same as dimension of n-tuples in
+ the basic set; this list cannot be empty */
+ CODE *code;
+ /* pseudo-code for computing basic set; cannot be NULL */
+ TUPLE *backup;
+ /* if this n-tuple is not empty, current values of dummy indices
+ in the domain block are the same as components of this n-tuple
+ (note that this n-tuple may have larger dimension than number
+ of dummy indices in this block, in which case extra components
+ are ignored); this n-tuple is used to restore former values of
+ dummy indices, if they were changed due to recursive calls to
+ the domain block */
+ DOMAIN_BLOCK *next;
+ /* the next block in the same domain */
+};
+
+struct DOMAIN_SLOT
+{ /* domain slot; it specifies an individual indexing position and
+ defines the corresponding dummy index */
+ char *name;
+ /* symbolic name of the dummy index; null pointer means the dummy
+ index is not explicitly specified */
+ CODE *code;
+ /* pseudo-code for computing symbolic value, at which the dummy
+ index is bound; NULL means the dummy index is free within the
+ domain scope */
+ SYMBOL *value;
+ /* current value assigned to the dummy index; NULL means no value
+ is assigned at the moment */
+ CODE *list;
+ /* linked list of pseudo-codes with operation O_INDEX referring
+ to this slot; this linked list is used to invalidate resultant
+ values of the operation, which depend on this dummy index */
+ DOMAIN_SLOT *next;
+ /* the next slot in the same domain block */
+};
+
+#define assign_dummy_index _glp_mpl_assign_dummy_index
+void assign_dummy_index
+( MPL *mpl,
+ DOMAIN_SLOT *slot, /* modified */
+ SYMBOL *value /* not changed */
+);
+/* assign new value to dummy index */
+
+#define update_dummy_indices _glp_mpl_update_dummy_indices
+void update_dummy_indices
+( MPL *mpl,
+ DOMAIN_BLOCK *block /* not changed */
+);
+/* update current values of dummy indices */
+
+#define enter_domain_block _glp_mpl_enter_domain_block
+int enter_domain_block
+( MPL *mpl,
+ DOMAIN_BLOCK *block, /* not changed */
+ TUPLE *tuple, /* not changed */
+ void *info, void (*func)(MPL *mpl, void *info)
+);
+/* enter domain block */
+
+#define eval_within_domain _glp_mpl_eval_within_domain
+int eval_within_domain
+( MPL *mpl,
+ DOMAIN *domain, /* not changed */
+ TUPLE *tuple, /* not changed */
+ void *info, void (*func)(MPL *mpl, void *info)
+);
+/* perform evaluation within domain scope */
+
+#define loop_within_domain _glp_mpl_loop_within_domain
+void loop_within_domain
+( MPL *mpl,
+ DOMAIN *domain, /* not changed */
+ void *info, int (*func)(MPL *mpl, void *info)
+);
+/* perform iterations within domain scope */
+
+#define out_of_domain _glp_mpl_out_of_domain
+void out_of_domain
+( MPL *mpl,
+ char *name, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* raise domain exception */
+
+#define get_domain_tuple _glp_mpl_get_domain_tuple
+TUPLE *get_domain_tuple
+( MPL *mpl,
+ DOMAIN *domain /* not changed */
+);
+/* obtain current n-tuple from domain */
+
+#define clean_domain _glp_mpl_clean_domain
+void clean_domain(MPL *mpl, DOMAIN *domain);
+/* clean domain */
+
+/**********************************************************************/
+/* * * MODEL SETS * * */
+/**********************************************************************/
+
+struct SET
+{ /* model set */
+ char *name;
+ /* symbolic name; cannot be NULL */
+ char *alias;
+ /* alias; NULL means alias is not specified */
+ int dim; /* aka arity */
+ /* dimension (number of subscripts); dim = 0 means 0-dimensional
+ (unsubscripted) set, dim > 0 means set of sets */
+ DOMAIN *domain;
+ /* subscript domain; NULL for 0-dimensional set */
+ int dimen;
+ /* dimension of n-tuples, which members of this set consist of
+ (note that the model set itself is an array of elemental sets,
+ which are its members; so, don't confuse this dimension with
+ dimension of the model set); always non-zero */
+ WITHIN *within;
+ /* list of supersets, which restrict each member of the set to be
+ in every superset from this list; this list can be empty */
+ CODE *assign;
+ /* pseudo-code for computing assigned value; can be NULL */
+ CODE *option;
+ /* pseudo-code for computing default value; can be NULL */
+ GADGET *gadget;
+ /* plain set used to initialize the array of sets; can be NULL */
+ int data;
+ /* data status flag:
+ 0 - no data are provided in the data section
+ 1 - data are provided, but not checked yet
+ 2 - data are provided and have been checked */
+ ARRAY *array;
+ /* array of members, which are assigned elemental sets */
+};
+
+struct WITHIN
+{ /* restricting superset list entry */
+ CODE *code;
+ /* pseudo-code for computing the superset; cannot be NULL */
+ WITHIN *next;
+ /* the next entry for the same set or parameter */
+};
+
+struct GADGET
+{ /* plain set used to initialize the array of sets with data */
+ SET *set;
+ /* pointer to plain set; cannot be NULL */
+ int ind[20]; /* ind[dim+dimen]; */
+ /* permutation of integers 1, 2, ..., dim+dimen */
+};
+
+#define check_elem_set _glp_mpl_check_elem_set
+void check_elem_set
+( MPL *mpl,
+ SET *set, /* not changed */
+ TUPLE *tuple, /* not changed */
+ ELEMSET *refer /* not changed */
+);
+/* check elemental set assigned to set member */
+
+#define take_member_set _glp_mpl_take_member_set
+ELEMSET *take_member_set /* returns reference, not value */
+( MPL *mpl,
+ SET *set, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* obtain elemental set assigned to set member */
+
+#define eval_member_set _glp_mpl_eval_member_set
+ELEMSET *eval_member_set /* returns reference, not value */
+( MPL *mpl,
+ SET *set, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* evaluate elemental set assigned to set member */
+
+#define eval_whole_set _glp_mpl_eval_whole_set
+void eval_whole_set(MPL *mpl, SET *set);
+/* evaluate model set over entire domain */
+
+#define clean_set _glp_mpl_clean_set
+void clean_set(MPL *mpl, SET *set);
+/* clean model set */
+
+/**********************************************************************/
+/* * * MODEL PARAMETERS * * */
+/**********************************************************************/
+
+struct PARAMETER
+{ /* model parameter */
+ char *name;
+ /* symbolic name; cannot be NULL */
+ char *alias;
+ /* alias; NULL means alias is not specified */
+ int dim; /* aka arity */
+ /* dimension (number of subscripts); dim = 0 means 0-dimensional
+ (unsubscripted) parameter */
+ DOMAIN *domain;
+ /* subscript domain; NULL for 0-dimensional parameter */
+ int type;
+ /* parameter type:
+ A_NUMERIC - numeric
+ A_INTEGER - integer
+ A_BINARY - binary
+ A_SYMBOLIC - symbolic */
+ CONDITION *cond;
+ /* list of conditions, which restrict each parameter member to
+ satisfy to every condition from this list; this list is used
+ only for numeric parameters and can be empty */
+ WITHIN *in;
+ /* list of supersets, which restrict each parameter member to be
+ in every superset from this list; this list is used only for
+ symbolic parameters and can be empty */
+ CODE *assign;
+ /* pseudo-code for computing assigned value; can be NULL */
+ CODE *option;
+ /* pseudo-code for computing default value; can be NULL */
+ int data;
+ /* data status flag:
+ 0 - no data are provided in the data section
+ 1 - data are provided, but not checked yet
+ 2 - data are provided and have been checked */
+ SYMBOL *defval;
+ /* default value provided in the data section; can be NULL */
+ ARRAY *array;
+ /* array of members, which are assigned numbers or symbols */
+};
+
+struct CONDITION
+{ /* restricting condition list entry */
+ int rho;
+ /* flag that specifies the form of the condition:
+ O_LT - less than
+ O_LE - less than or equal to
+ O_EQ - equal to
+ O_GE - greater than or equal to
+ O_GT - greater than
+ O_NE - not equal to */
+ CODE *code;
+ /* pseudo-code for computing the reference value */
+ CONDITION *next;
+ /* the next entry for the same parameter */
+};
+
+#define check_value_num _glp_mpl_check_value_num
+void check_value_num
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple, /* not changed */
+ double value
+);
+/* check numeric value assigned to parameter member */
+
+#define take_member_num _glp_mpl_take_member_num
+double take_member_num
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* obtain numeric value assigned to parameter member */
+
+#define eval_member_num _glp_mpl_eval_member_num
+double eval_member_num
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* evaluate numeric value assigned to parameter member */
+
+#define check_value_sym _glp_mpl_check_value_sym
+void check_value_sym
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple, /* not changed */
+ SYMBOL *value /* not changed */
+);
+/* check symbolic value assigned to parameter member */
+
+#define take_member_sym _glp_mpl_take_member_sym
+SYMBOL *take_member_sym /* returns value, not reference */
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* obtain symbolic value assigned to parameter member */
+
+#define eval_member_sym _glp_mpl_eval_member_sym
+SYMBOL *eval_member_sym /* returns value, not reference */
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* evaluate symbolic value assigned to parameter member */
+
+#define eval_whole_par _glp_mpl_eval_whole_par
+void eval_whole_par(MPL *mpl, PARAMETER *par);
+/* evaluate model parameter over entire domain */
+
+#define clean_parameter _glp_mpl_clean_parameter
+void clean_parameter(MPL *mpl, PARAMETER *par);
+/* clean model parameter */
+
+/**********************************************************************/
+/* * * MODEL VARIABLES * * */
+/**********************************************************************/
+
+struct VARIABLE
+{ /* model variable */
+ char *name;
+ /* symbolic name; cannot be NULL */
+ char *alias;
+ /* alias; NULL means alias is not specified */
+ int dim; /* aka arity */
+ /* dimension (number of subscripts); dim = 0 means 0-dimensional
+ (unsubscripted) variable */
+ DOMAIN *domain;
+ /* subscript domain; NULL for 0-dimensional variable */
+ int type;
+ /* variable type:
+ A_NUMERIC - continuous
+ A_INTEGER - integer
+ A_BINARY - binary */
+ CODE *lbnd;
+ /* pseudo-code for computing lower bound; NULL means lower bound
+ is not specified */
+ CODE *ubnd;
+ /* pseudo-code for computing upper bound; NULL means upper bound
+ is not specified */
+ /* if both the pointers lbnd and ubnd refer to the same code, the
+ variable is fixed at the corresponding value */
+ ARRAY *array;
+ /* array of members, which are assigned elemental variables */
+};
+
+#define take_member_var _glp_mpl_take_member_var
+ELEMVAR *take_member_var /* returns reference */
+( MPL *mpl,
+ VARIABLE *var, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* obtain reference to elemental variable */
+
+#define eval_member_var _glp_mpl_eval_member_var
+ELEMVAR *eval_member_var /* returns reference */
+( MPL *mpl,
+ VARIABLE *var, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* evaluate reference to elemental variable */
+
+#define eval_whole_var _glp_mpl_eval_whole_var
+void eval_whole_var(MPL *mpl, VARIABLE *var);
+/* evaluate model variable over entire domain */
+
+#define clean_variable _glp_mpl_clean_variable
+void clean_variable(MPL *mpl, VARIABLE *var);
+/* clean model variable */
+
+/**********************************************************************/
+/* * * MODEL CONSTRAINTS AND OBJECTIVES * * */
+/**********************************************************************/
+
+struct CONSTRAINT
+{ /* model constraint or objective */
+ char *name;
+ /* symbolic name; cannot be NULL */
+ char *alias;
+ /* alias; NULL means alias is not specified */
+ int dim; /* aka arity */
+ /* dimension (number of subscripts); dim = 0 means 0-dimensional
+ (unsubscripted) constraint */
+ DOMAIN *domain;
+ /* subscript domain; NULL for 0-dimensional constraint */
+ int type;
+ /* constraint type:
+ A_CONSTRAINT - constraint
+ A_MINIMIZE - objective (minimization)
+ A_MAXIMIZE - objective (maximization) */
+ CODE *code;
+ /* pseudo-code for computing main linear form; cannot be NULL */
+ CODE *lbnd;
+ /* pseudo-code for computing lower bound; NULL means lower bound
+ is not specified */
+ CODE *ubnd;
+ /* pseudo-code for computing upper bound; NULL means upper bound
+ is not specified */
+ /* if both the pointers lbnd and ubnd refer to the same code, the
+ constraint has the form of equation */
+ ARRAY *array;
+ /* array of members, which are assigned elemental constraints */
+};
+
+#define take_member_con _glp_mpl_take_member_con
+ELEMCON *take_member_con /* returns reference */
+( MPL *mpl,
+ CONSTRAINT *con, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* obtain reference to elemental constraint */
+
+#define eval_member_con _glp_mpl_eval_member_con
+ELEMCON *eval_member_con /* returns reference */
+( MPL *mpl,
+ CONSTRAINT *con, /* not changed */
+ TUPLE *tuple /* not changed */
+);
+/* evaluate reference to elemental constraint */
+
+#define eval_whole_con _glp_mpl_eval_whole_con
+void eval_whole_con(MPL *mpl, CONSTRAINT *con);
+/* evaluate model constraint over entire domain */
+
+#define clean_constraint _glp_mpl_clean_constraint
+void clean_constraint(MPL *mpl, CONSTRAINT *con);
+/* clean model constraint */
+
+/**********************************************************************/
+/* * * DATA TABLES * * */
+/**********************************************************************/
+
+struct TABLE
+{ /* data table */
+ char *name;
+ /* symbolic name; cannot be NULL */
+ char *alias;
+ /* alias; NULL means alias is not specified */
+ int type;
+ /* table type:
+ A_INPUT - input table
+ A_OUTPUT - output table */
+ TABARG *arg;
+ /* argument list; cannot be empty */
+ union
+ { struct
+ { SET *set;
+ /* input set; NULL means the set is not specified */
+ TABFLD *fld;
+ /* field list; cannot be empty */
+ TABIN *list;
+ /* input list; can be empty */
+ } in;
+ struct
+ { DOMAIN *domain;
+ /* subscript domain; cannot be NULL */
+ TABOUT *list;
+ /* output list; cannot be empty */
+ } out;
+ } u;
+};
+
+struct TABARG
+{ /* table argument list entry */
+ CODE *code;
+ /* pseudo-code for computing the argument */
+ TABARG *next;
+ /* next entry for the same table */
+};
+
+struct TABFLD
+{ /* table field list entry */
+ char *name;
+ /* field name; cannot be NULL */
+ TABFLD *next;
+ /* next entry for the same table */
+};
+
+struct TABIN
+{ /* table input list entry */
+ PARAMETER *par;
+ /* parameter to be read; cannot be NULL */
+ char *name;
+ /* column name; cannot be NULL */
+ TABIN *next;
+ /* next entry for the same table */
+};
+
+struct TABOUT
+{ /* table output list entry */
+ CODE *code;
+ /* pseudo-code for computing the value to be written */
+ char *name;
+ /* column name; cannot be NULL */
+ TABOUT *next;
+ /* next entry for the same table */
+};
+
+struct TABDCA
+{ /* table driver communication area */
+ int id;
+ /* driver identifier (set by mpl_tab_drv_open) */
+ void *link;
+ /* driver link pointer (set by mpl_tab_drv_open) */
+ int na;
+ /* number of arguments */
+ char **arg; /* char *arg[1+ns]; */
+ /* arg[k], 1 <= k <= ns, is pointer to k-th argument */
+ int nf;
+ /* number of fields */
+ char **name; /* char *name[1+nc]; */
+ /* name[k], 1 <= k <= nc, is name of k-th field */
+ int *type; /* int type[1+nc]; */
+ /* type[k], 1 <= k <= nc, is type of k-th field:
+ '?' - value not assigned
+ 'N' - number
+ 'S' - character string */
+ double *num; /* double num[1+nc]; */
+ /* num[k], 1 <= k <= nc, is numeric value of k-th field */
+ char **str;
+ /* str[k], 1 <= k <= nc, is string value of k-th field */
+};
+
+#define mpl_tab_num_args _glp_mpl_tab_num_args
+int mpl_tab_num_args(TABDCA *dca);
+
+#define mpl_tab_get_arg _glp_mpl_tab_get_arg
+const char *mpl_tab_get_arg(TABDCA *dca, int k);
+
+#define mpl_tab_num_flds _glp_mpl_tab_num_flds
+int mpl_tab_num_flds(TABDCA *dca);
+
+#define mpl_tab_get_name _glp_mpl_tab_get_name
+const char *mpl_tab_get_name(TABDCA *dca, int k);
+
+#define mpl_tab_get_type _glp_mpl_tab_get_type
+int mpl_tab_get_type(TABDCA *dca, int k);
+
+#define mpl_tab_get_num _glp_mpl_tab_get_num
+double mpl_tab_get_num(TABDCA *dca, int k);
+
+#define mpl_tab_get_str _glp_mpl_tab_get_str
+const char *mpl_tab_get_str(TABDCA *dca, int k);
+
+#define mpl_tab_set_num _glp_mpl_tab_set_num
+void mpl_tab_set_num(TABDCA *dca, int k, double num);
+
+#define mpl_tab_set_str _glp_mpl_tab_set_str
+void mpl_tab_set_str(TABDCA *dca, int k, const char *str);
+
+#define mpl_tab_drv_open _glp_mpl_tab_drv_open
+void mpl_tab_drv_open(MPL *mpl, int mode);
+
+#define mpl_tab_drv_read _glp_mpl_tab_drv_read
+int mpl_tab_drv_read(MPL *mpl);
+
+#define mpl_tab_drv_write _glp_mpl_tab_drv_write
+void mpl_tab_drv_write(MPL *mpl);
+
+#define mpl_tab_drv_close _glp_mpl_tab_drv_close
+void mpl_tab_drv_close(MPL *mpl);
+
+/**********************************************************************/
+/* * * PSEUDO-CODE * * */
+/**********************************************************************/
+
+union OPERANDS
+{ /* operands that participate in pseudo-code operation (choice of
+ particular operands depends on the operation code) */
+ /*--------------------------------------------------------------*/
+ double num; /* O_NUMBER */
+ /* floaing-point number to be taken */
+ /*--------------------------------------------------------------*/
+ char *str; /* O_STRING */
+ /* character string to be taken */
+ /*--------------------------------------------------------------*/
+ struct /* O_INDEX */
+ { DOMAIN_SLOT *slot;
+ /* domain slot, which contains dummy index to be taken */
+ CODE *next;
+ /* the next pseudo-code with op = O_INDEX, which refers to the
+ same slot as this one; pointer to the beginning of this list
+ is stored in the corresponding domain slot */
+ } index;
+ /*--------------------------------------------------------------*/
+ struct /* O_MEMNUM, O_MEMSYM */
+ { PARAMETER *par;
+ /* model parameter, which contains member to be taken */
+ ARG_LIST *list;
+ /* list of subscripts; NULL for 0-dimensional parameter */
+ } par;
+ /*--------------------------------------------------------------*/
+ struct /* O_MEMSET */
+ { SET *set;
+ /* model set, which contains member to be taken */
+ ARG_LIST *list;
+ /* list of subscripts; NULL for 0-dimensional set */
+ } set;
+ /*--------------------------------------------------------------*/
+ struct /* O_MEMVAR */
+ { VARIABLE *var;
+ /* model variable, which contains member to be taken */
+ ARG_LIST *list;
+ /* list of subscripts; NULL for 0-dimensional variable */
+#if 1 /* 15/V-2010 */
+ int suff;
+ /* suffix specified: */
+#define DOT_NONE 0x00 /* none (means variable itself) */
+#define DOT_LB 0x01 /* .lb (lower bound) */
+#define DOT_UB 0x02 /* .ub (upper bound) */
+#define DOT_STATUS 0x03 /* .status (status) */
+#define DOT_VAL 0x04 /* .val (primal value) */
+#define DOT_DUAL 0x05 /* .dual (dual value) */
+#endif
+ } var;
+#if 1 /* 15/V-2010 */
+ /*--------------------------------------------------------------*/
+ struct /* O_MEMCON */
+ { CONSTRAINT *con;
+ /* model constraint, which contains member to be taken */
+ ARG_LIST *list;
+ /* list of subscripys; NULL for 0-dimensional constraint */
+ int suff;
+ /* suffix specified (see O_MEMVAR above) */
+ } con;
+#endif
+ /*--------------------------------------------------------------*/
+ ARG_LIST *list; /* O_TUPLE, O_MAKE, n-ary operations */
+ /* list of operands */
+ /*--------------------------------------------------------------*/
+ DOMAIN_BLOCK *slice; /* O_SLICE */
+ /* domain block, which specifies slice (i.e. n-tuple that contains
+ free dummy indices); this operation is never evaluated */
+ /*--------------------------------------------------------------*/
+ struct /* unary, binary, ternary operations */
+ { CODE *x;
+ /* pseudo-code for computing first operand */
+ CODE *y;
+ /* pseudo-code for computing second operand */
+ CODE *z;
+ /* pseudo-code for computing third operand */
+ } arg;
+ /*--------------------------------------------------------------*/
+ struct /* iterated operations */
+ { DOMAIN *domain;
+ /* domain, over which the operation is performed */
+ CODE *x;
+ /* pseudo-code for computing "integrand" */
+ } loop;
+ /*--------------------------------------------------------------*/
+};
+
+struct ARG_LIST
+{ /* operands list entry */
+ CODE *x;
+ /* pseudo-code for computing operand */
+ ARG_LIST *next;
+ /* the next operand of the same operation */
+};
+
+struct CODE
+{ /* pseudo-code (internal form of expressions) */
+ int op;
+ /* operation code: */
+#define O_NUMBER 301 /* take floating-point number */
+#define O_STRING 302 /* take character string */
+#define O_INDEX 303 /* take dummy index */
+#define O_MEMNUM 304 /* take member of numeric parameter */
+#define O_MEMSYM 305 /* take member of symbolic parameter */
+#define O_MEMSET 306 /* take member of set */
+#define O_MEMVAR 307 /* take member of variable */
+#define O_MEMCON 308 /* take member of constraint */
+#define O_TUPLE 309 /* make n-tuple */
+#define O_MAKE 310 /* make elemental set of n-tuples */
+#define O_SLICE 311 /* define domain block (dummy op) */
+ /* 0-ary operations --------------------*/
+#define O_IRAND224 312 /* pseudo-random in [0, 2^24-1] */
+#define O_UNIFORM01 313 /* pseudo-random in [0, 1) */
+#define O_NORMAL01 314 /* gaussian random, mu = 0, sigma = 1 */
+#define O_GMTIME 315 /* current calendar time (UTC) */
+ /* unary operations --------------------*/
+#define O_CVTNUM 316 /* conversion to numeric */
+#define O_CVTSYM 317 /* conversion to symbolic */
+#define O_CVTLOG 318 /* conversion to logical */
+#define O_CVTTUP 319 /* conversion to 1-tuple */
+#define O_CVTLFM 320 /* conversion to linear form */
+#define O_PLUS 321 /* unary plus */
+#define O_MINUS 322 /* unary minus */
+#define O_NOT 323 /* negation (logical "not") */
+#define O_ABS 324 /* absolute value */
+#define O_CEIL 325 /* round upward ("ceiling of x") */
+#define O_FLOOR 326 /* round downward ("floor of x") */
+#define O_EXP 327 /* base-e exponential */
+#define O_LOG 328 /* natural logarithm */
+#define O_LOG10 329 /* common (decimal) logarithm */
+#define O_SQRT 330 /* square root */
+#define O_SIN 331 /* trigonometric sine */
+#define O_COS 332 /* trigonometric cosine */
+#define O_TAN 333 /* trigonometric tangent */
+#define O_ATAN 334 /* trigonometric arctangent */
+#define O_ROUND 335 /* round to nearest integer */
+#define O_TRUNC 336 /* truncate to nearest integer */
+#define O_CARD 337 /* cardinality of set */
+#define O_LENGTH 338 /* length of symbolic value */
+ /* binary operations -------------------*/
+#define O_ADD 339 /* addition */
+#define O_SUB 340 /* subtraction */
+#define O_LESS 341 /* non-negative subtraction */
+#define O_MUL 342 /* multiplication */
+#define O_DIV 343 /* division */
+#define O_IDIV 344 /* quotient of exact division */
+#define O_MOD 345 /* remainder of exact division */
+#define O_POWER 346 /* exponentiation (raise to power) */
+#define O_ATAN2 347 /* trigonometric arctangent */
+#define O_ROUND2 348 /* round to n fractional digits */
+#define O_TRUNC2 349 /* truncate to n fractional digits */
+#define O_UNIFORM 350 /* pseudo-random in [a, b) */
+#define O_NORMAL 351 /* gaussian random, given mu and sigma */
+#define O_CONCAT 352 /* concatenation */
+#define O_LT 353 /* comparison on 'less than' */
+#define O_LE 354 /* comparison on 'not greater than' */
+#define O_EQ 355 /* comparison on 'equal to' */
+#define O_GE 356 /* comparison on 'not less than' */
+#define O_GT 357 /* comparison on 'greater than' */
+#define O_NE 358 /* comparison on 'not equal to' */
+#define O_AND 359 /* conjunction (logical "and") */
+#define O_OR 360 /* disjunction (logical "or") */
+#define O_UNION 361 /* union */
+#define O_DIFF 362 /* difference */
+#define O_SYMDIFF 363 /* symmetric difference */
+#define O_INTER 364 /* intersection */
+#define O_CROSS 365 /* cross (Cartesian) product */
+#define O_IN 366 /* test on 'x in Y' */
+#define O_NOTIN 367 /* test on 'x not in Y' */
+#define O_WITHIN 368 /* test on 'X within Y' */
+#define O_NOTWITHIN 369 /* test on 'X not within Y' */
+#define O_SUBSTR 370 /* substring */
+#define O_STR2TIME 371 /* convert string to time */
+#define O_TIME2STR 372 /* convert time to string */
+ /* ternary operations ------------------*/
+#define O_DOTS 373 /* build "arithmetic" set */
+#define O_FORK 374 /* if-then-else */
+#define O_SUBSTR3 375 /* substring */
+ /* n-ary operations --------------------*/
+#define O_MIN 376 /* minimal value (n-ary) */
+#define O_MAX 377 /* maximal value (n-ary) */
+ /* iterated operations -----------------*/
+#define O_SUM 378 /* summation */
+#define O_PROD 379 /* multiplication */
+#define O_MINIMUM 380 /* minimum */
+#define O_MAXIMUM 381 /* maximum */
+#define O_FORALL 382 /* conjunction (A-quantification) */
+#define O_EXISTS 383 /* disjunction (E-quantification) */
+#define O_SETOF 384 /* compute elemental set */
+#define O_BUILD 385 /* build elemental set */
+ OPERANDS arg;
+ /* operands that participate in the operation */
+ int type;
+ /* type of the resultant value:
+ A_NUMERIC - numeric
+ A_SYMBOLIC - symbolic
+ A_LOGICAL - logical
+ A_TUPLE - n-tuple
+ A_ELEMSET - elemental set
+ A_FORMULA - linear form */
+ int dim;
+ /* dimension of the resultant value; for A_TUPLE and A_ELEMSET it
+ is the dimension of the corresponding n-tuple(s) and cannot be
+ zero; for other resultant types it is always zero */
+ CODE *up;
+ /* parent pseudo-code, which refers to this pseudo-code as to its
+ operand; NULL means this pseudo-code has no parent and defines
+ an expression, which is not contained in another expression */
+ int vflag;
+ /* volatile flag; being set this flag means that this operation
+ has a side effect; for primary expressions this flag is set
+ directly by corresponding parsing routines (for example, if
+ primary expression is a reference to a function that generates
+ pseudo-random numbers); in other cases this flag is inherited
+ from operands */
+ int valid;
+ /* if this flag is set, the resultant value, which is a temporary
+ result of evaluating this operation on particular values of
+ operands, is valid; if this flag is clear, the resultant value
+ doesn't exist and therefore not valid; having been evaluated
+ the resultant value is stored here and not destroyed until the
+ dummy indices, which this value depends on, have been changed
+ (and if it doesn't depend on dummy indices at all, it is never
+ destroyed); thus, if the resultant value is valid, evaluating
+ routine can immediately take its copy not computing the result
+ from scratch; this mechanism is similar to moving invariants
+ out of loops and allows improving efficiency at the expense of
+ some extra memory needed to keep temporary results */
+ /* however, if the volatile flag (see above) is set, even if the
+ resultant value is valid, evaluating routine computes it as if
+ it were not valid, i.e. caching is not used in this case */
+ VALUE value;
+ /* resultant value in generic format */
+};
+
+#define eval_numeric _glp_mpl_eval_numeric
+double eval_numeric(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to determine numeric value */
+
+#define eval_symbolic _glp_mpl_eval_symbolic
+SYMBOL *eval_symbolic(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to determine symbolic value */
+
+#define eval_logical _glp_mpl_eval_logical
+int eval_logical(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to determine logical value */
+
+#define eval_tuple _glp_mpl_eval_tuple
+TUPLE *eval_tuple(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to construct n-tuple */
+
+#define eval_elemset _glp_mpl_eval_elemset
+ELEMSET *eval_elemset(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to construct elemental set */
+
+#define is_member _glp_mpl_is_member
+int is_member(MPL *mpl, CODE *code, TUPLE *tuple);
+/* check if n-tuple is in set specified by pseudo-code */
+
+#define eval_formula _glp_mpl_eval_formula
+FORMULA *eval_formula(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to construct linear form */
+
+#define clean_code _glp_mpl_clean_code
+void clean_code(MPL *mpl, CODE *code);
+/* clean pseudo-code */
+
+/**********************************************************************/
+/* * * MODEL STATEMENTS * * */
+/**********************************************************************/
+
+struct CHECK
+{ /* check statement */
+ DOMAIN *domain;
+ /* subscript domain; NULL means domain is not used */
+ CODE *code;
+ /* code for computing the predicate to be checked */
+};
+
+struct DISPLAY
+{ /* display statement */
+ DOMAIN *domain;
+ /* subscript domain; NULL means domain is not used */
+ DISPLAY1 *list;
+ /* display list; cannot be empty */
+};
+
+struct DISPLAY1
+{ /* display list entry */
+ int type;
+ /* item type:
+ A_INDEX - dummy index
+ A_SET - model set
+ A_PARAMETER - model parameter
+ A_VARIABLE - model variable
+ A_CONSTRAINT - model constraint/objective
+ A_EXPRESSION - expression */
+ union
+ { DOMAIN_SLOT *slot;
+ SET *set;
+ PARAMETER *par;
+ VARIABLE *var;
+ CONSTRAINT *con;
+ CODE *code;
+ } u;
+ /* item to be displayed */
+#if 0 /* 15/V-2010 */
+ ARG_LIST *list;
+ /* optional subscript list (for constraint/objective only) */
+#endif
+ DISPLAY1 *next;
+ /* the next entry for the same statement */
+};
+
+struct PRINTF
+{ /* printf statement */
+ DOMAIN *domain;
+ /* subscript domain; NULL means domain is not used */
+ CODE *fmt;
+ /* pseudo-code for computing format string */
+ PRINTF1 *list;
+ /* printf list; can be empty */
+ CODE *fname;
+ /* pseudo-code for computing filename to redirect the output;
+ NULL means the output goes to stdout */
+ int app;
+ /* if this flag is set, the output is appended */
+};
+
+struct PRINTF1
+{ /* printf list entry */
+ CODE *code;
+ /* pseudo-code for computing value to be printed */
+ PRINTF1 *next;
+ /* the next entry for the same statement */
+};
+
+struct FOR
+{ /* for statement */
+ DOMAIN *domain;
+ /* subscript domain; cannot be NULL */
+ STATEMENT *list;
+ /* linked list of model statements within this for statement in
+ the original order */
+};
+
+struct STATEMENT
+{ /* model statement */
+ int line;
+ /* number of source text line, where statement begins */
+ int type;
+ /* statement type:
+ A_SET - set statement
+ A_PARAMETER - parameter statement
+ A_VARIABLE - variable statement
+ A_CONSTRAINT - constraint/objective statement
+ A_TABLE - table statement
+ A_SOLVE - solve statement
+ A_CHECK - check statement
+ A_DISPLAY - display statement
+ A_PRINTF - printf statement
+ A_FOR - for statement */
+ union
+ { SET *set;
+ PARAMETER *par;
+ VARIABLE *var;
+ CONSTRAINT *con;
+ TABLE *tab;
+ void *slv; /* currently not used (set to NULL) */
+ CHECK *chk;
+ DISPLAY *dpy;
+ PRINTF *prt;
+ FOR *fur;
+ } u;
+ /* specific part of statement */
+ STATEMENT *next;
+ /* the next statement; in this list statements follow in the same
+ order as they appear in the model section */
+};
+
+#define execute_table _glp_mpl_execute_table
+void execute_table(MPL *mpl, TABLE *tab);
+/* execute table statement */
+
+#define free_dca _glp_mpl_free_dca
+void free_dca(MPL *mpl);
+/* free table driver communucation area */
+
+#define clean_table _glp_mpl_clean_table
+void clean_table(MPL *mpl, TABLE *tab);
+/* clean table statement */
+
+#define execute_check _glp_mpl_execute_check
+void execute_check(MPL *mpl, CHECK *chk);
+/* execute check statement */
+
+#define clean_check _glp_mpl_clean_check
+void clean_check(MPL *mpl, CHECK *chk);
+/* clean check statement */
+
+#define execute_display _glp_mpl_execute_display
+void execute_display(MPL *mpl, DISPLAY *dpy);
+/* execute display statement */
+
+#define clean_display _glp_mpl_clean_display
+void clean_display(MPL *mpl, DISPLAY *dpy);
+/* clean display statement */
+
+#define execute_printf _glp_mpl_execute_printf
+void execute_printf(MPL *mpl, PRINTF *prt);
+/* execute printf statement */
+
+#define clean_printf _glp_mpl_clean_printf
+void clean_printf(MPL *mpl, PRINTF *prt);
+/* clean printf statement */
+
+#define execute_for _glp_mpl_execute_for
+void execute_for(MPL *mpl, FOR *fur);
+/* execute for statement */
+
+#define clean_for _glp_mpl_clean_for
+void clean_for(MPL *mpl, FOR *fur);
+/* clean for statement */
+
+#define execute_statement _glp_mpl_execute_statement
+void execute_statement(MPL *mpl, STATEMENT *stmt);
+/* execute specified model statement */
+
+#define clean_statement _glp_mpl_clean_statement
+void clean_statement(MPL *mpl, STATEMENT *stmt);
+/* clean specified model statement */
+
+/**********************************************************************/
+/* * * GENERATING AND POSTSOLVING MODEL * * */
+/**********************************************************************/
+
+#define alloc_content _glp_mpl_alloc_content
+void alloc_content(MPL *mpl);
+/* allocate content arrays for all model objects */
+
+#define generate_model _glp_mpl_generate_model
+void generate_model(MPL *mpl);
+/* generate model */
+
+#define build_problem _glp_mpl_build_problem
+void build_problem(MPL *mpl);
+/* build problem instance */
+
+#define postsolve_model _glp_mpl_postsolve_model
+void postsolve_model(MPL *mpl);
+/* postsolve model */
+
+#define clean_model _glp_mpl_clean_model
+void clean_model(MPL *mpl);
+/* clean model content */
+
+/**********************************************************************/
+/* * * INPUT/OUTPUT * * */
+/**********************************************************************/
+
+#define open_input _glp_mpl_open_input
+void open_input(MPL *mpl, char *file);
+/* open input text file */
+
+#define read_char _glp_mpl_read_char
+int read_char(MPL *mpl);
+/* read next character from input text file */
+
+#define close_input _glp_mpl_close_input
+void close_input(MPL *mpl);
+/* close input text file */
+
+#define open_output _glp_mpl_open_output
+void open_output(MPL *mpl, char *file);
+/* open output text file */
+
+#define write_char _glp_mpl_write_char
+void write_char(MPL *mpl, int c);
+/* write next character to output text file */
+
+#define write_text _glp_mpl_write_text
+void write_text(MPL *mpl, char *fmt, ...);
+/* format and write text to output text file */
+
+#define flush_output _glp_mpl_flush_output
+void flush_output(MPL *mpl);
+/* finalize writing data to output text file */
+
+/**********************************************************************/
+/* * * SOLVER INTERFACE * * */
+/**********************************************************************/
+
+#define MPL_FR 401 /* free (unbounded) */
+#define MPL_LO 402 /* lower bound */
+#define MPL_UP 403 /* upper bound */
+#define MPL_DB 404 /* both lower and upper bounds */
+#define MPL_FX 405 /* fixed */
+
+#define MPL_ST 411 /* constraint */
+#define MPL_MIN 412 /* objective (minimization) */
+#define MPL_MAX 413 /* objective (maximization) */
+
+#define MPL_NUM 421 /* continuous */
+#define MPL_INT 422 /* integer */
+#define MPL_BIN 423 /* binary */
+
+#define error _glp_mpl_error
+void error(MPL *mpl, char *fmt, ...);
+/* print error message and terminate model processing */
+
+#define warning _glp_mpl_warning
+void warning(MPL *mpl, char *fmt, ...);
+/* print warning message and continue model processing */
+
+#define mpl_initialize _glp_mpl_initialize
+MPL *mpl_initialize(void);
+/* create and initialize translator database */
+
+#define mpl_read_model _glp_mpl_read_model
+int mpl_read_model(MPL *mpl, char *file, int skip_data);
+/* read model section and optional data section */
+
+#define mpl_read_data _glp_mpl_read_data
+int mpl_read_data(MPL *mpl, char *file);
+/* read data section */
+
+#define mpl_generate _glp_mpl_generate
+int mpl_generate(MPL *mpl, char *file);
+/* generate model */
+
+#define mpl_get_prob_name _glp_mpl_get_prob_name
+char *mpl_get_prob_name(MPL *mpl);
+/* obtain problem (model) name */
+
+#define mpl_get_num_rows _glp_mpl_get_num_rows
+int mpl_get_num_rows(MPL *mpl);
+/* determine number of rows */
+
+#define mpl_get_num_cols _glp_mpl_get_num_cols
+int mpl_get_num_cols(MPL *mpl);
+/* determine number of columns */
+
+#define mpl_get_row_name _glp_mpl_get_row_name
+char *mpl_get_row_name(MPL *mpl, int i);
+/* obtain row name */
+
+#define mpl_get_row_kind _glp_mpl_get_row_kind
+int mpl_get_row_kind(MPL *mpl, int i);
+/* determine row kind */
+
+#define mpl_get_row_bnds _glp_mpl_get_row_bnds
+int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
+/* obtain row bounds */
+
+#define mpl_get_mat_row _glp_mpl_get_mat_row
+int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
+/* obtain row of the constraint matrix */
+
+#define mpl_get_row_c0 _glp_mpl_get_row_c0
+double mpl_get_row_c0(MPL *mpl, int i);
+/* obtain constant term of free row */
+
+#define mpl_get_col_name _glp_mpl_get_col_name
+char *mpl_get_col_name(MPL *mpl, int j);
+/* obtain column name */
+
+#define mpl_get_col_kind _glp_mpl_get_col_kind
+int mpl_get_col_kind(MPL *mpl, int j);
+/* determine column kind */
+
+#define mpl_get_col_bnds _glp_mpl_get_col_bnds
+int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
+/* obtain column bounds */
+
+#define mpl_has_solve_stmt _glp_mpl_has_solve_stmt
+int mpl_has_solve_stmt(MPL *mpl);
+/* check if model has solve statement */
+
+#if 1 /* 15/V-2010 */
+#define mpl_put_row_soln _glp_mpl_put_row_soln
+void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
+ double dual);
+/* store row (constraint/objective) solution components */
+#endif
+
+#if 1 /* 15/V-2010 */
+#define mpl_put_col_soln _glp_mpl_put_col_soln
+void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
+ double dual);
+/* store column (variable) solution components */
+#endif
+
+#if 0 /* 15/V-2010 */
+#define mpl_put_col_value _glp_mpl_put_col_value
+void mpl_put_col_value(MPL *mpl, int j, double val);
+/* store column value */
+#endif
+
+#define mpl_postsolve _glp_mpl_postsolve
+int mpl_postsolve(MPL *mpl);
+/* postsolve model */
+
+#define mpl_terminate _glp_mpl_terminate
+void mpl_terminate(MPL *mpl);
+/* free all resources used by translator */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/mpl/mpl1.c b/test/monniaux/glpk-4.65/src/mpl/mpl1.c
new file mode 100644
index 00000000..7dc3cd79
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/mpl/mpl1.c
@@ -0,0 +1,4718 @@
+/* mpl1.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2003-2016 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/>.
+***********************************************************************/
+
+#include "mpl.h"
+
+#define dmp_get_atomv dmp_get_atom
+
+/**********************************************************************/
+/* * * PROCESSING MODEL SECTION * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- enter_context - enter current token into context queue.
+--
+-- This routine enters the current token into the context queue. */
+
+void enter_context(MPL *mpl)
+{ char *image, *s;
+ if (mpl->token == T_EOF)
+ image = "_|_";
+ else if (mpl->token == T_STRING)
+ image = "'...'";
+ else
+ image = mpl->image;
+ xassert(0 <= mpl->c_ptr && mpl->c_ptr < CONTEXT_SIZE);
+ mpl->context[mpl->c_ptr++] = ' ';
+ if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
+ for (s = image; *s != '\0'; s++)
+ { mpl->context[mpl->c_ptr++] = *s;
+ if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- print_context - print current content of context queue.
+--
+-- This routine prints current content of the context queue. */
+
+void print_context(MPL *mpl)
+{ int c;
+ while (mpl->c_ptr > 0)
+ { mpl->c_ptr--;
+ c = mpl->context[0];
+ memmove(mpl->context, mpl->context+1, CONTEXT_SIZE-1);
+ mpl->context[CONTEXT_SIZE-1] = (char)c;
+ }
+ xprintf("Context: %s%.*s\n", mpl->context[0] == ' ' ? "" : "...",
+ CONTEXT_SIZE, mpl->context);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- get_char - scan next character from input text file.
+--
+-- This routine scans a next ASCII character from the input text file.
+-- In case of end-of-file, the character is assigned EOF. */
+
+void get_char(MPL *mpl)
+{ int c;
+ if (mpl->c == EOF) goto done;
+ if (mpl->c == '\n') mpl->line++;
+ c = read_char(mpl);
+ if (c == EOF)
+ { if (mpl->c == '\n')
+ mpl->line--;
+ else
+ warning(mpl, "final NL missing before end of file");
+ }
+ else if (c == '\n')
+ ;
+ else if (isspace(c))
+ c = ' ';
+ else if (iscntrl(c))
+ { enter_context(mpl);
+ error(mpl, "control character 0x%02X not allowed", c);
+ }
+ mpl->c = c;
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- append_char - append character to current token.
+--
+-- This routine appends the current character to the current token and
+-- then scans a next character. */
+
+void append_char(MPL *mpl)
+{ xassert(0 <= mpl->imlen && mpl->imlen <= MAX_LENGTH);
+ if (mpl->imlen == MAX_LENGTH)
+ { switch (mpl->token)
+ { case T_NAME:
+ enter_context(mpl);
+ error(mpl, "symbolic name %s... too long", mpl->image);
+ case T_SYMBOL:
+ enter_context(mpl);
+ error(mpl, "symbol %s... too long", mpl->image);
+ case T_NUMBER:
+ enter_context(mpl);
+ error(mpl, "numeric literal %s... too long", mpl->image);
+ case T_STRING:
+ enter_context(mpl);
+ error(mpl, "string literal too long");
+ default:
+ xassert(mpl != mpl);
+ }
+ }
+ mpl->image[mpl->imlen++] = (char)mpl->c;
+ mpl->image[mpl->imlen] = '\0';
+ get_char(mpl);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- get_token - scan next token from input text file.
+--
+-- This routine scans a next token from the input text file using the
+-- standard finite automation technique. */
+
+void get_token(MPL *mpl)
+{ /* save the current token */
+ mpl->b_token = mpl->token;
+ mpl->b_imlen = mpl->imlen;
+ strcpy(mpl->b_image, mpl->image);
+ mpl->b_value = mpl->value;
+ /* if the next token is already scanned, make it current */
+ if (mpl->f_scan)
+ { mpl->f_scan = 0;
+ mpl->token = mpl->f_token;
+ mpl->imlen = mpl->f_imlen;
+ strcpy(mpl->image, mpl->f_image);
+ mpl->value = mpl->f_value;
+ goto done;
+ }
+loop: /* nothing has been scanned so far */
+ mpl->token = 0;
+ mpl->imlen = 0;
+ mpl->image[0] = '\0';
+ mpl->value = 0.0;
+ /* skip any uninteresting characters */
+ while (mpl->c == ' ' || mpl->c == '\n') get_char(mpl);
+ /* recognize and construct the token */
+ if (mpl->c == EOF)
+ { /* end-of-file reached */
+ mpl->token = T_EOF;
+ }
+ else if (mpl->c == '#')
+ { /* comment; skip anything until end-of-line */
+ while (mpl->c != '\n' && mpl->c != EOF) get_char(mpl);
+ goto loop;
+ }
+ else if (!mpl->flag_d && (isalpha(mpl->c) || mpl->c == '_'))
+ { /* symbolic name or reserved keyword */
+ mpl->token = T_NAME;
+ while (isalnum(mpl->c) || mpl->c == '_') append_char(mpl);
+ if (strcmp(mpl->image, "and") == 0)
+ mpl->token = T_AND;
+ else if (strcmp(mpl->image, "by") == 0)
+ mpl->token = T_BY;
+ else if (strcmp(mpl->image, "cross") == 0)
+ mpl->token = T_CROSS;
+ else if (strcmp(mpl->image, "diff") == 0)
+ mpl->token = T_DIFF;
+ else if (strcmp(mpl->image, "div") == 0)
+ mpl->token = T_DIV;
+ else if (strcmp(mpl->image, "else") == 0)
+ mpl->token = T_ELSE;
+ else if (strcmp(mpl->image, "if") == 0)
+ mpl->token = T_IF;
+ else if (strcmp(mpl->image, "in") == 0)
+ mpl->token = T_IN;
+#if 1 /* 21/VII-2006 */
+ else if (strcmp(mpl->image, "Infinity") == 0)
+ mpl->token = T_INFINITY;
+#endif
+ else if (strcmp(mpl->image, "inter") == 0)
+ mpl->token = T_INTER;
+ else if (strcmp(mpl->image, "less") == 0)
+ mpl->token = T_LESS;
+ else if (strcmp(mpl->image, "mod") == 0)
+ mpl->token = T_MOD;
+ else if (strcmp(mpl->image, "not") == 0)
+ mpl->token = T_NOT;
+ else if (strcmp(mpl->image, "or") == 0)
+ mpl->token = T_OR;
+ else if (strcmp(mpl->image, "s") == 0 && mpl->c == '.')
+ { mpl->token = T_SPTP;
+ append_char(mpl);
+ if (mpl->c != 't')
+sptp: { enter_context(mpl);
+ error(mpl, "keyword s.t. incomplete");
+ }
+ append_char(mpl);
+ if (mpl->c != '.') goto sptp;
+ append_char(mpl);
+ }
+ else if (strcmp(mpl->image, "symdiff") == 0)
+ mpl->token = T_SYMDIFF;
+ else if (strcmp(mpl->image, "then") == 0)
+ mpl->token = T_THEN;
+ else if (strcmp(mpl->image, "union") == 0)
+ mpl->token = T_UNION;
+ else if (strcmp(mpl->image, "within") == 0)
+ mpl->token = T_WITHIN;
+ }
+ else if (!mpl->flag_d && isdigit(mpl->c))
+ { /* numeric literal */
+ mpl->token = T_NUMBER;
+ /* scan integer part */
+ while (isdigit(mpl->c)) append_char(mpl);
+ /* scan optional fractional part */
+ if (mpl->c == '.')
+ { append_char(mpl);
+ if (mpl->c == '.')
+ { /* hmm, it is not the fractional part, it is dots that
+ follow the integer part */
+ mpl->imlen--;
+ mpl->image[mpl->imlen] = '\0';
+ mpl->f_dots = 1;
+ goto conv;
+ }
+frac: while (isdigit(mpl->c)) append_char(mpl);
+ }
+ /* scan optional decimal exponent */
+ if (mpl->c == 'e' || mpl->c == 'E')
+ { append_char(mpl);
+ if (mpl->c == '+' || mpl->c == '-') append_char(mpl);
+ if (!isdigit(mpl->c))
+ { enter_context(mpl);
+ error(mpl, "numeric literal %s incomplete", mpl->image);
+ }
+ while (isdigit(mpl->c)) append_char(mpl);
+ }
+ /* there must be no letter following the numeric literal */
+ if (isalpha(mpl->c) || mpl->c == '_')
+ { enter_context(mpl);
+ error(mpl, "symbol %s%c... should be enclosed in quotes",
+ mpl->image, mpl->c);
+ }
+conv: /* convert numeric literal to floating-point */
+ if (str2num(mpl->image, &mpl->value))
+err: { enter_context(mpl);
+ error(mpl, "cannot convert numeric literal %s to floating-p"
+ "oint number", mpl->image);
+ }
+ }
+ else if (mpl->c == '\'' || mpl->c == '"')
+ { /* character string */
+ int quote = mpl->c;
+ mpl->token = T_STRING;
+ get_char(mpl);
+ for (;;)
+ { if (mpl->c == '\n' || mpl->c == EOF)
+ { enter_context(mpl);
+ error(mpl, "unexpected end of line; string literal incom"
+ "plete");
+ }
+ if (mpl->c == quote)
+ { get_char(mpl);
+ if (mpl->c != quote) break;
+ }
+ append_char(mpl);
+ }
+ }
+ else if (!mpl->flag_d && mpl->c == '+')
+ mpl->token = T_PLUS, append_char(mpl);
+ else if (!mpl->flag_d && mpl->c == '-')
+ mpl->token = T_MINUS, append_char(mpl);
+ else if (mpl->c == '*')
+ { mpl->token = T_ASTERISK, append_char(mpl);
+ if (mpl->c == '*')
+ mpl->token = T_POWER, append_char(mpl);
+ }
+ else if (mpl->c == '/')
+ { mpl->token = T_SLASH, append_char(mpl);
+ if (mpl->c == '*')
+ { /* comment sequence */
+ get_char(mpl);
+ for (;;)
+ { if (mpl->c == EOF)
+ { /* do not call enter_context at this point */
+ error(mpl, "unexpected end of file; comment sequence "
+ "incomplete");
+ }
+ else if (mpl->c == '*')
+ { get_char(mpl);
+ if (mpl->c == '/') break;
+ }
+ else
+ get_char(mpl);
+ }
+ get_char(mpl);
+ goto loop;
+ }
+ }
+ else if (mpl->c == '^')
+ mpl->token = T_POWER, append_char(mpl);
+ else if (mpl->c == '<')
+ { mpl->token = T_LT, append_char(mpl);
+ if (mpl->c == '=')
+ mpl->token = T_LE, append_char(mpl);
+ else if (mpl->c == '>')
+ mpl->token = T_NE, append_char(mpl);
+#if 1 /* 11/II-2008 */
+ else if (mpl->c == '-')
+ mpl->token = T_INPUT, append_char(mpl);
+#endif
+ }
+ else if (mpl->c == '=')
+ { mpl->token = T_EQ, append_char(mpl);
+ if (mpl->c == '=') append_char(mpl);
+ }
+ else if (mpl->c == '>')
+ { mpl->token = T_GT, append_char(mpl);
+ if (mpl->c == '=')
+ mpl->token = T_GE, append_char(mpl);
+#if 1 /* 14/VII-2006 */
+ else if (mpl->c == '>')
+ mpl->token = T_APPEND, append_char(mpl);
+#endif
+ }
+ else if (mpl->c == '!')
+ { mpl->token = T_NOT, append_char(mpl);
+ if (mpl->c == '=')
+ mpl->token = T_NE, append_char(mpl);
+ }
+ else if (mpl->c == '&')
+ { mpl->token = T_CONCAT, append_char(mpl);
+ if (mpl->c == '&')
+ mpl->token = T_AND, append_char(mpl);
+ }
+ else if (mpl->c == '|')
+ { mpl->token = T_BAR, append_char(mpl);
+ if (mpl->c == '|')
+ mpl->token = T_OR, append_char(mpl);
+ }
+ else if (!mpl->flag_d && mpl->c == '.')
+ { mpl->token = T_POINT, append_char(mpl);
+ if (mpl->f_dots)
+ { /* dots; the first dot was read on the previous call to the
+ scanner, so the current character is the second dot */
+ mpl->token = T_DOTS;
+ mpl->imlen = 2;
+ strcpy(mpl->image, "..");
+ mpl->f_dots = 0;
+ }
+ else if (mpl->c == '.')
+ mpl->token = T_DOTS, append_char(mpl);
+ else if (isdigit(mpl->c))
+ { /* numeric literal that begins with the decimal point */
+ mpl->token = T_NUMBER, append_char(mpl);
+ goto frac;
+ }
+ }
+ else if (mpl->c == ',')
+ mpl->token = T_COMMA, append_char(mpl);
+ else if (mpl->c == ':')
+ { mpl->token = T_COLON, append_char(mpl);
+ if (mpl->c == '=')
+ mpl->token = T_ASSIGN, append_char(mpl);
+ }
+ else if (mpl->c == ';')
+ mpl->token = T_SEMICOLON, append_char(mpl);
+ else if (mpl->c == '(')
+ mpl->token = T_LEFT, append_char(mpl);
+ else if (mpl->c == ')')
+ mpl->token = T_RIGHT, append_char(mpl);
+ else if (mpl->c == '[')
+ mpl->token = T_LBRACKET, append_char(mpl);
+ else if (mpl->c == ']')
+ mpl->token = T_RBRACKET, append_char(mpl);
+ else if (mpl->c == '{')
+ mpl->token = T_LBRACE, append_char(mpl);
+ else if (mpl->c == '}')
+ mpl->token = T_RBRACE, append_char(mpl);
+#if 1 /* 11/II-2008 */
+ else if (mpl->c == '~')
+ mpl->token = T_TILDE, append_char(mpl);
+#endif
+ else if (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
+ { /* symbol */
+ xassert(mpl->flag_d);
+ mpl->token = T_SYMBOL;
+ while (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
+ append_char(mpl);
+ switch (str2num(mpl->image, &mpl->value))
+ { case 0:
+ mpl->token = T_NUMBER;
+ break;
+ case 1:
+ goto err;
+ case 2:
+ break;
+ default:
+ xassert(mpl != mpl);
+ }
+ }
+ else
+ { enter_context(mpl);
+ error(mpl, "character %c not allowed", mpl->c);
+ }
+ /* enter the current token into the context queue */
+ enter_context(mpl);
+ /* reset the flag, which may be set by indexing_expression() and
+ is used by expression_list() */
+ mpl->flag_x = 0;
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- unget_token - return current token back to input stream.
+--
+-- This routine returns the current token back to the input stream, so
+-- the previously scanned token becomes the current one. */
+
+void unget_token(MPL *mpl)
+{ /* save the current token, which becomes the next one */
+ xassert(!mpl->f_scan);
+ mpl->f_scan = 1;
+ mpl->f_token = mpl->token;
+ mpl->f_imlen = mpl->imlen;
+ strcpy(mpl->f_image, mpl->image);
+ mpl->f_value = mpl->value;
+ /* restore the previous token, which becomes the current one */
+ mpl->token = mpl->b_token;
+ mpl->imlen = mpl->b_imlen;
+ strcpy(mpl->image, mpl->b_image);
+ mpl->value = mpl->b_value;
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- is_keyword - check if current token is given non-reserved keyword.
+--
+-- If the current token is given (non-reserved) keyword, this routine
+-- returns non-zero. Otherwise zero is returned. */
+
+int is_keyword(MPL *mpl, char *keyword)
+{ return
+ mpl->token == T_NAME && strcmp(mpl->image, keyword) == 0;
+}
+
+/*----------------------------------------------------------------------
+-- is_reserved - check if current token is reserved keyword.
+--
+-- If the current token is a reserved keyword, this routine returns
+-- non-zero. Otherwise zero is returned. */
+
+int is_reserved(MPL *mpl)
+{ return
+ mpl->token == T_AND && mpl->image[0] == 'a' ||
+ mpl->token == T_BY ||
+ mpl->token == T_CROSS ||
+ mpl->token == T_DIFF ||
+ mpl->token == T_DIV ||
+ mpl->token == T_ELSE ||
+ mpl->token == T_IF ||
+ mpl->token == T_IN ||
+ mpl->token == T_INTER ||
+ mpl->token == T_LESS ||
+ mpl->token == T_MOD ||
+ mpl->token == T_NOT && mpl->image[0] == 'n' ||
+ mpl->token == T_OR && mpl->image[0] == 'o' ||
+ mpl->token == T_SYMDIFF ||
+ mpl->token == T_THEN ||
+ mpl->token == T_UNION ||
+ mpl->token == T_WITHIN;
+}
+
+/*----------------------------------------------------------------------
+-- make_code - generate pseudo-code (basic routine).
+--
+-- This routine generates specified pseudo-code. It is assumed that all
+-- other translator routines use this basic routine. */
+
+CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim)
+{ CODE *code;
+ DOMAIN *domain;
+ DOMAIN_BLOCK *block;
+ ARG_LIST *e;
+ /* generate pseudo-code */
+ code = alloc(CODE);
+ code->op = op;
+ code->vflag = 0; /* is inherited from operand(s) */
+ /* copy operands and also make them referring to the pseudo-code
+ being generated, because the latter becomes the parent for all
+ its operands */
+ memset(&code->arg, '?', sizeof(OPERANDS));
+ switch (op)
+ { case O_NUMBER:
+ code->arg.num = arg->num;
+ break;
+ case O_STRING:
+ code->arg.str = arg->str;
+ break;
+ case O_INDEX:
+ code->arg.index.slot = arg->index.slot;
+ code->arg.index.next = arg->index.next;
+ break;
+ case O_MEMNUM:
+ case O_MEMSYM:
+ for (e = arg->par.list; e != NULL; e = e->next)
+ { xassert(e->x != NULL);
+ xassert(e->x->up == NULL);
+ e->x->up = code;
+ code->vflag |= e->x->vflag;
+ }
+ code->arg.par.par = arg->par.par;
+ code->arg.par.list = arg->par.list;
+ break;
+ case O_MEMSET:
+ for (e = arg->set.list; e != NULL; e = e->next)
+ { xassert(e->x != NULL);
+ xassert(e->x->up == NULL);
+ e->x->up = code;
+ code->vflag |= e->x->vflag;
+ }
+ code->arg.set.set = arg->set.set;
+ code->arg.set.list = arg->set.list;
+ break;
+ case O_MEMVAR:
+ for (e = arg->var.list; e != NULL; e = e->next)
+ { xassert(e->x != NULL);
+ xassert(e->x->up == NULL);
+ e->x->up = code;
+ code->vflag |= e->x->vflag;
+ }
+ code->arg.var.var = arg->var.var;
+ code->arg.var.list = arg->var.list;
+#if 1 /* 15/V-2010 */
+ code->arg.var.suff = arg->var.suff;
+#endif
+ break;
+#if 1 /* 15/V-2010 */
+ case O_MEMCON:
+ for (e = arg->con.list; e != NULL; e = e->next)
+ { xassert(e->x != NULL);
+ xassert(e->x->up == NULL);
+ e->x->up = code;
+ code->vflag |= e->x->vflag;
+ }
+ code->arg.con.con = arg->con.con;
+ code->arg.con.list = arg->con.list;
+ code->arg.con.suff = arg->con.suff;
+ break;
+#endif
+ case O_TUPLE:
+ case O_MAKE:
+ for (e = arg->list; e != NULL; e = e->next)
+ { xassert(e->x != NULL);
+ xassert(e->x->up == NULL);
+ e->x->up = code;
+ code->vflag |= e->x->vflag;
+ }
+ code->arg.list = arg->list;
+ break;
+ case O_SLICE:
+ xassert(arg->slice != NULL);
+ code->arg.slice = arg->slice;
+ break;
+ case O_IRAND224:
+ case O_UNIFORM01:
+ case O_NORMAL01:
+ case O_GMTIME:
+ code->vflag = 1;
+ break;
+ case O_CVTNUM:
+ case O_CVTSYM:
+ case O_CVTLOG:
+ case O_CVTTUP:
+ case O_CVTLFM:
+ case O_PLUS:
+ case O_MINUS:
+ case O_NOT:
+ case O_ABS:
+ case O_CEIL:
+ case O_FLOOR:
+ case O_EXP:
+ case O_LOG:
+ case O_LOG10:
+ case O_SQRT:
+ case O_SIN:
+ case O_COS:
+ case O_TAN:
+ case O_ATAN:
+ case O_ROUND:
+ case O_TRUNC:
+ case O_CARD:
+ case O_LENGTH:
+ /* unary operation */
+ xassert(arg->arg.x != NULL);
+ xassert(arg->arg.x->up == NULL);
+ arg->arg.x->up = code;
+ code->vflag |= arg->arg.x->vflag;
+ code->arg.arg.x = arg->arg.x;
+ break;
+ case O_ADD:
+ case O_SUB:
+ case O_LESS:
+ case O_MUL:
+ case O_DIV:
+ case O_IDIV:
+ case O_MOD:
+ case O_POWER:
+ case O_ATAN2:
+ case O_ROUND2:
+ case O_TRUNC2:
+ case O_UNIFORM:
+ if (op == O_UNIFORM) code->vflag = 1;
+ case O_NORMAL:
+ if (op == O_NORMAL) code->vflag = 1;
+ case O_CONCAT:
+ case O_LT:
+ case O_LE:
+ case O_EQ:
+ case O_GE:
+ case O_GT:
+ case O_NE:
+ case O_AND:
+ case O_OR:
+ case O_UNION:
+ case O_DIFF:
+ case O_SYMDIFF:
+ case O_INTER:
+ case O_CROSS:
+ case O_IN:
+ case O_NOTIN:
+ case O_WITHIN:
+ case O_NOTWITHIN:
+ case O_SUBSTR:
+ case O_STR2TIME:
+ case O_TIME2STR:
+ /* binary operation */
+ xassert(arg->arg.x != NULL);
+ xassert(arg->arg.x->up == NULL);
+ arg->arg.x->up = code;
+ code->vflag |= arg->arg.x->vflag;
+ xassert(arg->arg.y != NULL);
+ xassert(arg->arg.y->up == NULL);
+ arg->arg.y->up = code;
+ code->vflag |= arg->arg.y->vflag;
+ code->arg.arg.x = arg->arg.x;
+ code->arg.arg.y = arg->arg.y;
+ break;
+ case O_DOTS:
+ case O_FORK:
+ case O_SUBSTR3:
+ /* ternary operation */
+ xassert(arg->arg.x != NULL);
+ xassert(arg->arg.x->up == NULL);
+ arg->arg.x->up = code;
+ code->vflag |= arg->arg.x->vflag;
+ xassert(arg->arg.y != NULL);
+ xassert(arg->arg.y->up == NULL);
+ arg->arg.y->up = code;
+ code->vflag |= arg->arg.y->vflag;
+ if (arg->arg.z != NULL)
+ { xassert(arg->arg.z->up == NULL);
+ arg->arg.z->up = code;
+ code->vflag |= arg->arg.z->vflag;
+ }
+ code->arg.arg.x = arg->arg.x;
+ code->arg.arg.y = arg->arg.y;
+ code->arg.arg.z = arg->arg.z;
+ break;
+ case O_MIN:
+ case O_MAX:
+ /* n-ary operation */
+ for (e = arg->list; e != NULL; e = e->next)
+ { xassert(e->x != NULL);
+ xassert(e->x->up == NULL);
+ e->x->up = code;
+ code->vflag |= e->x->vflag;
+ }
+ code->arg.list = arg->list;
+ break;
+ case O_SUM:
+ case O_PROD:
+ case O_MINIMUM:
+ case O_MAXIMUM:
+ case O_FORALL:
+ case O_EXISTS:
+ case O_SETOF:
+ case O_BUILD:
+ /* iterated operation */
+ domain = arg->loop.domain;
+ xassert(domain != NULL);
+ if (domain->code != NULL)
+ { xassert(domain->code->up == NULL);
+ domain->code->up = code;
+ code->vflag |= domain->code->vflag;
+ }
+ for (block = domain->list; block != NULL; block =
+ block->next)
+ { xassert(block->code != NULL);
+ xassert(block->code->up == NULL);
+ block->code->up = code;
+ code->vflag |= block->code->vflag;
+ }
+ if (arg->loop.x != NULL)
+ { xassert(arg->loop.x->up == NULL);
+ arg->loop.x->up = code;
+ code->vflag |= arg->loop.x->vflag;
+ }
+ code->arg.loop.domain = arg->loop.domain;
+ code->arg.loop.x = arg->loop.x;
+ break;
+ default:
+ xassert(op != op);
+ }
+ /* set other attributes of the pseudo-code */
+ code->type = type;
+ code->dim = dim;
+ code->up = NULL;
+ code->valid = 0;
+ memset(&code->value, '?', sizeof(VALUE));
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- make_unary - generate pseudo-code for unary operation.
+--
+-- This routine generates pseudo-code for unary operation. */
+
+CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim)
+{ CODE *code;
+ OPERANDS arg;
+ xassert(x != NULL);
+ arg.arg.x = x;
+ code = make_code(mpl, op, &arg, type, dim);
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- make_binary - generate pseudo-code for binary operation.
+--
+-- This routine generates pseudo-code for binary operation. */
+
+CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
+ int dim)
+{ CODE *code;
+ OPERANDS arg;
+ xassert(x != NULL);
+ xassert(y != NULL);
+ arg.arg.x = x;
+ arg.arg.y = y;
+ code = make_code(mpl, op, &arg, type, dim);
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- make_ternary - generate pseudo-code for ternary operation.
+--
+-- This routine generates pseudo-code for ternary operation. */
+
+CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
+ int type, int dim)
+{ CODE *code;
+ OPERANDS arg;
+ xassert(x != NULL);
+ xassert(y != NULL);
+ /* third operand can be NULL */
+ arg.arg.x = x;
+ arg.arg.y = y;
+ arg.arg.z = z;
+ code = make_code(mpl, op, &arg, type, dim);
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- numeric_literal - parse reference to numeric literal.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <numeric literal> */
+
+CODE *numeric_literal(MPL *mpl)
+{ CODE *code;
+ OPERANDS arg;
+ xassert(mpl->token == T_NUMBER);
+ arg.num = mpl->value;
+ code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
+ get_token(mpl /* <numeric literal> */);
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- string_literal - parse reference to string literal.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <string literal> */
+
+CODE *string_literal(MPL *mpl)
+{ CODE *code;
+ OPERANDS arg;
+ xassert(mpl->token == T_STRING);
+ arg.str = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(arg.str, mpl->image);
+ code = make_code(mpl, O_STRING, &arg, A_SYMBOLIC, 0);
+ get_token(mpl /* <string literal> */);
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- create_arg_list - create empty operands list.
+--
+-- This routine creates operands list, which is initially empty. */
+
+ARG_LIST *create_arg_list(MPL *mpl)
+{ ARG_LIST *list;
+ xassert(mpl == mpl);
+ list = NULL;
+ return list;
+}
+
+/*----------------------------------------------------------------------
+-- expand_arg_list - append operand to operands list.
+--
+-- This routine appends new operand to specified operands list. */
+
+ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x)
+{ ARG_LIST *tail, *temp;
+ xassert(x != NULL);
+ /* create new operands list entry */
+ tail = alloc(ARG_LIST);
+ tail->x = x;
+ tail->next = NULL;
+ /* and append it to the operands list */
+ if (list == NULL)
+ list = tail;
+ else
+ { for (temp = list; temp->next != NULL; temp = temp->next);
+ temp->next = tail;
+ }
+ return list;
+}
+
+/*----------------------------------------------------------------------
+-- arg_list_len - determine length of operands list.
+--
+-- This routine returns the number of operands in operands list. */
+
+int arg_list_len(MPL *mpl, ARG_LIST *list)
+{ ARG_LIST *temp;
+ int len;
+ xassert(mpl == mpl);
+ len = 0;
+ for (temp = list; temp != NULL; temp = temp->next) len++;
+ return len;
+}
+
+/*----------------------------------------------------------------------
+-- subscript_list - parse subscript list.
+--
+-- This routine parses subscript list using the syntax:
+--
+-- <subscript list> ::= <subscript>
+-- <subscript list> ::= <subscript list> , <subscript>
+-- <subscript> ::= <expression 5> */
+
+ARG_LIST *subscript_list(MPL *mpl)
+{ ARG_LIST *list;
+ CODE *x;
+ list = create_arg_list(mpl);
+ for (;;)
+ { /* parse subscript expression */
+ x = expression_5(mpl);
+ /* convert it to symbolic type, if necessary */
+ if (x->type == A_NUMERIC)
+ x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+ /* check that now the expression is of symbolic type */
+ if (x->type != A_SYMBOLIC)
+ error(mpl, "subscript expression has invalid type");
+ xassert(x->dim == 0);
+ /* and append it to the subscript list */
+ list = expand_arg_list(mpl, list, x);
+ /* check a token that follows the subscript expression */
+ if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_RBRACKET)
+ break;
+ else
+ error(mpl, "syntax error in subscript list");
+ }
+ return list;
+}
+
+#if 1 /* 15/V-2010 */
+/*----------------------------------------------------------------------
+-- object_reference - parse reference to named object.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <dummy index>
+-- <primary expression> ::= <set name>
+-- <primary expression> ::= <set name> [ <subscript list> ]
+-- <primary expression> ::= <parameter name>
+-- <primary expression> ::= <parameter name> [ <subscript list> ]
+-- <primary expression> ::= <variable name> <suffix>
+-- <primary expression> ::= <variable name> [ <subscript list> ]
+-- <suffix>
+-- <primary expression> ::= <constraint name> <suffix>
+-- <primary expression> ::= <constraint name> [ <subscript list> ]
+-- <suffix>
+-- <dummy index> ::= <symbolic name>
+-- <set name> ::= <symbolic name>
+-- <parameter name> ::= <symbolic name>
+-- <variable name> ::= <symbolic name>
+-- <constraint name> ::= <symbolic name>
+-- <suffix> ::= <empty> | .lb | .ub | .status | .val | .dual */
+
+CODE *object_reference(MPL *mpl)
+{ AVLNODE *node;
+ DOMAIN_SLOT *slot;
+ SET *set;
+ PARAMETER *par;
+ VARIABLE *var;
+ CONSTRAINT *con;
+ ARG_LIST *list;
+ OPERANDS arg;
+ CODE *code;
+ char *name;
+ int dim, suff;
+ /* find the object in the symbolic name table */
+ xassert(mpl->token == T_NAME);
+ node = avl_find_node(mpl->tree, mpl->image);
+ if (node == NULL)
+ error(mpl, "%s not defined", mpl->image);
+ /* check the object type and obtain its dimension */
+ switch (avl_get_node_type(node))
+ { case A_INDEX:
+ /* dummy index */
+ slot = (DOMAIN_SLOT *)avl_get_node_link(node);
+ name = slot->name;
+ dim = 0;
+ break;
+ case A_SET:
+ /* model set */
+ set = (SET *)avl_get_node_link(node);
+ name = set->name;
+ dim = set->dim;
+ /* if a set object is referenced in its own declaration and
+ the dimen attribute is not specified yet, use dimen 1 by
+ default */
+ if (set->dimen == 0) set->dimen = 1;
+ break;
+ case A_PARAMETER:
+ /* model parameter */
+ par = (PARAMETER *)avl_get_node_link(node);
+ name = par->name;
+ dim = par->dim;
+ break;
+ case A_VARIABLE:
+ /* model variable */
+ var = (VARIABLE *)avl_get_node_link(node);
+ name = var->name;
+ dim = var->dim;
+ break;
+ case A_CONSTRAINT:
+ /* model constraint or objective */
+ con = (CONSTRAINT *)avl_get_node_link(node);
+ name = con->name;
+ dim = con->dim;
+ break;
+ default:
+ xassert(node != node);
+ }
+ get_token(mpl /* <symbolic name> */);
+ /* parse optional subscript list */
+ if (mpl->token == T_LBRACKET)
+ { /* subscript list is specified */
+ if (dim == 0)
+ error(mpl, "%s cannot be subscripted", name);
+ get_token(mpl /* [ */);
+ list = subscript_list(mpl);
+ if (dim != arg_list_len(mpl, list))
+ error(mpl, "%s must have %d subscript%s rather than %d",
+ name, dim, dim == 1 ? "" : "s", arg_list_len(mpl, list));
+ xassert(mpl->token == T_RBRACKET);
+ get_token(mpl /* ] */);
+ }
+ else
+ { /* subscript list is not specified */
+ if (dim != 0)
+ error(mpl, "%s must be subscripted", name);
+ list = create_arg_list(mpl);
+ }
+ /* parse optional suffix */
+ if (!mpl->flag_s && avl_get_node_type(node) == A_VARIABLE)
+ suff = DOT_NONE;
+ else
+ suff = DOT_VAL;
+ if (mpl->token == T_POINT)
+ { get_token(mpl /* . */);
+ if (mpl->token != T_NAME)
+ error(mpl, "invalid use of period");
+ if (!(avl_get_node_type(node) == A_VARIABLE ||
+ avl_get_node_type(node) == A_CONSTRAINT))
+ error(mpl, "%s cannot have a suffix", name);
+ if (strcmp(mpl->image, "lb") == 0)
+ suff = DOT_LB;
+ else if (strcmp(mpl->image, "ub") == 0)
+ suff = DOT_UB;
+ else if (strcmp(mpl->image, "status") == 0)
+ suff = DOT_STATUS;
+ else if (strcmp(mpl->image, "val") == 0)
+ suff = DOT_VAL;
+ else if (strcmp(mpl->image, "dual") == 0)
+ suff = DOT_DUAL;
+ else
+ error(mpl, "suffix .%s invalid", mpl->image);
+ get_token(mpl /* suffix */);
+ }
+ /* generate pseudo-code to take value of the object */
+ switch (avl_get_node_type(node))
+ { case A_INDEX:
+ arg.index.slot = slot;
+ arg.index.next = slot->list;
+ code = make_code(mpl, O_INDEX, &arg, A_SYMBOLIC, 0);
+ slot->list = code;
+ break;
+ case A_SET:
+ arg.set.set = set;
+ arg.set.list = list;
+ code = make_code(mpl, O_MEMSET, &arg, A_ELEMSET,
+ set->dimen);
+ break;
+ case A_PARAMETER:
+ arg.par.par = par;
+ arg.par.list = list;
+ if (par->type == A_SYMBOLIC)
+ code = make_code(mpl, O_MEMSYM, &arg, A_SYMBOLIC, 0);
+ else
+ code = make_code(mpl, O_MEMNUM, &arg, A_NUMERIC, 0);
+ break;
+ case A_VARIABLE:
+ if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
+ || suff == DOT_DUAL))
+ error(mpl, "invalid reference to status, primal value, o"
+ "r dual value of variable %s above solve statement",
+ var->name);
+ arg.var.var = var;
+ arg.var.list = list;
+ arg.var.suff = suff;
+ code = make_code(mpl, O_MEMVAR, &arg, suff == DOT_NONE ?
+ A_FORMULA : A_NUMERIC, 0);
+ break;
+ case A_CONSTRAINT:
+ if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
+ || suff == DOT_DUAL))
+ error(mpl, "invalid reference to status, primal value, o"
+ "r dual value of %s %s above solve statement",
+ con->type == A_CONSTRAINT ? "constraint" : "objective"
+ , con->name);
+ arg.con.con = con;
+ arg.con.list = list;
+ arg.con.suff = suff;
+ code = make_code(mpl, O_MEMCON, &arg, A_NUMERIC, 0);
+ break;
+ default:
+ xassert(node != node);
+ }
+ return code;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- numeric_argument - parse argument passed to built-in function.
+--
+-- This routine parses an argument passed to numeric built-in function
+-- using the syntax:
+--
+-- <arg> ::= <expression 5> */
+
+CODE *numeric_argument(MPL *mpl, char *func)
+{ CODE *x;
+ x = expression_5(mpl);
+ /* convert the argument to numeric type, if necessary */
+ if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ /* check that now the argument is of numeric type */
+ if (x->type != A_NUMERIC)
+ error(mpl, "argument for %s has invalid type", func);
+ xassert(x->dim == 0);
+ return x;
+}
+
+#if 1 /* 15/VII-2006 */
+CODE *symbolic_argument(MPL *mpl, char *func)
+{ CODE *x;
+ x = expression_5(mpl);
+ /* convert the argument to symbolic type, if necessary */
+ if (x->type == A_NUMERIC)
+ x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+ /* check that now the argument is of symbolic type */
+ if (x->type != A_SYMBOLIC)
+ error(mpl, "argument for %s has invalid type", func);
+ xassert(x->dim == 0);
+ return x;
+}
+#endif
+
+#if 1 /* 15/VII-2006 */
+CODE *elemset_argument(MPL *mpl, char *func)
+{ CODE *x;
+ x = expression_9(mpl);
+ if (x->type != A_ELEMSET)
+ error(mpl, "argument for %s has invalid type", func);
+ xassert(x->dim > 0);
+ return x;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- function_reference - parse reference to built-in function.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= abs ( <arg> )
+-- <primary expression> ::= ceil ( <arg> )
+-- <primary expression> ::= floor ( <arg> )
+-- <primary expression> ::= exp ( <arg> )
+-- <primary expression> ::= log ( <arg> )
+-- <primary expression> ::= log10 ( <arg> )
+-- <primary expression> ::= max ( <arg list> )
+-- <primary expression> ::= min ( <arg list> )
+-- <primary expression> ::= sqrt ( <arg> )
+-- <primary expression> ::= sin ( <arg> )
+-- <primary expression> ::= cos ( <arg> )
+-- <primary expression> ::= tan ( <arg> )
+-- <primary expression> ::= atan ( <arg> )
+-- <primary expression> ::= atan2 ( <arg> , <arg> )
+-- <primary expression> ::= round ( <arg> )
+-- <primary expression> ::= round ( <arg> , <arg> )
+-- <primary expression> ::= trunc ( <arg> )
+-- <primary expression> ::= trunc ( <arg> , <arg> )
+-- <primary expression> ::= Irand224 ( )
+-- <primary expression> ::= Uniform01 ( )
+-- <primary expression> ::= Uniform ( <arg> , <arg> )
+-- <primary expression> ::= Normal01 ( )
+-- <primary expression> ::= Normal ( <arg> , <arg> )
+-- <primary expression> ::= card ( <arg> )
+-- <primary expression> ::= length ( <arg> )
+-- <primary expression> ::= substr ( <arg> , <arg> )
+-- <primary expression> ::= substr ( <arg> , <arg> , <arg> )
+-- <primary expression> ::= str2time ( <arg> , <arg> )
+-- <primary expression> ::= time2str ( <arg> , <arg> )
+-- <primary expression> ::= gmtime ( )
+-- <arg list> ::= <arg>
+-- <arg list> ::= <arg list> , <arg> */
+
+CODE *function_reference(MPL *mpl)
+{ CODE *code;
+ OPERANDS arg;
+ int op;
+ char func[15+1];
+ /* determine operation code */
+ xassert(mpl->token == T_NAME);
+ if (strcmp(mpl->image, "abs") == 0)
+ op = O_ABS;
+ else if (strcmp(mpl->image, "ceil") == 0)
+ op = O_CEIL;
+ else if (strcmp(mpl->image, "floor") == 0)
+ op = O_FLOOR;
+ else if (strcmp(mpl->image, "exp") == 0)
+ op = O_EXP;
+ else if (strcmp(mpl->image, "log") == 0)
+ op = O_LOG;
+ else if (strcmp(mpl->image, "log10") == 0)
+ op = O_LOG10;
+ else if (strcmp(mpl->image, "sqrt") == 0)
+ op = O_SQRT;
+ else if (strcmp(mpl->image, "sin") == 0)
+ op = O_SIN;
+ else if (strcmp(mpl->image, "cos") == 0)
+ op = O_COS;
+ else if (strcmp(mpl->image, "tan") == 0)
+ op = O_TAN;
+ else if (strcmp(mpl->image, "atan") == 0)
+ op = O_ATAN;
+ else if (strcmp(mpl->image, "min") == 0)
+ op = O_MIN;
+ else if (strcmp(mpl->image, "max") == 0)
+ op = O_MAX;
+ else if (strcmp(mpl->image, "round") == 0)
+ op = O_ROUND;
+ else if (strcmp(mpl->image, "trunc") == 0)
+ op = O_TRUNC;
+ else if (strcmp(mpl->image, "Irand224") == 0)
+ op = O_IRAND224;
+ else if (strcmp(mpl->image, "Uniform01") == 0)
+ op = O_UNIFORM01;
+ else if (strcmp(mpl->image, "Uniform") == 0)
+ op = O_UNIFORM;
+ else if (strcmp(mpl->image, "Normal01") == 0)
+ op = O_NORMAL01;
+ else if (strcmp(mpl->image, "Normal") == 0)
+ op = O_NORMAL;
+ else if (strcmp(mpl->image, "card") == 0)
+ op = O_CARD;
+ else if (strcmp(mpl->image, "length") == 0)
+ op = O_LENGTH;
+ else if (strcmp(mpl->image, "substr") == 0)
+ op = O_SUBSTR;
+ else if (strcmp(mpl->image, "str2time") == 0)
+ op = O_STR2TIME;
+ else if (strcmp(mpl->image, "time2str") == 0)
+ op = O_TIME2STR;
+ else if (strcmp(mpl->image, "gmtime") == 0)
+ op = O_GMTIME;
+ else
+ error(mpl, "function %s unknown", mpl->image);
+ /* save symbolic name of the function */
+ strcpy(func, mpl->image);
+ xassert(strlen(func) < sizeof(func));
+ get_token(mpl /* <symbolic name> */);
+ /* check the left parenthesis that follows the function name */
+ xassert(mpl->token == T_LEFT);
+ get_token(mpl /* ( */);
+ /* parse argument list */
+ if (op == O_MIN || op == O_MAX)
+ { /* min and max allow arbitrary number of arguments */
+ arg.list = create_arg_list(mpl);
+ /* parse argument list */
+ for (;;)
+ { /* parse argument and append it to the operands list */
+ arg.list = expand_arg_list(mpl, arg.list,
+ numeric_argument(mpl, func));
+ /* check a token that follows the argument */
+ if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_RIGHT)
+ break;
+ else
+ error(mpl, "syntax error in argument list for %s", func);
+ }
+ }
+ else if (op == O_IRAND224 || op == O_UNIFORM01 || op ==
+ O_NORMAL01 || op == O_GMTIME)
+ { /* Irand224, Uniform01, Normal01, gmtime need no arguments */
+ if (mpl->token != T_RIGHT)
+ error(mpl, "%s needs no arguments", func);
+ }
+ else if (op == O_UNIFORM || op == O_NORMAL)
+ { /* Uniform and Normal need two arguments */
+ /* parse the first argument */
+ arg.arg.x = numeric_argument(mpl, func);
+ /* check a token that follows the first argument */
+ if (mpl->token == T_COMMA)
+ ;
+ else if (mpl->token == T_RIGHT)
+ error(mpl, "%s needs two arguments", func);
+ else
+ error(mpl, "syntax error in argument for %s", func);
+ get_token(mpl /* , */);
+ /* parse the second argument */
+ arg.arg.y = numeric_argument(mpl, func);
+ /* check a token that follows the second argument */
+ if (mpl->token == T_COMMA)
+ error(mpl, "%s needs two argument", func);
+ else if (mpl->token == T_RIGHT)
+ ;
+ else
+ error(mpl, "syntax error in argument for %s", func);
+ }
+ else if (op == O_ATAN || op == O_ROUND || op == O_TRUNC)
+ { /* atan, round, and trunc need one or two arguments */
+ /* parse the first argument */
+ arg.arg.x = numeric_argument(mpl, func);
+ /* parse the second argument, if specified */
+ if (mpl->token == T_COMMA)
+ { switch (op)
+ { case O_ATAN: op = O_ATAN2; break;
+ case O_ROUND: op = O_ROUND2; break;
+ case O_TRUNC: op = O_TRUNC2; break;
+ default: xassert(op != op);
+ }
+ get_token(mpl /* , */);
+ arg.arg.y = numeric_argument(mpl, func);
+ }
+ /* check a token that follows the last argument */
+ if (mpl->token == T_COMMA)
+ error(mpl, "%s needs one or two arguments", func);
+ else if (mpl->token == T_RIGHT)
+ ;
+ else
+ error(mpl, "syntax error in argument for %s", func);
+ }
+ else if (op == O_SUBSTR)
+ { /* substr needs two or three arguments */
+ /* parse the first argument */
+ arg.arg.x = symbolic_argument(mpl, func);
+ /* check a token that follows the first argument */
+ if (mpl->token == T_COMMA)
+ ;
+ else if (mpl->token == T_RIGHT)
+ error(mpl, "%s needs two or three arguments", func);
+ else
+ error(mpl, "syntax error in argument for %s", func);
+ get_token(mpl /* , */);
+ /* parse the second argument */
+ arg.arg.y = numeric_argument(mpl, func);
+ /* parse the third argument, if specified */
+ if (mpl->token == T_COMMA)
+ { op = O_SUBSTR3;
+ get_token(mpl /* , */);
+ arg.arg.z = numeric_argument(mpl, func);
+ }
+ /* check a token that follows the last argument */
+ if (mpl->token == T_COMMA)
+ error(mpl, "%s needs two or three arguments", func);
+ else if (mpl->token == T_RIGHT)
+ ;
+ else
+ error(mpl, "syntax error in argument for %s", func);
+ }
+ else if (op == O_STR2TIME)
+ { /* str2time needs two arguments, both symbolic */
+ /* parse the first argument */
+ arg.arg.x = symbolic_argument(mpl, func);
+ /* check a token that follows the first argument */
+ if (mpl->token == T_COMMA)
+ ;
+ else if (mpl->token == T_RIGHT)
+ error(mpl, "%s needs two arguments", func);
+ else
+ error(mpl, "syntax error in argument for %s", func);
+ get_token(mpl /* , */);
+ /* parse the second argument */
+ arg.arg.y = symbolic_argument(mpl, func);
+ /* check a token that follows the second argument */
+ if (mpl->token == T_COMMA)
+ error(mpl, "%s needs two argument", func);
+ else if (mpl->token == T_RIGHT)
+ ;
+ else
+ error(mpl, "syntax error in argument for %s", func);
+ }
+ else if (op == O_TIME2STR)
+ { /* time2str needs two arguments, numeric and symbolic */
+ /* parse the first argument */
+ arg.arg.x = numeric_argument(mpl, func);
+ /* check a token that follows the first argument */
+ if (mpl->token == T_COMMA)
+ ;
+ else if (mpl->token == T_RIGHT)
+ error(mpl, "%s needs two arguments", func);
+ else
+ error(mpl, "syntax error in argument for %s", func);
+ get_token(mpl /* , */);
+ /* parse the second argument */
+ arg.arg.y = symbolic_argument(mpl, func);
+ /* check a token that follows the second argument */
+ if (mpl->token == T_COMMA)
+ error(mpl, "%s needs two argument", func);
+ else if (mpl->token == T_RIGHT)
+ ;
+ else
+ error(mpl, "syntax error in argument for %s", func);
+ }
+ else
+ { /* other functions need one argument */
+ if (op == O_CARD)
+ arg.arg.x = elemset_argument(mpl, func);
+ else if (op == O_LENGTH)
+ arg.arg.x = symbolic_argument(mpl, func);
+ else
+ arg.arg.x = numeric_argument(mpl, func);
+ /* check a token that follows the argument */
+ if (mpl->token == T_COMMA)
+ error(mpl, "%s needs one argument", func);
+ else if (mpl->token == T_RIGHT)
+ ;
+ else
+ error(mpl, "syntax error in argument for %s", func);
+ }
+ /* make pseudo-code to call the built-in function */
+ if (op == O_SUBSTR || op == O_SUBSTR3 || op == O_TIME2STR)
+ code = make_code(mpl, op, &arg, A_SYMBOLIC, 0);
+ else
+ code = make_code(mpl, op, &arg, A_NUMERIC, 0);
+ /* the reference ends with the right parenthesis */
+ xassert(mpl->token == T_RIGHT);
+ get_token(mpl /* ) */);
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- create_domain - create empty domain.
+--
+-- This routine creates empty domain, which is initially empty, i.e.
+-- has no domain blocks. */
+
+DOMAIN *create_domain(MPL *mpl)
+{ DOMAIN *domain;
+ domain = alloc(DOMAIN);
+ domain->list = NULL;
+ domain->code = NULL;
+ return domain;
+}
+
+/*----------------------------------------------------------------------
+-- create_block - create empty domain block.
+--
+-- This routine creates empty domain block, which is initially empty,
+-- i.e. has no domain slots. */
+
+DOMAIN_BLOCK *create_block(MPL *mpl)
+{ DOMAIN_BLOCK *block;
+ block = alloc(DOMAIN_BLOCK);
+ block->list = NULL;
+ block->code = NULL;
+ block->backup = NULL;
+ block->next = NULL;
+ return block;
+}
+
+/*----------------------------------------------------------------------
+-- append_block - append domain block to specified domain.
+--
+-- This routine adds given domain block to the end of the block list of
+-- specified domain. */
+
+void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block)
+{ DOMAIN_BLOCK *temp;
+ xassert(mpl == mpl);
+ xassert(domain != NULL);
+ xassert(block != NULL);
+ xassert(block->next == NULL);
+ if (domain->list == NULL)
+ domain->list = block;
+ else
+ { for (temp = domain->list; temp->next != NULL; temp =
+ temp->next);
+ temp->next = block;
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- append_slot - create and append new slot to domain block.
+--
+-- This routine creates new domain slot and adds it to the end of slot
+-- list of specified domain block.
+--
+-- The parameter name is symbolic name of the dummy index associated
+-- with the slot (the character string must be allocated). NULL means
+-- the dummy index is not explicitly specified.
+--
+-- The parameter code is pseudo-code for computing symbolic value, at
+-- which the dummy index is bounded. NULL means the dummy index is free
+-- in the domain scope. */
+
+DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
+ CODE *code)
+{ DOMAIN_SLOT *slot, *temp;
+ xassert(block != NULL);
+ slot = alloc(DOMAIN_SLOT);
+ slot->name = name;
+ slot->code = code;
+ slot->value = NULL;
+ slot->list = NULL;
+ slot->next = NULL;
+ if (block->list == NULL)
+ block->list = slot;
+ else
+ { for (temp = block->list; temp->next != NULL; temp =
+ temp->next);
+ temp->next = slot;
+ }
+ return slot;
+}
+
+/*----------------------------------------------------------------------
+-- expression_list - parse expression list.
+--
+-- This routine parses a list of one or more expressions enclosed into
+-- the parentheses using the syntax:
+--
+-- <primary expression> ::= ( <expression list> )
+-- <expression list> ::= <expression 13>
+-- <expression list> ::= <expression 13> , <expression list>
+--
+-- Note that this construction may have three different meanings:
+--
+-- 1. If <expression list> consists of only one expression, <primary
+-- expression> is a parenthesized expression, which may be of any
+-- valid type (not necessarily 1-tuple).
+--
+-- 2. If <expression list> consists of several expressions separated by
+-- commae, where no expression is undeclared symbolic name, <primary
+-- expression> is a n-tuple.
+--
+-- 3. If <expression list> consists of several expressions separated by
+-- commae, where at least one expression is undeclared symbolic name
+-- (that denotes a dummy index), <primary expression> is a slice and
+-- can be only used as constituent of indexing expression. */
+
+#define max_dim 20
+/* maximal number of components allowed within parentheses */
+
+CODE *expression_list(MPL *mpl)
+{ CODE *code;
+ OPERANDS arg;
+ struct { char *name; CODE *code; } list[1+max_dim];
+ int flag_x, next_token, dim, j, slice = 0;
+ xassert(mpl->token == T_LEFT);
+ /* the flag, which allows recognizing undeclared symbolic names
+ as dummy indices, will be automatically reset by get_token(),
+ so save it before scanning the next token */
+ flag_x = mpl->flag_x;
+ get_token(mpl /* ( */);
+ /* parse <expression list> */
+ for (dim = 1; ; dim++)
+ { if (dim > max_dim)
+ error(mpl, "too many components within parentheses");
+ /* current component of <expression list> can be either dummy
+ index or expression */
+ if (mpl->token == T_NAME)
+ { /* symbolic name is recognized as dummy index only if:
+ the flag, which allows that, is set, and
+ the name is followed by comma or right parenthesis, and
+ the name is undeclared */
+ get_token(mpl /* <symbolic name> */);
+ next_token = mpl->token;
+ unget_token(mpl);
+ if (!(flag_x &&
+ (next_token == T_COMMA || next_token == T_RIGHT) &&
+ avl_find_node(mpl->tree, mpl->image) == NULL))
+ { /* this is not dummy index */
+ goto expr;
+ }
+ /* all dummy indices within the same slice must have unique
+ symbolic names */
+ for (j = 1; j < dim; j++)
+ { if (list[j].name != NULL && strcmp(list[j].name,
+ mpl->image) == 0)
+ error(mpl, "duplicate dummy index %s not allowed",
+ mpl->image);
+ }
+ /* current component of <expression list> is dummy index */
+ list[dim].name
+ = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(list[dim].name, mpl->image);
+ list[dim].code = NULL;
+ get_token(mpl /* <symbolic name> */);
+ /* <expression list> is a slice, because at least one dummy
+ index has appeared */
+ slice = 1;
+ /* note that the context ( <dummy index> ) is not allowed,
+ i.e. in this case <primary expression> is considered as
+ a parenthesized expression */
+ if (dim == 1 && mpl->token == T_RIGHT)
+ error(mpl, "%s not defined", list[dim].name);
+ }
+ else
+expr: { /* current component of <expression list> is expression */
+ code = expression_13(mpl);
+ /* if the current expression is followed by comma or it is
+ not the very first expression, entire <expression list>
+ is n-tuple or slice, in which case the current expression
+ should be converted to symbolic type, if necessary */
+ if (mpl->token == T_COMMA || dim > 1)
+ { if (code->type == A_NUMERIC)
+ code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
+ /* now the expression must be of symbolic type */
+ if (code->type != A_SYMBOLIC)
+ error(mpl, "component expression has invalid type");
+ xassert(code->dim == 0);
+ }
+ list[dim].name = NULL;
+ list[dim].code = code;
+ }
+ /* check a token that follows the current component */
+ if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_RIGHT)
+ break;
+ else
+ error(mpl, "right parenthesis missing where expected");
+ }
+ /* generate pseudo-code for <primary expression> */
+ if (dim == 1 && !slice)
+ { /* <primary expression> is a parenthesized expression */
+ code = list[1].code;
+ }
+ else if (!slice)
+ { /* <primary expression> is a n-tuple */
+ arg.list = create_arg_list(mpl);
+ for (j = 1; j <= dim; j++)
+ arg.list = expand_arg_list(mpl, arg.list, list[j].code);
+ code = make_code(mpl, O_TUPLE, &arg, A_TUPLE, dim);
+ }
+ else
+ { /* <primary expression> is a slice */
+ arg.slice = create_block(mpl);
+ for (j = 1; j <= dim; j++)
+ append_slot(mpl, arg.slice, list[j].name, list[j].code);
+ /* note that actually pseudo-codes with op = O_SLICE are never
+ evaluated */
+ code = make_code(mpl, O_SLICE, &arg, A_TUPLE, dim);
+ }
+ get_token(mpl /* ) */);
+ /* if <primary expression> is a slice, there must be the keyword
+ 'in', which follows the right parenthesis */
+ if (slice && mpl->token != T_IN)
+ error(mpl, "keyword in missing where expected");
+ /* if the slice flag is set and there is the keyword 'in', which
+ follows <primary expression>, the latter must be a slice */
+ if (flag_x && mpl->token == T_IN && !slice)
+ { if (dim == 1)
+ error(mpl, "syntax error in indexing expression");
+ else
+ error(mpl, "0-ary slice not allowed");
+ }
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- literal set - parse literal set.
+--
+-- This routine parses literal set using the syntax:
+--
+-- <literal set> ::= { <member list> }
+-- <member list> ::= <member expression>
+-- <member list> ::= <member list> , <member expression>
+-- <member expression> ::= <expression 5>
+--
+-- It is assumed that the left curly brace and the very first member
+-- expression that follows it are already parsed. The right curly brace
+-- remains unscanned on exit. */
+
+CODE *literal_set(MPL *mpl, CODE *code)
+{ OPERANDS arg;
+ int j;
+ xassert(code != NULL);
+ arg.list = create_arg_list(mpl);
+ /* parse <member list> */
+ for (j = 1; ; j++)
+ { /* all member expressions must be n-tuples; so, if the current
+ expression is not n-tuple, convert it to 1-tuple */
+ if (code->type == A_NUMERIC)
+ code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
+ if (code->type == A_SYMBOLIC)
+ code = make_unary(mpl, O_CVTTUP, code, A_TUPLE, 1);
+ /* now the expression must be n-tuple */
+ if (code->type != A_TUPLE)
+ error(mpl, "member expression has invalid type");
+ /* all member expressions must have identical dimension */
+ if (arg.list != NULL && arg.list->x->dim != code->dim)
+ error(mpl, "member %d has %d component%s while member %d ha"
+ "s %d component%s",
+ j-1, arg.list->x->dim, arg.list->x->dim == 1 ? "" : "s",
+ j, code->dim, code->dim == 1 ? "" : "s");
+ /* append the current expression to the member list */
+ arg.list = expand_arg_list(mpl, arg.list, code);
+ /* check a token that follows the current expression */
+ if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_RBRACE)
+ break;
+ else
+ error(mpl, "syntax error in literal set");
+ /* parse the next expression that follows the comma */
+ code = expression_5(mpl);
+ }
+ /* generate pseudo-code for <literal set> */
+ code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, arg.list->x->dim);
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- indexing_expression - parse indexing expression.
+--
+-- This routine parses indexing expression using the syntax:
+--
+-- <indexing expression> ::= <literal set>
+-- <indexing expression> ::= { <indexing list> }
+-- <indexing expression> ::= { <indexing list> : <logical expression> }
+-- <indexing list> ::= <indexing element>
+-- <indexing list> ::= <indexing list> , <indexing element>
+-- <indexing element> ::= <basic expression>
+-- <indexing element> ::= <dummy index> in <basic expression>
+-- <indexing element> ::= <slice> in <basic expression>
+-- <dummy index> ::= <symbolic name>
+-- <slice> ::= ( <expression list> )
+-- <basic expression> ::= <expression 9>
+-- <logical expression> ::= <expression 13>
+--
+-- This routine creates domain for <indexing expression>, where each
+-- domain block corresponds to <indexing element>, and each domain slot
+-- corresponds to individual indexing position. */
+
+DOMAIN *indexing_expression(MPL *mpl)
+{ DOMAIN *domain;
+ DOMAIN_BLOCK *block;
+ DOMAIN_SLOT *slot;
+ CODE *code;
+ xassert(mpl->token == T_LBRACE);
+ get_token(mpl /* { */);
+ if (mpl->token == T_RBRACE)
+ error(mpl, "empty indexing expression not allowed");
+ /* create domain to be constructed */
+ domain = create_domain(mpl);
+ /* parse either <member list> or <indexing list> that follows the
+ left brace */
+ for (;;)
+ { /* domain block for <indexing element> is not created yet */
+ block = NULL;
+ /* pseudo-code for <basic expression> is not generated yet */
+ code = NULL;
+ /* check a token, which <indexing element> begins with */
+ if (mpl->token == T_NAME)
+ { /* it is a symbolic name */
+ int next_token;
+ char *name;
+ /* symbolic name is recognized as dummy index only if it is
+ followed by the keyword 'in' and not declared */
+ get_token(mpl /* <symbolic name> */);
+ next_token = mpl->token;
+ unget_token(mpl);
+ if (!(next_token == T_IN &&
+ avl_find_node(mpl->tree, mpl->image) == NULL))
+ { /* this is not dummy index; the symbolic name begins an
+ expression, which is either <basic expression> or the
+ very first <member expression> in <literal set> */
+ goto expr;
+ }
+ /* create domain block with one slot, which is assigned the
+ dummy index */
+ block = create_block(mpl);
+ name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(name, mpl->image);
+ append_slot(mpl, block, name, NULL);
+ get_token(mpl /* <symbolic name> */);
+ /* the keyword 'in' is already checked above */
+ xassert(mpl->token == T_IN);
+ get_token(mpl /* in */);
+ /* <basic expression> that follows the keyword 'in' will be
+ parsed below */
+ }
+ else if (mpl->token == T_LEFT)
+ { /* it is the left parenthesis; parse expression that begins
+ with this parenthesis (the flag is set in order to allow
+ recognizing slices; see the routine expression_list) */
+ mpl->flag_x = 1;
+ code = expression_9(mpl);
+ if (code->op != O_SLICE)
+ { /* this is either <basic expression> or the very first
+ <member expression> in <literal set> */
+ goto expr;
+ }
+ /* this is a slice; besides the corresponding domain block
+ is already created by expression_list() */
+ block = code->arg.slice;
+ code = NULL; /* <basic expression> is not parsed yet */
+ /* the keyword 'in' following the slice is already checked
+ by expression_list() */
+ xassert(mpl->token == T_IN);
+ get_token(mpl /* in */);
+ /* <basic expression> that follows the keyword 'in' will be
+ parsed below */
+ }
+expr: /* parse expression that follows either the keyword 'in' (in
+ which case it can be <basic expression) or the left brace
+ (in which case it can be <basic expression> as well as the
+ very first <member expression> in <literal set>); note that
+ this expression can be already parsed above */
+ if (code == NULL) code = expression_9(mpl);
+ /* check the type of the expression just parsed */
+ if (code->type != A_ELEMSET)
+ { /* it is not <basic expression> and therefore it can only
+ be the very first <member expression> in <literal set>;
+ however, then there must be no dummy index neither slice
+ between the left brace and this expression */
+ if (block != NULL)
+ error(mpl, "domain expression has invalid type");
+ /* parse the rest part of <literal set> and make this set
+ be <basic expression>, i.e. the construction {a, b, c}
+ is parsed as it were written as {A}, where A = {a, b, c}
+ is a temporary elemental set */
+ code = literal_set(mpl, code);
+ }
+ /* now pseudo-code for <basic set> has been built */
+ xassert(code != NULL);
+ xassert(code->type == A_ELEMSET);
+ xassert(code->dim > 0);
+ /* if domain block for the current <indexing element> is still
+ not created, create it for fake slice of the same dimension
+ as <basic set> */
+ if (block == NULL)
+ { int j;
+ block = create_block(mpl);
+ for (j = 1; j <= code->dim; j++)
+ append_slot(mpl, block, NULL, NULL);
+ }
+ /* number of indexing positions in <indexing element> must be
+ the same as dimension of n-tuples in basic set */
+ { int dim = 0;
+ for (slot = block->list; slot != NULL; slot = slot->next)
+ dim++;
+ if (dim != code->dim)
+ error(mpl,"%d %s specified for set of dimension %d",
+ dim, dim == 1 ? "index" : "indices", code->dim);
+ }
+ /* store pseudo-code for <basic set> in the domain block */
+ xassert(block->code == NULL);
+ block->code = code;
+ /* and append the domain block to the domain */
+ append_block(mpl, domain, block);
+ /* the current <indexing element> has been completely parsed;
+ include all its dummy indices into the symbolic name table
+ to make them available for referencing from expressions;
+ implicit declarations of dummy indices remain valid while
+ the corresponding domain scope is valid */
+ for (slot = block->list; slot != NULL; slot = slot->next)
+ if (slot->name != NULL)
+ { AVLNODE *node;
+ xassert(avl_find_node(mpl->tree, slot->name) == NULL);
+ node = avl_insert_node(mpl->tree, slot->name);
+ avl_set_node_type(node, A_INDEX);
+ avl_set_node_link(node, (void *)slot);
+ }
+ /* check a token that follows <indexing element> */
+ if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_COLON || mpl->token == T_RBRACE)
+ break;
+ else
+ error(mpl, "syntax error in indexing expression");
+ }
+ /* parse <logical expression> that follows the colon */
+ if (mpl->token == T_COLON)
+ { get_token(mpl /* : */);
+ code = expression_13(mpl);
+ /* convert the expression to logical type, if necessary */
+ if (code->type == A_SYMBOLIC)
+ code = make_unary(mpl, O_CVTNUM, code, A_NUMERIC, 0);
+ if (code->type == A_NUMERIC)
+ code = make_unary(mpl, O_CVTLOG, code, A_LOGICAL, 0);
+ /* now the expression must be of logical type */
+ if (code->type != A_LOGICAL)
+ error(mpl, "expression following colon has invalid type");
+ xassert(code->dim == 0);
+ domain->code = code;
+ /* the right brace must follow the logical expression */
+ if (mpl->token != T_RBRACE)
+ error(mpl, "syntax error in indexing expression");
+ }
+ get_token(mpl /* } */);
+ return domain;
+}
+
+/*----------------------------------------------------------------------
+-- close_scope - close scope of indexing expression.
+--
+-- The routine closes the scope of indexing expression specified by its
+-- domain and thereby makes all dummy indices introduced in the indexing
+-- expression no longer available for referencing. */
+
+void close_scope(MPL *mpl, DOMAIN *domain)
+{ DOMAIN_BLOCK *block;
+ DOMAIN_SLOT *slot;
+ AVLNODE *node;
+ xassert(domain != NULL);
+ /* remove all dummy indices from the symbolic names table */
+ for (block = domain->list; block != NULL; block = block->next)
+ { for (slot = block->list; slot != NULL; slot = slot->next)
+ { if (slot->name != NULL)
+ { node = avl_find_node(mpl->tree, slot->name);
+ xassert(node != NULL);
+ xassert(avl_get_node_type(node) == A_INDEX);
+ avl_delete_node(mpl->tree, node);
+ }
+ }
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- iterated_expression - parse iterated expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <iterated expression>
+-- <iterated expression> ::= sum <indexing expression> <expression 3>
+-- <iterated expression> ::= prod <indexing expression> <expression 3>
+-- <iterated expression> ::= min <indexing expression> <expression 3>
+-- <iterated expression> ::= max <indexing expression> <expression 3>
+-- <iterated expression> ::= exists <indexing expression>
+-- <expression 12>
+-- <iterated expression> ::= forall <indexing expression>
+-- <expression 12>
+-- <iterated expression> ::= setof <indexing expression> <expression 5>
+--
+-- Note that parsing "integrand" depends on the iterated operator. */
+
+#if 1 /* 07/IX-2008 */
+static void link_up(CODE *code)
+{ /* if we have something like sum{(i+1,j,k-1) in E} x[i,j,k],
+ where i and k are dummy indices defined out of the iterated
+ expression, we should link up pseudo-code for computing i+1
+ and k-1 to pseudo-code for computing the iterated expression;
+ this is needed to invalidate current value of the iterated
+ expression once i or k have been changed */
+ DOMAIN_BLOCK *block;
+ DOMAIN_SLOT *slot;
+ for (block = code->arg.loop.domain->list; block != NULL;
+ block = block->next)
+ { for (slot = block->list; slot != NULL; slot = slot->next)
+ { if (slot->code != NULL)
+ { xassert(slot->code->up == NULL);
+ slot->code->up = code;
+ }
+ }
+ }
+ return;
+}
+#endif
+
+CODE *iterated_expression(MPL *mpl)
+{ CODE *code;
+ OPERANDS arg;
+ int op;
+ char opstr[8];
+ /* determine operation code */
+ xassert(mpl->token == T_NAME);
+ if (strcmp(mpl->image, "sum") == 0)
+ op = O_SUM;
+ else if (strcmp(mpl->image, "prod") == 0)
+ op = O_PROD;
+ else if (strcmp(mpl->image, "min") == 0)
+ op = O_MINIMUM;
+ else if (strcmp(mpl->image, "max") == 0)
+ op = O_MAXIMUM;
+ else if (strcmp(mpl->image, "forall") == 0)
+ op = O_FORALL;
+ else if (strcmp(mpl->image, "exists") == 0)
+ op = O_EXISTS;
+ else if (strcmp(mpl->image, "setof") == 0)
+ op = O_SETOF;
+ else
+ error(mpl, "operator %s unknown", mpl->image);
+ strcpy(opstr, mpl->image);
+ xassert(strlen(opstr) < sizeof(opstr));
+ get_token(mpl /* <symbolic name> */);
+ /* check the left brace that follows the operator name */
+ xassert(mpl->token == T_LBRACE);
+ /* parse indexing expression that controls iterating */
+ arg.loop.domain = indexing_expression(mpl);
+ /* parse "integrand" expression and generate pseudo-code */
+ switch (op)
+ { case O_SUM:
+ case O_PROD:
+ case O_MINIMUM:
+ case O_MAXIMUM:
+ arg.loop.x = expression_3(mpl);
+ /* convert the integrand to numeric type, if necessary */
+ if (arg.loop.x->type == A_SYMBOLIC)
+ arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
+ A_NUMERIC, 0);
+ /* now the integrand must be of numeric type or linear form
+ (the latter is only allowed for the sum operator) */
+ if (!(arg.loop.x->type == A_NUMERIC ||
+ op == O_SUM && arg.loop.x->type == A_FORMULA))
+err: error(mpl, "integrand following %s{...} has invalid type"
+ , opstr);
+ xassert(arg.loop.x->dim == 0);
+ /* generate pseudo-code */
+ code = make_code(mpl, op, &arg, arg.loop.x->type, 0);
+ break;
+ case O_FORALL:
+ case O_EXISTS:
+ arg.loop.x = expression_12(mpl);
+ /* convert the integrand to logical type, if necessary */
+ if (arg.loop.x->type == A_SYMBOLIC)
+ arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
+ A_NUMERIC, 0);
+ if (arg.loop.x->type == A_NUMERIC)
+ arg.loop.x = make_unary(mpl, O_CVTLOG, arg.loop.x,
+ A_LOGICAL, 0);
+ /* now the integrand must be of logical type */
+ if (arg.loop.x->type != A_LOGICAL) goto err;
+ xassert(arg.loop.x->dim == 0);
+ /* generate pseudo-code */
+ code = make_code(mpl, op, &arg, A_LOGICAL, 0);
+ break;
+ case O_SETOF:
+ arg.loop.x = expression_5(mpl);
+ /* convert the integrand to 1-tuple, if necessary */
+ if (arg.loop.x->type == A_NUMERIC)
+ arg.loop.x = make_unary(mpl, O_CVTSYM, arg.loop.x,
+ A_SYMBOLIC, 0);
+ if (arg.loop.x->type == A_SYMBOLIC)
+ arg.loop.x = make_unary(mpl, O_CVTTUP, arg.loop.x,
+ A_TUPLE, 1);
+ /* now the integrand must be n-tuple */
+ if (arg.loop.x->type != A_TUPLE) goto err;
+ xassert(arg.loop.x->dim > 0);
+ /* generate pseudo-code */
+ code = make_code(mpl, op, &arg, A_ELEMSET, arg.loop.x->dim);
+ break;
+ default:
+ xassert(op != op);
+ }
+ /* close the scope of the indexing expression */
+ close_scope(mpl, arg.loop.domain);
+#if 1 /* 07/IX-2008 */
+ link_up(code);
+#endif
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- domain_arity - determine arity of domain.
+--
+-- This routine returns arity of specified domain, which is number of
+-- its free dummy indices. */
+
+int domain_arity(MPL *mpl, DOMAIN *domain)
+{ DOMAIN_BLOCK *block;
+ DOMAIN_SLOT *slot;
+ int arity;
+ xassert(mpl == mpl);
+ arity = 0;
+ for (block = domain->list; block != NULL; block = block->next)
+ for (slot = block->list; slot != NULL; slot = slot->next)
+ if (slot->code == NULL) arity++;
+ return arity;
+}
+
+/*----------------------------------------------------------------------
+-- set_expression - parse set expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= { }
+-- <primary expression> ::= <indexing expression> */
+
+CODE *set_expression(MPL *mpl)
+{ CODE *code;
+ OPERANDS arg;
+ xassert(mpl->token == T_LBRACE);
+ get_token(mpl /* { */);
+ /* check a token that follows the left brace */
+ if (mpl->token == T_RBRACE)
+ { /* it is the right brace, so the resultant is an empty set of
+ dimension 1 */
+ arg.list = NULL;
+ /* generate pseudo-code to build the resultant set */
+ code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, 1);
+ get_token(mpl /* } */);
+ }
+ else
+ { /* the next token begins an indexing expression */
+ unget_token(mpl);
+ arg.loop.domain = indexing_expression(mpl);
+ arg.loop.x = NULL; /* integrand is not used */
+ /* close the scope of the indexing expression */
+ close_scope(mpl, arg.loop.domain);
+ /* generate pseudo-code to build the resultant set */
+ code = make_code(mpl, O_BUILD, &arg, A_ELEMSET,
+ domain_arity(mpl, arg.loop.domain));
+#if 1 /* 07/IX-2008 */
+ link_up(code);
+#endif
+ }
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- branched_expression - parse conditional expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <branched expression>
+-- <branched expression> ::= if <logical expression> then <expression 9>
+-- <branched expression> ::= if <logical expression> then <expression 9>
+-- else <expression 9>
+-- <logical expression> ::= <expression 13> */
+
+CODE *branched_expression(MPL *mpl)
+{ CODE *code, *x, *y, *z;
+ xassert(mpl->token == T_IF);
+ get_token(mpl /* if */);
+ /* parse <logical expression> that follows 'if' */
+ x = expression_13(mpl);
+ /* convert the expression to logical type, if necessary */
+ if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (x->type == A_NUMERIC)
+ x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+ /* now the expression must be of logical type */
+ if (x->type != A_LOGICAL)
+ error(mpl, "expression following if has invalid type");
+ xassert(x->dim == 0);
+ /* the keyword 'then' must follow the logical expression */
+ if (mpl->token != T_THEN)
+ error(mpl, "keyword then missing where expected");
+ get_token(mpl /* then */);
+ /* parse <expression> that follows 'then' and check its type */
+ y = expression_9(mpl);
+ if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC ||
+ y->type == A_ELEMSET || y->type == A_FORMULA))
+ error(mpl, "expression following then has invalid type");
+ /* if the expression that follows the keyword 'then' is elemental
+ set, the keyword 'else' cannot be omitted; otherwise else-part
+ is optional */
+ if (mpl->token != T_ELSE)
+ { if (y->type == A_ELEMSET)
+ error(mpl, "keyword else missing where expected");
+ z = NULL;
+ goto skip;
+ }
+ get_token(mpl /* else */);
+ /* parse <expression> that follow 'else' and check its type */
+ z = expression_9(mpl);
+ if (!(z->type == A_NUMERIC || z->type == A_SYMBOLIC ||
+ z->type == A_ELEMSET || z->type == A_FORMULA))
+ error(mpl, "expression following else has invalid type");
+ /* convert to identical types, if necessary */
+ if (y->type == A_FORMULA || z->type == A_FORMULA)
+ { if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (y->type == A_NUMERIC)
+ y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
+ if (z->type == A_SYMBOLIC)
+ z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
+ if (z->type == A_NUMERIC)
+ z = make_unary(mpl, O_CVTLFM, z, A_FORMULA, 0);
+ }
+ if (y->type == A_SYMBOLIC || z->type == A_SYMBOLIC)
+ { if (y->type == A_NUMERIC)
+ y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
+ if (z->type == A_NUMERIC)
+ z = make_unary(mpl, O_CVTSYM, z, A_SYMBOLIC, 0);
+ }
+ /* now both expressions must have identical types */
+ if (y->type != z->type)
+ error(mpl, "expressions following then and else have incompati"
+ "ble types");
+ /* and identical dimensions */
+ if (y->dim != z->dim)
+ error(mpl, "expressions following then and else have different"
+ " dimensions %d and %d, respectively", y->dim, z->dim);
+skip: /* generate pseudo-code to perform branching */
+ code = make_ternary(mpl, O_FORK, x, y, z, y->type, y->dim);
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- primary_expression - parse primary expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <numeric literal>
+-- <primary expression> ::= Infinity
+-- <primary expression> ::= <string literal>
+-- <primary expression> ::= <dummy index>
+-- <primary expression> ::= <set name>
+-- <primary expression> ::= <set name> [ <subscript list> ]
+-- <primary expression> ::= <parameter name>
+-- <primary expression> ::= <parameter name> [ <subscript list> ]
+-- <primary expression> ::= <variable name>
+-- <primary expression> ::= <variable name> [ <subscript list> ]
+-- <primary expression> ::= <built-in function> ( <argument list> )
+-- <primary expression> ::= ( <expression list> )
+-- <primary expression> ::= <iterated expression>
+-- <primary expression> ::= { }
+-- <primary expression> ::= <indexing expression>
+-- <primary expression> ::= <branched expression>
+--
+-- For complete list of syntactic rules for <primary expression> see
+-- comments to the corresponding parsing routines. */
+
+CODE *primary_expression(MPL *mpl)
+{ CODE *code;
+ if (mpl->token == T_NUMBER)
+ { /* parse numeric literal */
+ code = numeric_literal(mpl);
+ }
+#if 1 /* 21/VII-2006 */
+ else if (mpl->token == T_INFINITY)
+ { /* parse "infinity" */
+ OPERANDS arg;
+ arg.num = DBL_MAX;
+ code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
+ get_token(mpl /* Infinity */);
+ }
+#endif
+ else if (mpl->token == T_STRING)
+ { /* parse string literal */
+ code = string_literal(mpl);
+ }
+ else if (mpl->token == T_NAME)
+ { int next_token;
+ get_token(mpl /* <symbolic name> */);
+ next_token = mpl->token;
+ unget_token(mpl);
+ /* check a token that follows <symbolic name> */
+ switch (next_token)
+ { case T_LBRACKET:
+ /* parse reference to subscripted object */
+ code = object_reference(mpl);
+ break;
+ case T_LEFT:
+ /* parse reference to built-in function */
+ code = function_reference(mpl);
+ break;
+ case T_LBRACE:
+ /* parse iterated expression */
+ code = iterated_expression(mpl);
+ break;
+ default:
+ /* parse reference to unsubscripted object */
+ code = object_reference(mpl);
+ break;
+ }
+ }
+ else if (mpl->token == T_LEFT)
+ { /* parse parenthesized expression */
+ code = expression_list(mpl);
+ }
+ else if (mpl->token == T_LBRACE)
+ { /* parse set expression */
+ code = set_expression(mpl);
+ }
+ else if (mpl->token == T_IF)
+ { /* parse conditional expression */
+ code = branched_expression(mpl);
+ }
+ else if (is_reserved(mpl))
+ { /* other reserved keywords cannot be used here */
+ error(mpl, "invalid use of reserved keyword %s", mpl->image);
+ }
+ else
+ error(mpl, "syntax error in expression");
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- error_preceding - raise error if preceding operand has wrong type.
+--
+-- This routine is called to raise error if operand that precedes some
+-- infix operator has invalid type. */
+
+void error_preceding(MPL *mpl, char *opstr)
+{ error(mpl, "operand preceding %s has invalid type", opstr);
+ /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- error_following - raise error if following operand has wrong type.
+--
+-- This routine is called to raise error if operand that follows some
+-- infix operator has invalid type. */
+
+void error_following(MPL *mpl, char *opstr)
+{ error(mpl, "operand following %s has invalid type", opstr);
+ /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- error_dimension - raise error if operands have different dimension.
+--
+-- This routine is called to raise error if two operands of some infix
+-- operator have different dimension. */
+
+void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2)
+{ error(mpl, "operands preceding and following %s have different di"
+ "mensions %d and %d, respectively", opstr, dim1, dim2);
+ /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- expression_0 - parse expression of level 0.
+--
+-- This routine parses expression of level 0 using the syntax:
+--
+-- <expression 0> ::= <primary expression> */
+
+CODE *expression_0(MPL *mpl)
+{ CODE *code;
+ code = primary_expression(mpl);
+ return code;
+}
+
+/*----------------------------------------------------------------------
+-- expression_1 - parse expression of level 1.
+--
+-- This routine parses expression of level 1 using the syntax:
+--
+-- <expression 1> ::= <expression 0>
+-- <expression 1> ::= <expression 0> <power> <expression 1>
+-- <expression 1> ::= <expression 0> <power> <expression 2>
+-- <power> ::= ^ | ** */
+
+CODE *expression_1(MPL *mpl)
+{ CODE *x, *y;
+ char opstr[8];
+ x = expression_0(mpl);
+ if (mpl->token == T_POWER)
+ { strcpy(opstr, mpl->image);
+ xassert(strlen(opstr) < sizeof(opstr));
+ if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (x->type != A_NUMERIC)
+ error_preceding(mpl, opstr);
+ get_token(mpl /* ^ | ** */);
+ if (mpl->token == T_PLUS || mpl->token == T_MINUS)
+ y = expression_2(mpl);
+ else
+ y = expression_1(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (y->type != A_NUMERIC)
+ error_following(mpl, opstr);
+ x = make_binary(mpl, O_POWER, x, y, A_NUMERIC, 0);
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_2 - parse expression of level 2.
+--
+-- This routine parses expression of level 2 using the syntax:
+--
+-- <expression 2> ::= <expression 1>
+-- <expression 2> ::= + <expression 1>
+-- <expression 2> ::= - <expression 1> */
+
+CODE *expression_2(MPL *mpl)
+{ CODE *x;
+ if (mpl->token == T_PLUS)
+ { get_token(mpl /* + */);
+ x = expression_1(mpl);
+ if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+ error_following(mpl, "+");
+ x = make_unary(mpl, O_PLUS, x, x->type, 0);
+ }
+ else if (mpl->token == T_MINUS)
+ { get_token(mpl /* - */);
+ x = expression_1(mpl);
+ if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+ error_following(mpl, "-");
+ x = make_unary(mpl, O_MINUS, x, x->type, 0);
+ }
+ else
+ x = expression_1(mpl);
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_3 - parse expression of level 3.
+--
+-- This routine parses expression of level 3 using the syntax:
+--
+-- <expression 3> ::= <expression 2>
+-- <expression 3> ::= <expression 3> * <expression 2>
+-- <expression 3> ::= <expression 3> / <expression 2>
+-- <expression 3> ::= <expression 3> div <expression 2>
+-- <expression 3> ::= <expression 3> mod <expression 2> */
+
+CODE *expression_3(MPL *mpl)
+{ CODE *x, *y;
+ x = expression_2(mpl);
+ for (;;)
+ { if (mpl->token == T_ASTERISK)
+ { if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+ error_preceding(mpl, "*");
+ get_token(mpl /* * */);
+ y = expression_2(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
+ error_following(mpl, "*");
+ if (x->type == A_FORMULA && y->type == A_FORMULA)
+ error(mpl, "multiplication of linear forms not allowed");
+ if (x->type == A_NUMERIC && y->type == A_NUMERIC)
+ x = make_binary(mpl, O_MUL, x, y, A_NUMERIC, 0);
+ else
+ x = make_binary(mpl, O_MUL, x, y, A_FORMULA, 0);
+ }
+ else if (mpl->token == T_SLASH)
+ { if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+ error_preceding(mpl, "/");
+ get_token(mpl /* / */);
+ y = expression_2(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (y->type != A_NUMERIC)
+ error_following(mpl, "/");
+ if (x->type == A_NUMERIC)
+ x = make_binary(mpl, O_DIV, x, y, A_NUMERIC, 0);
+ else
+ x = make_binary(mpl, O_DIV, x, y, A_FORMULA, 0);
+ }
+ else if (mpl->token == T_DIV)
+ { if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (x->type != A_NUMERIC)
+ error_preceding(mpl, "div");
+ get_token(mpl /* div */);
+ y = expression_2(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (y->type != A_NUMERIC)
+ error_following(mpl, "div");
+ x = make_binary(mpl, O_IDIV, x, y, A_NUMERIC, 0);
+ }
+ else if (mpl->token == T_MOD)
+ { if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (x->type != A_NUMERIC)
+ error_preceding(mpl, "mod");
+ get_token(mpl /* mod */);
+ y = expression_2(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (y->type != A_NUMERIC)
+ error_following(mpl, "mod");
+ x = make_binary(mpl, O_MOD, x, y, A_NUMERIC, 0);
+ }
+ else
+ break;
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_4 - parse expression of level 4.
+--
+-- This routine parses expression of level 4 using the syntax:
+--
+-- <expression 4> ::= <expression 3>
+-- <expression 4> ::= <expression 4> + <expression 3>
+-- <expression 4> ::= <expression 4> - <expression 3>
+-- <expression 4> ::= <expression 4> less <expression 3> */
+
+CODE *expression_4(MPL *mpl)
+{ CODE *x, *y;
+ x = expression_3(mpl);
+ for (;;)
+ { if (mpl->token == T_PLUS)
+ { if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+ error_preceding(mpl, "+");
+ get_token(mpl /* + */);
+ y = expression_3(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
+ error_following(mpl, "+");
+ if (x->type == A_NUMERIC && y->type == A_FORMULA)
+ x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
+ if (x->type == A_FORMULA && y->type == A_NUMERIC)
+ y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
+ x = make_binary(mpl, O_ADD, x, y, x->type, 0);
+ }
+ else if (mpl->token == T_MINUS)
+ { if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+ error_preceding(mpl, "-");
+ get_token(mpl /* - */);
+ y = expression_3(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
+ error_following(mpl, "-");
+ if (x->type == A_NUMERIC && y->type == A_FORMULA)
+ x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
+ if (x->type == A_FORMULA && y->type == A_NUMERIC)
+ y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
+ x = make_binary(mpl, O_SUB, x, y, x->type, 0);
+ }
+ else if (mpl->token == T_LESS)
+ { if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (x->type != A_NUMERIC)
+ error_preceding(mpl, "less");
+ get_token(mpl /* less */);
+ y = expression_3(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (y->type != A_NUMERIC)
+ error_following(mpl, "less");
+ x = make_binary(mpl, O_LESS, x, y, A_NUMERIC, 0);
+ }
+ else
+ break;
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_5 - parse expression of level 5.
+--
+-- This routine parses expression of level 5 using the syntax:
+--
+-- <expression 5> ::= <expression 4>
+-- <expression 5> ::= <expression 5> & <expression 4> */
+
+CODE *expression_5(MPL *mpl)
+{ CODE *x, *y;
+ x = expression_4(mpl);
+ for (;;)
+ { if (mpl->token == T_CONCAT)
+ { if (x->type == A_NUMERIC)
+ x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+ if (x->type != A_SYMBOLIC)
+ error_preceding(mpl, "&");
+ get_token(mpl /* & */);
+ y = expression_4(mpl);
+ if (y->type == A_NUMERIC)
+ y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
+ if (y->type != A_SYMBOLIC)
+ error_following(mpl, "&");
+ x = make_binary(mpl, O_CONCAT, x, y, A_SYMBOLIC, 0);
+ }
+ else
+ break;
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_6 - parse expression of level 6.
+--
+-- This routine parses expression of level 6 using the syntax:
+--
+-- <expression 6> ::= <expression 5>
+-- <expression 6> ::= <expression 5> .. <expression 5>
+-- <expression 6> ::= <expression 5> .. <expression 5> by
+-- <expression 5> */
+
+CODE *expression_6(MPL *mpl)
+{ CODE *x, *y, *z;
+ x = expression_5(mpl);
+ if (mpl->token == T_DOTS)
+ { if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (x->type != A_NUMERIC)
+ error_preceding(mpl, "..");
+ get_token(mpl /* .. */);
+ y = expression_5(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (y->type != A_NUMERIC)
+ error_following(mpl, "..");
+ if (mpl->token == T_BY)
+ { get_token(mpl /* by */);
+ z = expression_5(mpl);
+ if (z->type == A_SYMBOLIC)
+ z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
+ if (z->type != A_NUMERIC)
+ error_following(mpl, "by");
+ }
+ else
+ z = NULL;
+ x = make_ternary(mpl, O_DOTS, x, y, z, A_ELEMSET, 1);
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_7 - parse expression of level 7.
+--
+-- This routine parses expression of level 7 using the syntax:
+--
+-- <expression 7> ::= <expression 6>
+-- <expression 7> ::= <expression 7> cross <expression 6> */
+
+CODE *expression_7(MPL *mpl)
+{ CODE *x, *y;
+ x = expression_6(mpl);
+ for (;;)
+ { if (mpl->token == T_CROSS)
+ { if (x->type != A_ELEMSET)
+ error_preceding(mpl, "cross");
+ get_token(mpl /* cross */);
+ y = expression_6(mpl);
+ if (y->type != A_ELEMSET)
+ error_following(mpl, "cross");
+ x = make_binary(mpl, O_CROSS, x, y, A_ELEMSET,
+ x->dim + y->dim);
+ }
+ else
+ break;
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_8 - parse expression of level 8.
+--
+-- This routine parses expression of level 8 using the syntax:
+--
+-- <expression 8> ::= <expression 7>
+-- <expression 8> ::= <expression 8> inter <expression 7> */
+
+CODE *expression_8(MPL *mpl)
+{ CODE *x, *y;
+ x = expression_7(mpl);
+ for (;;)
+ { if (mpl->token == T_INTER)
+ { if (x->type != A_ELEMSET)
+ error_preceding(mpl, "inter");
+ get_token(mpl /* inter */);
+ y = expression_7(mpl);
+ if (y->type != A_ELEMSET)
+ error_following(mpl, "inter");
+ if (x->dim != y->dim)
+ error_dimension(mpl, "inter", x->dim, y->dim);
+ x = make_binary(mpl, O_INTER, x, y, A_ELEMSET, x->dim);
+ }
+ else
+ break;
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_9 - parse expression of level 9.
+--
+-- This routine parses expression of level 9 using the syntax:
+--
+-- <expression 9> ::= <expression 8>
+-- <expression 9> ::= <expression 9> union <expression 8>
+-- <expression 9> ::= <expression 9> diff <expression 8>
+-- <expression 9> ::= <expression 9> symdiff <expression 8> */
+
+CODE *expression_9(MPL *mpl)
+{ CODE *x, *y;
+ x = expression_8(mpl);
+ for (;;)
+ { if (mpl->token == T_UNION)
+ { if (x->type != A_ELEMSET)
+ error_preceding(mpl, "union");
+ get_token(mpl /* union */);
+ y = expression_8(mpl);
+ if (y->type != A_ELEMSET)
+ error_following(mpl, "union");
+ if (x->dim != y->dim)
+ error_dimension(mpl, "union", x->dim, y->dim);
+ x = make_binary(mpl, O_UNION, x, y, A_ELEMSET, x->dim);
+ }
+ else if (mpl->token == T_DIFF)
+ { if (x->type != A_ELEMSET)
+ error_preceding(mpl, "diff");
+ get_token(mpl /* diff */);
+ y = expression_8(mpl);
+ if (y->type != A_ELEMSET)
+ error_following(mpl, "diff");
+ if (x->dim != y->dim)
+ error_dimension(mpl, "diff", x->dim, y->dim);
+ x = make_binary(mpl, O_DIFF, x, y, A_ELEMSET, x->dim);
+ }
+ else if (mpl->token == T_SYMDIFF)
+ { if (x->type != A_ELEMSET)
+ error_preceding(mpl, "symdiff");
+ get_token(mpl /* symdiff */);
+ y = expression_8(mpl);
+ if (y->type != A_ELEMSET)
+ error_following(mpl, "symdiff");
+ if (x->dim != y->dim)
+ error_dimension(mpl, "symdiff", x->dim, y->dim);
+ x = make_binary(mpl, O_SYMDIFF, x, y, A_ELEMSET, x->dim);
+ }
+ else
+ break;
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_10 - parse expression of level 10.
+--
+-- This routine parses expression of level 10 using the syntax:
+--
+-- <expression 10> ::= <expression 9>
+-- <expression 10> ::= <expression 9> <rho> <expression 9>
+-- <rho> ::= < | <= | = | == | >= | > | <> | != | in | not in | ! in |
+-- within | not within | ! within */
+
+CODE *expression_10(MPL *mpl)
+{ CODE *x, *y;
+ int op = -1;
+ char opstr[16];
+ x = expression_9(mpl);
+ strcpy(opstr, "");
+ switch (mpl->token)
+ { case T_LT:
+ op = O_LT; break;
+ case T_LE:
+ op = O_LE; break;
+ case T_EQ:
+ op = O_EQ; break;
+ case T_GE:
+ op = O_GE; break;
+ case T_GT:
+ op = O_GT; break;
+ case T_NE:
+ op = O_NE; break;
+ case T_IN:
+ op = O_IN; break;
+ case T_WITHIN:
+ op = O_WITHIN; break;
+ case T_NOT:
+ strcpy(opstr, mpl->image);
+ get_token(mpl /* not | ! */);
+ if (mpl->token == T_IN)
+ op = O_NOTIN;
+ else if (mpl->token == T_WITHIN)
+ op = O_NOTWITHIN;
+ else
+ error(mpl, "invalid use of %s", opstr);
+ strcat(opstr, " ");
+ break;
+ default:
+ goto done;
+ }
+ strcat(opstr, mpl->image);
+ xassert(strlen(opstr) < sizeof(opstr));
+ switch (op)
+ { case O_EQ:
+ case O_NE:
+#if 1 /* 02/VIII-2008 */
+ case O_LT:
+ case O_LE:
+ case O_GT:
+ case O_GE:
+#endif
+ if (!(x->type == A_NUMERIC || x->type == A_SYMBOLIC))
+ error_preceding(mpl, opstr);
+ get_token(mpl /* <rho> */);
+ y = expression_9(mpl);
+ if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC))
+ error_following(mpl, opstr);
+ if (x->type == A_NUMERIC && y->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+ if (x->type == A_SYMBOLIC && y->type == A_NUMERIC)
+ y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
+ x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+ break;
+#if 0 /* 02/VIII-2008 */
+ case O_LT:
+ case O_LE:
+ case O_GT:
+ case O_GE:
+ if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (x->type != A_NUMERIC)
+ error_preceding(mpl, opstr);
+ get_token(mpl /* <rho> */);
+ y = expression_9(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (y->type != A_NUMERIC)
+ error_following(mpl, opstr);
+ x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+ break;
+#endif
+ case O_IN:
+ case O_NOTIN:
+ if (x->type == A_NUMERIC)
+ x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+ if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTTUP, x, A_TUPLE, 1);
+ if (x->type != A_TUPLE)
+ error_preceding(mpl, opstr);
+ get_token(mpl /* <rho> */);
+ y = expression_9(mpl);
+ if (y->type != A_ELEMSET)
+ error_following(mpl, opstr);
+ if (x->dim != y->dim)
+ error_dimension(mpl, opstr, x->dim, y->dim);
+ x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+ break;
+ case O_WITHIN:
+ case O_NOTWITHIN:
+ if (x->type != A_ELEMSET)
+ error_preceding(mpl, opstr);
+ get_token(mpl /* <rho> */);
+ y = expression_9(mpl);
+ if (y->type != A_ELEMSET)
+ error_following(mpl, opstr);
+ if (x->dim != y->dim)
+ error_dimension(mpl, opstr, x->dim, y->dim);
+ x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+ break;
+ default:
+ xassert(op != op);
+ }
+done: return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_11 - parse expression of level 11.
+--
+-- This routine parses expression of level 11 using the syntax:
+--
+-- <expression 11> ::= <expression 10>
+-- <expression 11> ::= not <expression 10>
+-- <expression 11> ::= ! <expression 10> */
+
+CODE *expression_11(MPL *mpl)
+{ CODE *x;
+ char opstr[8];
+ if (mpl->token == T_NOT)
+ { strcpy(opstr, mpl->image);
+ xassert(strlen(opstr) < sizeof(opstr));
+ get_token(mpl /* not | ! */);
+ x = expression_10(mpl);
+ if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (x->type == A_NUMERIC)
+ x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+ if (x->type != A_LOGICAL)
+ error_following(mpl, opstr);
+ x = make_unary(mpl, O_NOT, x, A_LOGICAL, 0);
+ }
+ else
+ x = expression_10(mpl);
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_12 - parse expression of level 12.
+--
+-- This routine parses expression of level 12 using the syntax:
+--
+-- <expression 12> ::= <expression 11>
+-- <expression 12> ::= <expression 12> and <expression 11>
+-- <expression 12> ::= <expression 12> && <expression 11> */
+
+CODE *expression_12(MPL *mpl)
+{ CODE *x, *y;
+ char opstr[8];
+ x = expression_11(mpl);
+ for (;;)
+ { if (mpl->token == T_AND)
+ { strcpy(opstr, mpl->image);
+ xassert(strlen(opstr) < sizeof(opstr));
+ if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (x->type == A_NUMERIC)
+ x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+ if (x->type != A_LOGICAL)
+ error_preceding(mpl, opstr);
+ get_token(mpl /* and | && */);
+ y = expression_11(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (y->type == A_NUMERIC)
+ y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
+ if (y->type != A_LOGICAL)
+ error_following(mpl, opstr);
+ x = make_binary(mpl, O_AND, x, y, A_LOGICAL, 0);
+ }
+ else
+ break;
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_13 - parse expression of level 13.
+--
+-- This routine parses expression of level 13 using the syntax:
+--
+-- <expression 13> ::= <expression 12>
+-- <expression 13> ::= <expression 13> or <expression 12>
+-- <expression 13> ::= <expression 13> || <expression 12> */
+
+CODE *expression_13(MPL *mpl)
+{ CODE *x, *y;
+ char opstr[8];
+ x = expression_12(mpl);
+ for (;;)
+ { if (mpl->token == T_OR)
+ { strcpy(opstr, mpl->image);
+ xassert(strlen(opstr) < sizeof(opstr));
+ if (x->type == A_SYMBOLIC)
+ x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+ if (x->type == A_NUMERIC)
+ x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+ if (x->type != A_LOGICAL)
+ error_preceding(mpl, opstr);
+ get_token(mpl /* or | || */);
+ y = expression_12(mpl);
+ if (y->type == A_SYMBOLIC)
+ y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+ if (y->type == A_NUMERIC)
+ y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
+ if (y->type != A_LOGICAL)
+ error_following(mpl, opstr);
+ x = make_binary(mpl, O_OR, x, y, A_LOGICAL, 0);
+ }
+ else
+ break;
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- set_statement - parse set statement.
+--
+-- This routine parses set statement using the syntax:
+--
+-- <set statement> ::= set <symbolic name> <alias> <domain>
+-- <attributes> ;
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <attributes> ::= <empty>
+-- <attributes> ::= <attributes> , dimen <numeric literal>
+-- <attributes> ::= <attributes> , within <expression 9>
+-- <attributes> ::= <attributes> , := <expression 9>
+-- <attributes> ::= <attributes> , default <expression 9>
+--
+-- Commae in <attributes> are optional and may be omitted anywhere. */
+
+SET *set_statement(MPL *mpl)
+{ SET *set;
+ int dimen_used = 0;
+ xassert(is_keyword(mpl, "set"));
+ get_token(mpl /* set */);
+ /* symbolic name must follow the keyword 'set' */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl, "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "symbolic name missing where expected");
+ /* there must be no other object with the same name */
+ if (avl_find_node(mpl->tree, mpl->image) != NULL)
+ error(mpl, "%s multiply declared", mpl->image);
+ /* create model set */
+ set = alloc(SET);
+ set->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(set->name, mpl->image);
+ set->alias = NULL;
+ set->dim = 0;
+ set->domain = NULL;
+ set->dimen = 0;
+ set->within = NULL;
+ set->assign = NULL;
+ set->option = NULL;
+ set->gadget = NULL;
+ set->data = 0;
+ set->array = NULL;
+ get_token(mpl /* <symbolic name> */);
+ /* parse optional alias */
+ if (mpl->token == T_STRING)
+ { set->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(set->alias, mpl->image);
+ get_token(mpl /* <string literal> */);
+ }
+ /* parse optional indexing expression */
+ if (mpl->token == T_LBRACE)
+ { set->domain = indexing_expression(mpl);
+ set->dim = domain_arity(mpl, set->domain);
+ }
+ /* include the set name in the symbolic names table */
+ { AVLNODE *node;
+ node = avl_insert_node(mpl->tree, set->name);
+ avl_set_node_type(node, A_SET);
+ avl_set_node_link(node, (void *)set);
+ }
+ /* parse the list of optional attributes */
+ for (;;)
+ { if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_SEMICOLON)
+ break;
+ if (is_keyword(mpl, "dimen"))
+ { /* dimension of set members */
+ int dimen;
+ get_token(mpl /* dimen */);
+ if (!(mpl->token == T_NUMBER &&
+ 1.0 <= mpl->value && mpl->value <= 20.0 &&
+ floor(mpl->value) == mpl->value))
+ error(mpl, "dimension must be integer between 1 and 20");
+ dimen = (int)(mpl->value + 0.5);
+ if (dimen_used)
+ error(mpl, "at most one dimension attribute allowed");
+ if (set->dimen > 0)
+ error(mpl, "dimension %d conflicts with dimension %d alr"
+ "eady determined", dimen, set->dimen);
+ set->dimen = dimen;
+ dimen_used = 1;
+ get_token(mpl /* <numeric literal> */);
+ }
+ else if (mpl->token == T_WITHIN || mpl->token == T_IN)
+ { /* restricting superset */
+ WITHIN *within, *temp;
+ if (mpl->token == T_IN && !mpl->as_within)
+ { warning(mpl, "keyword in understood as within");
+ mpl->as_within = 1;
+ }
+ get_token(mpl /* within */);
+ /* create new restricting superset list entry and append it
+ to the within-list */
+ within = alloc(WITHIN);
+ within->code = NULL;
+ within->next = NULL;
+ if (set->within == NULL)
+ set->within = within;
+ else
+ { for (temp = set->within; temp->next != NULL; temp =
+ temp->next);
+ temp->next = within;
+ }
+ /* parse an expression that follows 'within' */
+ within->code = expression_9(mpl);
+ if (within->code->type != A_ELEMSET)
+ error(mpl, "expression following within has invalid type"
+ );
+ xassert(within->code->dim > 0);
+ /* check/set dimension of set members */
+ if (set->dimen == 0) set->dimen = within->code->dim;
+ if (set->dimen != within->code->dim)
+ error(mpl, "set expression following within must have di"
+ "mension %d rather than %d",
+ set->dimen, within->code->dim);
+ }
+ else if (mpl->token == T_ASSIGN)
+ { /* assignment expression */
+ if (!(set->assign == NULL && set->option == NULL &&
+ set->gadget == NULL))
+err: error(mpl, "at most one := or default/data allowed");
+ get_token(mpl /* := */);
+ /* parse an expression that follows ':=' */
+ set->assign = expression_9(mpl);
+ if (set->assign->type != A_ELEMSET)
+ error(mpl, "expression following := has invalid type");
+ xassert(set->assign->dim > 0);
+ /* check/set dimension of set members */
+ if (set->dimen == 0) set->dimen = set->assign->dim;
+ if (set->dimen != set->assign->dim)
+ error(mpl, "set expression following := must have dimens"
+ "ion %d rather than %d",
+ set->dimen, set->assign->dim);
+ }
+ else if (is_keyword(mpl, "default"))
+ { /* expression for default value */
+ if (!(set->assign == NULL && set->option == NULL)) goto err;
+ get_token(mpl /* := */);
+ /* parse an expression that follows 'default' */
+ set->option = expression_9(mpl);
+ if (set->option->type != A_ELEMSET)
+ error(mpl, "expression following default has invalid typ"
+ "e");
+ xassert(set->option->dim > 0);
+ /* check/set dimension of set members */
+ if (set->dimen == 0) set->dimen = set->option->dim;
+ if (set->dimen != set->option->dim)
+ error(mpl, "set expression following default must have d"
+ "imension %d rather than %d",
+ set->dimen, set->option->dim);
+ }
+#if 1 /* 12/XII-2008 */
+ else if (is_keyword(mpl, "data"))
+ { /* gadget to initialize the set by data from plain set */
+ GADGET *gadget;
+ AVLNODE *node;
+ int i, k, fff[20];
+ if (!(set->assign == NULL && set->gadget == NULL)) goto err;
+ get_token(mpl /* data */);
+ set->gadget = gadget = alloc(GADGET);
+ /* set name must follow the keyword 'data' */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl, "invalid use of reserved keyword %s",
+ mpl->image);
+ else
+ error(mpl, "set name missing where expected");
+ /* find the set in the symbolic name table */
+ node = avl_find_node(mpl->tree, mpl->image);
+ if (node == NULL)
+ error(mpl, "%s not defined", mpl->image);
+ if (avl_get_node_type(node) != A_SET)
+err1: error(mpl, "%s not a plain set", mpl->image);
+ gadget->set = avl_get_node_link(node);
+ if (gadget->set->dim != 0) goto err1;
+ if (gadget->set == set)
+ error(mpl, "set cannot be initialized by itself");
+ /* check and set dimensions */
+ if (set->dim >= gadget->set->dimen)
+err2: error(mpl, "dimension of %s too small", mpl->image);
+ if (set->dimen == 0)
+ set->dimen = gadget->set->dimen - set->dim;
+ if (set->dim + set->dimen > gadget->set->dimen)
+ goto err2;
+ else if (set->dim + set->dimen < gadget->set->dimen)
+ error(mpl, "dimension of %s too big", mpl->image);
+ get_token(mpl /* set name */);
+ /* left parenthesis must follow the set name */
+ if (mpl->token == T_LEFT)
+ get_token(mpl /* ( */);
+ else
+ error(mpl, "left parenthesis missing where expected");
+ /* parse permutation of component numbers */
+ for (k = 0; k < gadget->set->dimen; k++) fff[k] = 0;
+ k = 0;
+ for (;;)
+ { if (mpl->token != T_NUMBER)
+ error(mpl, "component number missing where expected");
+ if (str2int(mpl->image, &i) != 0)
+err3: error(mpl, "component number must be integer between "
+ "1 and %d", gadget->set->dimen);
+ if (!(1 <= i && i <= gadget->set->dimen)) goto err3;
+ if (fff[i-1] != 0)
+ error(mpl, "component %d multiply specified", i);
+ gadget->ind[k++] = i, fff[i-1] = 1;
+ xassert(k <= gadget->set->dimen);
+ get_token(mpl /* number */);
+ if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_RIGHT)
+ break;
+ else
+ error(mpl, "syntax error in data attribute");
+ }
+ if (k < gadget->set->dimen)
+ error(mpl, "there are must be %d components rather than "
+ "%d", gadget->set->dimen, k);
+ get_token(mpl /* ) */);
+ }
+#endif
+ else
+ error(mpl, "syntax error in set statement");
+ }
+ /* close the domain scope */
+ if (set->domain != NULL) close_scope(mpl, set->domain);
+ /* if dimension of set members is still unknown, set it to 1 */
+ if (set->dimen == 0) set->dimen = 1;
+ /* the set statement has been completely parsed */
+ xassert(mpl->token == T_SEMICOLON);
+ get_token(mpl /* ; */);
+ return set;
+}
+
+/*----------------------------------------------------------------------
+-- parameter_statement - parse parameter statement.
+--
+-- This routine parses parameter statement using the syntax:
+--
+-- <parameter statement> ::= param <symbolic name> <alias> <domain>
+-- <attributes> ;
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <attributes> ::= <empty>
+-- <attributes> ::= <attributes> , integer
+-- <attributes> ::= <attributes> , binary
+-- <attributes> ::= <attributes> , symbolic
+-- <attributes> ::= <attributes> , <rho> <expression 5>
+-- <attributes> ::= <attributes> , in <expression 9>
+-- <attributes> ::= <attributes> , := <expression 5>
+-- <attributes> ::= <attributes> , default <expression 5>
+-- <rho> ::= < | <= | = | == | >= | > | <> | !=
+--
+-- Commae in <attributes> are optional and may be omitted anywhere. */
+
+PARAMETER *parameter_statement(MPL *mpl)
+{ PARAMETER *par;
+ int integer_used = 0, binary_used = 0, symbolic_used = 0;
+ xassert(is_keyword(mpl, "param"));
+ get_token(mpl /* param */);
+ /* symbolic name must follow the keyword 'param' */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl, "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "symbolic name missing where expected");
+ /* there must be no other object with the same name */
+ if (avl_find_node(mpl->tree, mpl->image) != NULL)
+ error(mpl, "%s multiply declared", mpl->image);
+ /* create model parameter */
+ par = alloc(PARAMETER);
+ par->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(par->name, mpl->image);
+ par->alias = NULL;
+ par->dim = 0;
+ par->domain = NULL;
+ par->type = A_NUMERIC;
+ par->cond = NULL;
+ par->in = NULL;
+ par->assign = NULL;
+ par->option = NULL;
+ par->data = 0;
+ par->defval = NULL;
+ par->array = NULL;
+ get_token(mpl /* <symbolic name> */);
+ /* parse optional alias */
+ if (mpl->token == T_STRING)
+ { par->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(par->alias, mpl->image);
+ get_token(mpl /* <string literal> */);
+ }
+ /* parse optional indexing expression */
+ if (mpl->token == T_LBRACE)
+ { par->domain = indexing_expression(mpl);
+ par->dim = domain_arity(mpl, par->domain);
+ }
+ /* include the parameter name in the symbolic names table */
+ { AVLNODE *node;
+ node = avl_insert_node(mpl->tree, par->name);
+ avl_set_node_type(node, A_PARAMETER);
+ avl_set_node_link(node, (void *)par);
+ }
+ /* parse the list of optional attributes */
+ for (;;)
+ { if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_SEMICOLON)
+ break;
+ if (is_keyword(mpl, "integer"))
+ { if (integer_used)
+ error(mpl, "at most one integer allowed");
+ if (par->type == A_SYMBOLIC)
+ error(mpl, "symbolic parameter cannot be integer");
+ if (par->type != A_BINARY) par->type = A_INTEGER;
+ integer_used = 1;
+ get_token(mpl /* integer */);
+ }
+ else if (is_keyword(mpl, "binary"))
+bin: { if (binary_used)
+ error(mpl, "at most one binary allowed");
+ if (par->type == A_SYMBOLIC)
+ error(mpl, "symbolic parameter cannot be binary");
+ par->type = A_BINARY;
+ binary_used = 1;
+ get_token(mpl /* binary */);
+ }
+ else if (is_keyword(mpl, "logical"))
+ { if (!mpl->as_binary)
+ { warning(mpl, "keyword logical understood as binary");
+ mpl->as_binary = 1;
+ }
+ goto bin;
+ }
+ else if (is_keyword(mpl, "symbolic"))
+ { if (symbolic_used)
+ error(mpl, "at most one symbolic allowed");
+ if (par->type != A_NUMERIC)
+ error(mpl, "integer or binary parameter cannot be symbol"
+ "ic");
+ /* the parameter may be referenced from expressions given
+ in the same parameter declaration, so its type must be
+ completed before parsing that expressions */
+ if (!(par->cond == NULL && par->in == NULL &&
+ par->assign == NULL && par->option == NULL))
+ error(mpl, "keyword symbolic must precede any other para"
+ "meter attributes");
+ par->type = A_SYMBOLIC;
+ symbolic_used = 1;
+ get_token(mpl /* symbolic */);
+ }
+ else if (mpl->token == T_LT || mpl->token == T_LE ||
+ mpl->token == T_EQ || mpl->token == T_GE ||
+ mpl->token == T_GT || mpl->token == T_NE)
+ { /* restricting condition */
+ CONDITION *cond, *temp;
+ char opstr[8];
+ /* create new restricting condition list entry and append
+ it to the conditions list */
+ cond = alloc(CONDITION);
+ switch (mpl->token)
+ { case T_LT:
+ cond->rho = O_LT, strcpy(opstr, mpl->image); break;
+ case T_LE:
+ cond->rho = O_LE, strcpy(opstr, mpl->image); break;
+ case T_EQ:
+ cond->rho = O_EQ, strcpy(opstr, mpl->image); break;
+ case T_GE:
+ cond->rho = O_GE, strcpy(opstr, mpl->image); break;
+ case T_GT:
+ cond->rho = O_GT, strcpy(opstr, mpl->image); break;
+ case T_NE:
+ cond->rho = O_NE, strcpy(opstr, mpl->image); break;
+ default:
+ xassert(mpl->token != mpl->token);
+ }
+ xassert(strlen(opstr) < sizeof(opstr));
+ cond->code = NULL;
+ cond->next = NULL;
+ if (par->cond == NULL)
+ par->cond = cond;
+ else
+ { for (temp = par->cond; temp->next != NULL; temp =
+ temp->next);
+ temp->next = cond;
+ }
+#if 0 /* 13/VIII-2008 */
+ if (par->type == A_SYMBOLIC &&
+ !(cond->rho == O_EQ || cond->rho == O_NE))
+ error(mpl, "inequality restriction not allowed");
+#endif
+ get_token(mpl /* rho */);
+ /* parse an expression that follows relational operator */
+ cond->code = expression_5(mpl);
+ if (!(cond->code->type == A_NUMERIC ||
+ cond->code->type == A_SYMBOLIC))
+ error(mpl, "expression following %s has invalid type",
+ opstr);
+ xassert(cond->code->dim == 0);
+ /* convert to the parameter type, if necessary */
+ if (par->type != A_SYMBOLIC && cond->code->type ==
+ A_SYMBOLIC)
+ cond->code = make_unary(mpl, O_CVTNUM, cond->code,
+ A_NUMERIC, 0);
+ if (par->type == A_SYMBOLIC && cond->code->type !=
+ A_SYMBOLIC)
+ cond->code = make_unary(mpl, O_CVTSYM, cond->code,
+ A_SYMBOLIC, 0);
+ }
+ else if (mpl->token == T_IN || mpl->token == T_WITHIN)
+ { /* restricting superset */
+ WITHIN *in, *temp;
+ if (mpl->token == T_WITHIN && !mpl->as_in)
+ { warning(mpl, "keyword within understood as in");
+ mpl->as_in = 1;
+ }
+ get_token(mpl /* in */);
+ /* create new restricting superset list entry and append it
+ to the in-list */
+ in = alloc(WITHIN);
+ in->code = NULL;
+ in->next = NULL;
+ if (par->in == NULL)
+ par->in = in;
+ else
+ { for (temp = par->in; temp->next != NULL; temp =
+ temp->next);
+ temp->next = in;
+ }
+ /* parse an expression that follows 'in' */
+ in->code = expression_9(mpl);
+ if (in->code->type != A_ELEMSET)
+ error(mpl, "expression following in has invalid type");
+ xassert(in->code->dim > 0);
+ if (in->code->dim != 1)
+ error(mpl, "set expression following in must have dimens"
+ "ion 1 rather than %d", in->code->dim);
+ }
+ else if (mpl->token == T_ASSIGN)
+ { /* assignment expression */
+ if (!(par->assign == NULL && par->option == NULL))
+err: error(mpl, "at most one := or default allowed");
+ get_token(mpl /* := */);
+ /* parse an expression that follows ':=' */
+ par->assign = expression_5(mpl);
+ /* the expression must be of numeric/symbolic type */
+ if (!(par->assign->type == A_NUMERIC ||
+ par->assign->type == A_SYMBOLIC))
+ error(mpl, "expression following := has invalid type");
+ xassert(par->assign->dim == 0);
+ /* convert to the parameter type, if necessary */
+ if (par->type != A_SYMBOLIC && par->assign->type ==
+ A_SYMBOLIC)
+ par->assign = make_unary(mpl, O_CVTNUM, par->assign,
+ A_NUMERIC, 0);
+ if (par->type == A_SYMBOLIC && par->assign->type !=
+ A_SYMBOLIC)
+ par->assign = make_unary(mpl, O_CVTSYM, par->assign,
+ A_SYMBOLIC, 0);
+ }
+ else if (is_keyword(mpl, "default"))
+ { /* expression for default value */
+ if (!(par->assign == NULL && par->option == NULL)) goto err;
+ get_token(mpl /* default */);
+ /* parse an expression that follows 'default' */
+ par->option = expression_5(mpl);
+ if (!(par->option->type == A_NUMERIC ||
+ par->option->type == A_SYMBOLIC))
+ error(mpl, "expression following default has invalid typ"
+ "e");
+ xassert(par->option->dim == 0);
+ /* convert to the parameter type, if necessary */
+ if (par->type != A_SYMBOLIC && par->option->type ==
+ A_SYMBOLIC)
+ par->option = make_unary(mpl, O_CVTNUM, par->option,
+ A_NUMERIC, 0);
+ if (par->type == A_SYMBOLIC && par->option->type !=
+ A_SYMBOLIC)
+ par->option = make_unary(mpl, O_CVTSYM, par->option,
+ A_SYMBOLIC, 0);
+ }
+ else
+ error(mpl, "syntax error in parameter statement");
+ }
+ /* close the domain scope */
+ if (par->domain != NULL) close_scope(mpl, par->domain);
+ /* the parameter statement has been completely parsed */
+ xassert(mpl->token == T_SEMICOLON);
+ get_token(mpl /* ; */);
+ return par;
+}
+
+/*----------------------------------------------------------------------
+-- variable_statement - parse variable statement.
+--
+-- This routine parses variable statement using the syntax:
+--
+-- <variable statement> ::= var <symbolic name> <alias> <domain>
+-- <attributes> ;
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <attributes> ::= <empty>
+-- <attributes> ::= <attributes> , integer
+-- <attributes> ::= <attributes> , binary
+-- <attributes> ::= <attributes> , <rho> <expression 5>
+-- <rho> ::= >= | <= | = | ==
+--
+-- Commae in <attributes> are optional and may be omitted anywhere. */
+
+VARIABLE *variable_statement(MPL *mpl)
+{ VARIABLE *var;
+ int integer_used = 0, binary_used = 0;
+ xassert(is_keyword(mpl, "var"));
+ if (mpl->flag_s)
+ error(mpl, "variable statement must precede solve statement");
+ get_token(mpl /* var */);
+ /* symbolic name must follow the keyword 'var' */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl, "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "symbolic name missing where expected");
+ /* there must be no other object with the same name */
+ if (avl_find_node(mpl->tree, mpl->image) != NULL)
+ error(mpl, "%s multiply declared", mpl->image);
+ /* create model variable */
+ var = alloc(VARIABLE);
+ var->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(var->name, mpl->image);
+ var->alias = NULL;
+ var->dim = 0;
+ var->domain = NULL;
+ var->type = A_NUMERIC;
+ var->lbnd = NULL;
+ var->ubnd = NULL;
+ var->array = NULL;
+ get_token(mpl /* <symbolic name> */);
+ /* parse optional alias */
+ if (mpl->token == T_STRING)
+ { var->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(var->alias, mpl->image);
+ get_token(mpl /* <string literal> */);
+ }
+ /* parse optional indexing expression */
+ if (mpl->token == T_LBRACE)
+ { var->domain = indexing_expression(mpl);
+ var->dim = domain_arity(mpl, var->domain);
+ }
+ /* include the variable name in the symbolic names table */
+ { AVLNODE *node;
+ node = avl_insert_node(mpl->tree, var->name);
+ avl_set_node_type(node, A_VARIABLE);
+ avl_set_node_link(node, (void *)var);
+ }
+ /* parse the list of optional attributes */
+ for (;;)
+ { if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_SEMICOLON)
+ break;
+ if (is_keyword(mpl, "integer"))
+ { if (integer_used)
+ error(mpl, "at most one integer allowed");
+ if (var->type != A_BINARY) var->type = A_INTEGER;
+ integer_used = 1;
+ get_token(mpl /* integer */);
+ }
+ else if (is_keyword(mpl, "binary"))
+bin: { if (binary_used)
+ error(mpl, "at most one binary allowed");
+ var->type = A_BINARY;
+ binary_used = 1;
+ get_token(mpl /* binary */);
+ }
+ else if (is_keyword(mpl, "logical"))
+ { if (!mpl->as_binary)
+ { warning(mpl, "keyword logical understood as binary");
+ mpl->as_binary = 1;
+ }
+ goto bin;
+ }
+ else if (is_keyword(mpl, "symbolic"))
+ error(mpl, "variable cannot be symbolic");
+ else if (mpl->token == T_GE)
+ { /* lower bound */
+ if (var->lbnd != NULL)
+ { if (var->lbnd == var->ubnd)
+ error(mpl, "both fixed value and lower bound not allo"
+ "wed");
+ else
+ error(mpl, "at most one lower bound allowed");
+ }
+ get_token(mpl /* >= */);
+ /* parse an expression that specifies the lower bound */
+ var->lbnd = expression_5(mpl);
+ if (var->lbnd->type == A_SYMBOLIC)
+ var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
+ A_NUMERIC, 0);
+ if (var->lbnd->type != A_NUMERIC)
+ error(mpl, "expression following >= has invalid type");
+ xassert(var->lbnd->dim == 0);
+ }
+ else if (mpl->token == T_LE)
+ { /* upper bound */
+ if (var->ubnd != NULL)
+ { if (var->ubnd == var->lbnd)
+ error(mpl, "both fixed value and upper bound not allo"
+ "wed");
+ else
+ error(mpl, "at most one upper bound allowed");
+ }
+ get_token(mpl /* <= */);
+ /* parse an expression that specifies the upper bound */
+ var->ubnd = expression_5(mpl);
+ if (var->ubnd->type == A_SYMBOLIC)
+ var->ubnd = make_unary(mpl, O_CVTNUM, var->ubnd,
+ A_NUMERIC, 0);
+ if (var->ubnd->type != A_NUMERIC)
+ error(mpl, "expression following <= has invalid type");
+ xassert(var->ubnd->dim == 0);
+ }
+ else if (mpl->token == T_EQ)
+ { /* fixed value */
+ char opstr[8];
+ if (!(var->lbnd == NULL && var->ubnd == NULL))
+ { if (var->lbnd == var->ubnd)
+ error(mpl, "at most one fixed value allowed");
+ else if (var->lbnd != NULL)
+ error(mpl, "both lower bound and fixed value not allo"
+ "wed");
+ else
+ error(mpl, "both upper bound and fixed value not allo"
+ "wed");
+ }
+ strcpy(opstr, mpl->image);
+ xassert(strlen(opstr) < sizeof(opstr));
+ get_token(mpl /* = | == */);
+ /* parse an expression that specifies the fixed value */
+ var->lbnd = expression_5(mpl);
+ if (var->lbnd->type == A_SYMBOLIC)
+ var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
+ A_NUMERIC, 0);
+ if (var->lbnd->type != A_NUMERIC)
+ error(mpl, "expression following %s has invalid type",
+ opstr);
+ xassert(var->lbnd->dim == 0);
+ /* indicate that the variable is fixed, not bounded */
+ var->ubnd = var->lbnd;
+ }
+ else if (mpl->token == T_LT || mpl->token == T_GT ||
+ mpl->token == T_NE)
+ error(mpl, "strict bound not allowed");
+ else
+ error(mpl, "syntax error in variable statement");
+ }
+ /* close the domain scope */
+ if (var->domain != NULL) close_scope(mpl, var->domain);
+ /* the variable statement has been completely parsed */
+ xassert(mpl->token == T_SEMICOLON);
+ get_token(mpl /* ; */);
+ return var;
+}
+
+/*----------------------------------------------------------------------
+-- constraint_statement - parse constraint statement.
+--
+-- This routine parses constraint statement using the syntax:
+--
+-- <constraint statement> ::= <subject to> <symbolic name> <alias>
+-- <domain> : <constraint> ;
+-- <subject to> ::= <empty>
+-- <subject to> ::= subject to
+-- <subject to> ::= subj to
+-- <subject to> ::= s.t.
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <constraint> ::= <formula> , >= <formula>
+-- <constraint> ::= <formula> , <= <formula>
+-- <constraint> ::= <formula> , = <formula>
+-- <constraint> ::= <formula> , <= <formula> , <= <formula>
+-- <constraint> ::= <formula> , >= <formula> , >= <formula>
+-- <formula> ::= <expression 5>
+--
+-- Commae in <constraint> are optional and may be omitted anywhere. */
+
+CONSTRAINT *constraint_statement(MPL *mpl)
+{ CONSTRAINT *con;
+ CODE *first, *second, *third;
+ int rho;
+ char opstr[8];
+ if (mpl->flag_s)
+ error(mpl, "constraint statement must precede solve statement")
+ ;
+ if (is_keyword(mpl, "subject"))
+ { get_token(mpl /* subject */);
+ if (!is_keyword(mpl, "to"))
+ error(mpl, "keyword subject to incomplete");
+ get_token(mpl /* to */);
+ }
+ else if (is_keyword(mpl, "subj"))
+ { get_token(mpl /* subj */);
+ if (!is_keyword(mpl, "to"))
+ error(mpl, "keyword subj to incomplete");
+ get_token(mpl /* to */);
+ }
+ else if (mpl->token == T_SPTP)
+ get_token(mpl /* s.t. */);
+ /* the current token must be symbolic name of constraint */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl, "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "symbolic name missing where expected");
+ /* there must be no other object with the same name */
+ if (avl_find_node(mpl->tree, mpl->image) != NULL)
+ error(mpl, "%s multiply declared", mpl->image);
+ /* create model constraint */
+ con = alloc(CONSTRAINT);
+ con->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(con->name, mpl->image);
+ con->alias = NULL;
+ con->dim = 0;
+ con->domain = NULL;
+ con->type = A_CONSTRAINT;
+ con->code = NULL;
+ con->lbnd = NULL;
+ con->ubnd = NULL;
+ con->array = NULL;
+ get_token(mpl /* <symbolic name> */);
+ /* parse optional alias */
+ if (mpl->token == T_STRING)
+ { con->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(con->alias, mpl->image);
+ get_token(mpl /* <string literal> */);
+ }
+ /* parse optional indexing expression */
+ if (mpl->token == T_LBRACE)
+ { con->domain = indexing_expression(mpl);
+ con->dim = domain_arity(mpl, con->domain);
+ }
+ /* include the constraint name in the symbolic names table */
+ { AVLNODE *node;
+ node = avl_insert_node(mpl->tree, con->name);
+ avl_set_node_type(node, A_CONSTRAINT);
+ avl_set_node_link(node, (void *)con);
+ }
+ /* the colon must precede the first expression */
+ if (mpl->token != T_COLON)
+ error(mpl, "colon missing where expected");
+ get_token(mpl /* : */);
+ /* parse the first expression */
+ first = expression_5(mpl);
+ if (first->type == A_SYMBOLIC)
+ first = make_unary(mpl, O_CVTNUM, first, A_NUMERIC, 0);
+ if (!(first->type == A_NUMERIC || first->type == A_FORMULA))
+ error(mpl, "expression following colon has invalid type");
+ xassert(first->dim == 0);
+ /* relational operator must follow the first expression */
+ if (mpl->token == T_COMMA) get_token(mpl /* , */);
+ switch (mpl->token)
+ { case T_LE:
+ case T_GE:
+ case T_EQ:
+ break;
+ case T_LT:
+ case T_GT:
+ case T_NE:
+ error(mpl, "strict inequality not allowed");
+ case T_SEMICOLON:
+ error(mpl, "constraint must be equality or inequality");
+ default:
+ goto err;
+ }
+ rho = mpl->token;
+ strcpy(opstr, mpl->image);
+ xassert(strlen(opstr) < sizeof(opstr));
+ get_token(mpl /* rho */);
+ /* parse the second expression */
+ second = expression_5(mpl);
+ if (second->type == A_SYMBOLIC)
+ second = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
+ if (!(second->type == A_NUMERIC || second->type == A_FORMULA))
+ error(mpl, "expression following %s has invalid type", opstr);
+ xassert(second->dim == 0);
+ /* check a token that follow the second expression */
+ if (mpl->token == T_COMMA)
+ { get_token(mpl /* , */);
+ if (mpl->token == T_SEMICOLON) goto err;
+ }
+ if (mpl->token == T_LT || mpl->token == T_LE ||
+ mpl->token == T_EQ || mpl->token == T_GE ||
+ mpl->token == T_GT || mpl->token == T_NE)
+ { /* it is another relational operator, therefore the constraint
+ is double inequality */
+ if (rho == T_EQ || mpl->token != rho)
+ error(mpl, "double inequality must be ... <= ... <= ... or "
+ "... >= ... >= ...");
+ /* the first expression cannot be linear form */
+ if (first->type == A_FORMULA)
+ error(mpl, "leftmost expression in double inequality cannot"
+ " be linear form");
+ get_token(mpl /* rho */);
+ /* parse the third expression */
+ third = expression_5(mpl);
+ if (third->type == A_SYMBOLIC)
+ third = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
+ if (!(third->type == A_NUMERIC || third->type == A_FORMULA))
+ error(mpl, "rightmost expression in double inequality const"
+ "raint has invalid type");
+ xassert(third->dim == 0);
+ /* the third expression also cannot be linear form */
+ if (third->type == A_FORMULA)
+ error(mpl, "rightmost expression in double inequality canno"
+ "t be linear form");
+ }
+ else
+ { /* the constraint is equality or single inequality */
+ third = NULL;
+ }
+ /* close the domain scope */
+ if (con->domain != NULL) close_scope(mpl, con->domain);
+ /* convert all expressions to linear form, if necessary */
+ if (first->type != A_FORMULA)
+ first = make_unary(mpl, O_CVTLFM, first, A_FORMULA, 0);
+ if (second->type != A_FORMULA)
+ second = make_unary(mpl, O_CVTLFM, second, A_FORMULA, 0);
+ if (third != NULL)
+ third = make_unary(mpl, O_CVTLFM, third, A_FORMULA, 0);
+ /* arrange expressions in the constraint */
+ if (third == NULL)
+ { /* the constraint is equality or single inequality */
+ switch (rho)
+ { case T_LE:
+ /* first <= second */
+ con->code = first;
+ con->lbnd = NULL;
+ con->ubnd = second;
+ break;
+ case T_GE:
+ /* first >= second */
+ con->code = first;
+ con->lbnd = second;
+ con->ubnd = NULL;
+ break;
+ case T_EQ:
+ /* first = second */
+ con->code = first;
+ con->lbnd = second;
+ con->ubnd = second;
+ break;
+ default:
+ xassert(rho != rho);
+ }
+ }
+ else
+ { /* the constraint is double inequality */
+ switch (rho)
+ { case T_LE:
+ /* first <= second <= third */
+ con->code = second;
+ con->lbnd = first;
+ con->ubnd = third;
+ break;
+ case T_GE:
+ /* first >= second >= third */
+ con->code = second;
+ con->lbnd = third;
+ con->ubnd = first;
+ break;
+ default:
+ xassert(rho != rho);
+ }
+ }
+ /* the constraint statement has been completely parsed */
+ if (mpl->token != T_SEMICOLON)
+err: error(mpl, "syntax error in constraint statement");
+ get_token(mpl /* ; */);
+ return con;
+}
+
+/*----------------------------------------------------------------------
+-- objective_statement - parse objective statement.
+--
+-- This routine parses objective statement using the syntax:
+--
+-- <objective statement> ::= <verb> <symbolic name> <alias> <domain> :
+-- <formula> ;
+-- <verb> ::= minimize
+-- <verb> ::= maximize
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <formula> ::= <expression 5> */
+
+CONSTRAINT *objective_statement(MPL *mpl)
+{ CONSTRAINT *obj;
+ int type;
+ if (is_keyword(mpl, "minimize"))
+ type = A_MINIMIZE;
+ else if (is_keyword(mpl, "maximize"))
+ type = A_MAXIMIZE;
+ else
+ xassert(mpl != mpl);
+ if (mpl->flag_s)
+ error(mpl, "objective statement must precede solve statement");
+ get_token(mpl /* minimize | maximize */);
+ /* symbolic name must follow the verb 'minimize' or 'maximize' */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl, "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "symbolic name missing where expected");
+ /* there must be no other object with the same name */
+ if (avl_find_node(mpl->tree, mpl->image) != NULL)
+ error(mpl, "%s multiply declared", mpl->image);
+ /* create model objective */
+ obj = alloc(CONSTRAINT);
+ obj->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(obj->name, mpl->image);
+ obj->alias = NULL;
+ obj->dim = 0;
+ obj->domain = NULL;
+ obj->type = type;
+ obj->code = NULL;
+ obj->lbnd = NULL;
+ obj->ubnd = NULL;
+ obj->array = NULL;
+ get_token(mpl /* <symbolic name> */);
+ /* parse optional alias */
+ if (mpl->token == T_STRING)
+ { obj->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(obj->alias, mpl->image);
+ get_token(mpl /* <string literal> */);
+ }
+ /* parse optional indexing expression */
+ if (mpl->token == T_LBRACE)
+ { obj->domain = indexing_expression(mpl);
+ obj->dim = domain_arity(mpl, obj->domain);
+ }
+ /* include the constraint name in the symbolic names table */
+ { AVLNODE *node;
+ node = avl_insert_node(mpl->tree, obj->name);
+ avl_set_node_type(node, A_CONSTRAINT);
+ avl_set_node_link(node, (void *)obj);
+ }
+ /* the colon must precede the objective expression */
+ if (mpl->token != T_COLON)
+ error(mpl, "colon missing where expected");
+ get_token(mpl /* : */);
+ /* parse the objective expression */
+ obj->code = expression_5(mpl);
+ if (obj->code->type == A_SYMBOLIC)
+ obj->code = make_unary(mpl, O_CVTNUM, obj->code, A_NUMERIC, 0);
+ if (obj->code->type == A_NUMERIC)
+ obj->code = make_unary(mpl, O_CVTLFM, obj->code, A_FORMULA, 0);
+ if (obj->code->type != A_FORMULA)
+ error(mpl, "expression following colon has invalid type");
+ xassert(obj->code->dim == 0);
+ /* close the domain scope */
+ if (obj->domain != NULL) close_scope(mpl, obj->domain);
+ /* the objective statement has been completely parsed */
+ if (mpl->token != T_SEMICOLON)
+ error(mpl, "syntax error in objective statement");
+ get_token(mpl /* ; */);
+ return obj;
+}
+
+#if 1 /* 11/II-2008 */
+/***********************************************************************
+* table_statement - parse table statement
+*
+* This routine parses table statement using the syntax:
+*
+* <table statement> ::= <input table statement>
+* <table statement> ::= <output table statement>
+*
+* <input table statement> ::=
+* table <table name> <alias> IN <argument list> :
+* <input set> [ <field list> ] , <input list> ;
+* <alias> ::= <empty>
+* <alias> ::= <string literal>
+* <argument list> ::= <expression 5>
+* <argument list> ::= <argument list> <expression 5>
+* <argument list> ::= <argument list> , <expression 5>
+* <input set> ::= <empty>
+* <input set> ::= <set name> <-
+* <field list> ::= <field name>
+* <field list> ::= <field list> , <field name>
+* <input list> ::= <input item>
+* <input list> ::= <input list> , <input item>
+* <input item> ::= <parameter name>
+* <input item> ::= <parameter name> ~ <field name>
+*
+* <output table statement> ::=
+* table <table name> <alias> <domain> OUT <argument list> :
+* <output list> ;
+* <domain> ::= <indexing expression>
+* <output list> ::= <output item>
+* <output list> ::= <output list> , <output item>
+* <output item> ::= <expression 5>
+* <output item> ::= <expression 5> ~ <field name> */
+
+TABLE *table_statement(MPL *mpl)
+{ TABLE *tab;
+ TABARG *last_arg, *arg;
+ TABFLD *last_fld, *fld;
+ TABIN *last_in, *in;
+ TABOUT *last_out, *out;
+ AVLNODE *node;
+ int nflds;
+ char name[MAX_LENGTH+1];
+ xassert(is_keyword(mpl, "table"));
+ get_token(mpl /* solve */);
+ /* symbolic name must follow the keyword table */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl, "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "symbolic name missing where expected");
+ /* there must be no other object with the same name */
+ if (avl_find_node(mpl->tree, mpl->image) != NULL)
+ error(mpl, "%s multiply declared", mpl->image);
+ /* create data table */
+ tab = alloc(TABLE);
+ tab->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(tab->name, mpl->image);
+ get_token(mpl /* <symbolic name> */);
+ /* parse optional alias */
+ if (mpl->token == T_STRING)
+ { tab->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(tab->alias, mpl->image);
+ get_token(mpl /* <string literal> */);
+ }
+ else
+ tab->alias = NULL;
+ /* parse optional indexing expression */
+ if (mpl->token == T_LBRACE)
+ { /* this is output table */
+ tab->type = A_OUTPUT;
+ tab->u.out.domain = indexing_expression(mpl);
+ if (!is_keyword(mpl, "OUT"))
+ error(mpl, "keyword OUT missing where expected");
+ get_token(mpl /* OUT */);
+ }
+ else
+ { /* this is input table */
+ tab->type = A_INPUT;
+ if (!is_keyword(mpl, "IN"))
+ error(mpl, "keyword IN missing where expected");
+ get_token(mpl /* IN */);
+ }
+ /* parse argument list */
+ tab->arg = last_arg = NULL;
+ for (;;)
+ { /* create argument list entry */
+ arg = alloc(TABARG);
+ /* parse argument expression */
+ if (mpl->token == T_COMMA || mpl->token == T_COLON ||
+ mpl->token == T_SEMICOLON)
+ error(mpl, "argument expression missing where expected");
+ arg->code = expression_5(mpl);
+ /* convert the result to symbolic type, if necessary */
+ if (arg->code->type == A_NUMERIC)
+ arg->code =
+ make_unary(mpl, O_CVTSYM, arg->code, A_SYMBOLIC, 0);
+ /* check that now the result is of symbolic type */
+ if (arg->code->type != A_SYMBOLIC)
+ error(mpl, "argument expression has invalid type");
+ /* add the entry to the end of the list */
+ arg->next = NULL;
+ if (last_arg == NULL)
+ tab->arg = arg;
+ else
+ last_arg->next = arg;
+ last_arg = arg;
+ /* argument expression has been parsed */
+ if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_COLON || mpl->token == T_SEMICOLON)
+ break;
+ }
+ xassert(tab->arg != NULL);
+ /* argument list must end with colon */
+ if (mpl->token == T_COLON)
+ get_token(mpl /* : */);
+ else
+ error(mpl, "colon missing where expected");
+ /* parse specific part of the table statement */
+ switch (tab->type)
+ { case A_INPUT: goto input_table;
+ case A_OUTPUT: goto output_table;
+ default: xassert(tab != tab);
+ }
+input_table:
+ /* parse optional set name */
+ if (mpl->token == T_NAME)
+ { node = avl_find_node(mpl->tree, mpl->image);
+ if (node == NULL)
+ error(mpl, "%s not defined", mpl->image);
+ if (avl_get_node_type(node) != A_SET)
+ error(mpl, "%s not a set", mpl->image);
+ tab->u.in.set = (SET *)avl_get_node_link(node);
+ if (tab->u.in.set->assign != NULL)
+ error(mpl, "%s needs no data", mpl->image);
+ if (tab->u.in.set->dim != 0)
+ error(mpl, "%s must be a simple set", mpl->image);
+ get_token(mpl /* <symbolic name> */);
+ if (mpl->token == T_INPUT)
+ get_token(mpl /* <- */);
+ else
+ error(mpl, "delimiter <- missing where expected");
+ }
+ else if (is_reserved(mpl))
+ error(mpl, "invalid use of reserved keyword %s", mpl->image);
+ else
+ tab->u.in.set = NULL;
+ /* parse field list */
+ tab->u.in.fld = last_fld = NULL;
+ nflds = 0;
+ if (mpl->token == T_LBRACKET)
+ get_token(mpl /* [ */);
+ else
+ error(mpl, "field list missing where expected");
+ for (;;)
+ { /* create field list entry */
+ fld = alloc(TABFLD);
+ /* parse field name */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl,
+ "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "field name missing where expected");
+ fld->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+ strcpy(fld->name, mpl->image);
+ get_token(mpl /* <symbolic name> */);
+ /* add the entry to the end of the list */
+ fld->next = NULL;
+ if (last_fld == NULL)
+ tab->u.in.fld = fld;
+ else
+ last_fld->next = fld;
+ last_fld = fld;
+ nflds++;
+ /* field name has been parsed */
+ if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_RBRACKET)
+ break;
+ else
+ error(mpl, "syntax error in field list");
+ }
+ /* check that the set dimen is equal to the number of fields */
+ if (tab->u.in.set != NULL && tab->u.in.set->dimen != nflds)
+ error(mpl, "there must be %d field%s rather than %d",
+ tab->u.in.set->dimen, tab->u.in.set->dimen == 1 ? "" : "s",
+ nflds);
+ get_token(mpl /* ] */);
+ /* parse optional input list */
+ tab->u.in.list = last_in = NULL;
+ while (mpl->token == T_COMMA)
+ { get_token(mpl /* , */);
+ /* create input list entry */
+ in = alloc(TABIN);
+ /* parse parameter name */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl,
+ "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "parameter name missing where expected");
+ node = avl_find_node(mpl->tree, mpl->image);
+ if (node == NULL)
+ error(mpl, "%s not defined", mpl->image);
+ if (avl_get_node_type(node) != A_PARAMETER)
+ error(mpl, "%s not a parameter", mpl->image);
+ in->par = (PARAMETER *)avl_get_node_link(node);
+ if (in->par->dim != nflds)
+ error(mpl, "%s must have %d subscript%s rather than %d",
+ mpl->image, nflds, nflds == 1 ? "" : "s", in->par->dim);
+ if (in->par->assign != NULL)
+ error(mpl, "%s needs no data", mpl->image);
+ get_token(mpl /* <symbolic name> */);
+ /* parse optional field name */
+ if (mpl->token == T_TILDE)
+ { get_token(mpl /* ~ */);
+ /* parse field name */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl,
+ "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "field name missing where expected");
+ xassert(strlen(mpl->image) < sizeof(name));
+ strcpy(name, mpl->image);
+ get_token(mpl /* <symbolic name> */);
+ }
+ else
+ { /* field name is the same as the parameter name */
+ xassert(strlen(in->par->name) < sizeof(name));
+ strcpy(name, in->par->name);
+ }
+ /* assign field name */
+ in->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
+ strcpy(in->name, name);
+ /* add the entry to the end of the list */
+ in->next = NULL;
+ if (last_in == NULL)
+ tab->u.in.list = in;
+ else
+ last_in->next = in;
+ last_in = in;
+ }
+ goto end_of_table;
+output_table:
+ /* parse output list */
+ tab->u.out.list = last_out = NULL;
+ for (;;)
+ { /* create output list entry */
+ out = alloc(TABOUT);
+ /* parse expression */
+ if (mpl->token == T_COMMA || mpl->token == T_SEMICOLON)
+ error(mpl, "expression missing where expected");
+ if (mpl->token == T_NAME)
+ { xassert(strlen(mpl->image) < sizeof(name));
+ strcpy(name, mpl->image);
+ }
+ else
+ name[0] = '\0';
+ out->code = expression_5(mpl);
+ /* parse optional field name */
+ if (mpl->token == T_TILDE)
+ { get_token(mpl /* ~ */);
+ /* parse field name */
+ if (mpl->token == T_NAME)
+ ;
+ else if (is_reserved(mpl))
+ error(mpl,
+ "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "field name missing where expected");
+ xassert(strlen(mpl->image) < sizeof(name));
+ strcpy(name, mpl->image);
+ get_token(mpl /* <symbolic name> */);
+ }
+ /* assign field name */
+ if (name[0] == '\0')
+ error(mpl, "field name required");
+ out->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
+ strcpy(out->name, name);
+ /* add the entry to the end of the list */
+ out->next = NULL;
+ if (last_out == NULL)
+ tab->u.out.list = out;
+ else
+ last_out->next = out;
+ last_out = out;
+ /* output item has been parsed */
+ if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else if (mpl->token == T_SEMICOLON)
+ break;
+ else
+ error(mpl, "syntax error in output list");
+ }
+ /* close the domain scope */
+ close_scope(mpl,tab->u.out.domain);
+end_of_table:
+ /* the table statement must end with semicolon */
+ if (mpl->token != T_SEMICOLON)
+ error(mpl, "syntax error in table statement");
+ get_token(mpl /* ; */);
+ return tab;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- solve_statement - parse solve statement.
+--
+-- This routine parses solve statement using the syntax:
+--
+-- <solve statement> ::= solve ;
+--
+-- The solve statement can be used at most once. */
+
+void *solve_statement(MPL *mpl)
+{ xassert(is_keyword(mpl, "solve"));
+ if (mpl->flag_s)
+ error(mpl, "at most one solve statement allowed");
+ mpl->flag_s = 1;
+ get_token(mpl /* solve */);
+ /* semicolon must follow solve statement */
+ if (mpl->token != T_SEMICOLON)
+ error(mpl, "syntax error in solve statement");
+ get_token(mpl /* ; */);
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+-- check_statement - parse check statement.
+--
+-- This routine parses check statement using the syntax:
+--
+-- <check statement> ::= check <domain> : <expression 13> ;
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+--
+-- If <domain> is omitted, colon following it may also be omitted. */
+
+CHECK *check_statement(MPL *mpl)
+{ CHECK *chk;
+ xassert(is_keyword(mpl, "check"));
+ /* create check descriptor */
+ chk = alloc(CHECK);
+ chk->domain = NULL;
+ chk->code = NULL;
+ get_token(mpl /* check */);
+ /* parse optional indexing expression */
+ if (mpl->token == T_LBRACE)
+ { chk->domain = indexing_expression(mpl);
+#if 0
+ if (mpl->token != T_COLON)
+ error(mpl, "colon missing where expected");
+#endif
+ }
+ /* skip optional colon */
+ if (mpl->token == T_COLON) get_token(mpl /* : */);
+ /* parse logical expression */
+ chk->code = expression_13(mpl);
+ if (chk->code->type != A_LOGICAL)
+ error(mpl, "expression has invalid type");
+ xassert(chk->code->dim == 0);
+ /* close the domain scope */
+ if (chk->domain != NULL) close_scope(mpl, chk->domain);
+ /* the check statement has been completely parsed */
+ if (mpl->token != T_SEMICOLON)
+ error(mpl, "syntax error in check statement");
+ get_token(mpl /* ; */);
+ return chk;
+}
+
+#if 1 /* 15/V-2010 */
+/*----------------------------------------------------------------------
+-- display_statement - parse display statement.
+--
+-- This routine parses display statement using the syntax:
+--
+-- <display statement> ::= display <domain> : <display list> ;
+-- <display statement> ::= display <domain> <display list> ;
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <display list> ::= <display entry>
+-- <display list> ::= <display list> , <display entry>
+-- <display entry> ::= <dummy index>
+-- <display entry> ::= <set name>
+-- <display entry> ::= <set name> [ <subscript list> ]
+-- <display entry> ::= <parameter name>
+-- <display entry> ::= <parameter name> [ <subscript list> ]
+-- <display entry> ::= <variable name>
+-- <display entry> ::= <variable name> [ <subscript list> ]
+-- <display entry> ::= <constraint name>
+-- <display entry> ::= <constraint name> [ <subscript list> ]
+-- <display entry> ::= <expression 13> */
+
+DISPLAY *display_statement(MPL *mpl)
+{ DISPLAY *dpy;
+ DISPLAY1 *entry, *last_entry;
+ xassert(is_keyword(mpl, "display"));
+ /* create display descriptor */
+ dpy = alloc(DISPLAY);
+ dpy->domain = NULL;
+ dpy->list = last_entry = NULL;
+ get_token(mpl /* display */);
+ /* parse optional indexing expression */
+ if (mpl->token == T_LBRACE)
+ dpy->domain = indexing_expression(mpl);
+ /* skip optional colon */
+ if (mpl->token == T_COLON) get_token(mpl /* : */);
+ /* parse display list */
+ for (;;)
+ { /* create new display entry */
+ entry = alloc(DISPLAY1);
+ entry->type = 0;
+ entry->next = NULL;
+ /* and append it to the display list */
+ if (dpy->list == NULL)
+ dpy->list = entry;
+ else
+ last_entry->next = entry;
+ last_entry = entry;
+ /* parse display entry */
+ if (mpl->token == T_NAME)
+ { AVLNODE *node;
+ int next_token;
+ get_token(mpl /* <symbolic name> */);
+ next_token = mpl->token;
+ unget_token(mpl);
+ if (!(next_token == T_COMMA || next_token == T_SEMICOLON))
+ { /* symbolic name begins expression */
+ goto expr;
+ }
+ /* display entry is dummy index or model object */
+ node = avl_find_node(mpl->tree, mpl->image);
+ if (node == NULL)
+ error(mpl, "%s not defined", mpl->image);
+ entry->type = avl_get_node_type(node);
+ switch (avl_get_node_type(node))
+ { case A_INDEX:
+ entry->u.slot =
+ (DOMAIN_SLOT *)avl_get_node_link(node);
+ break;
+ case A_SET:
+ entry->u.set = (SET *)avl_get_node_link(node);
+ break;
+ case A_PARAMETER:
+ entry->u.par = (PARAMETER *)avl_get_node_link(node);
+ break;
+ case A_VARIABLE:
+ entry->u.var = (VARIABLE *)avl_get_node_link(node);
+ if (!mpl->flag_s)
+ error(mpl, "invalid reference to variable %s above"
+ " solve statement", entry->u.var->name);
+ break;
+ case A_CONSTRAINT:
+ entry->u.con = (CONSTRAINT *)avl_get_node_link(node);
+ if (!mpl->flag_s)
+ error(mpl, "invalid reference to %s %s above solve"
+ " statement",
+ entry->u.con->type == A_CONSTRAINT ?
+ "constraint" : "objective", entry->u.con->name);
+ break;
+ default:
+ xassert(node != node);
+ }
+ get_token(mpl /* <symbolic name> */);
+ }
+ else
+expr: { /* display entry is expression */
+ entry->type = A_EXPRESSION;
+ entry->u.code = expression_13(mpl);
+ }
+ /* check a token that follows the entry parsed */
+ if (mpl->token == T_COMMA)
+ get_token(mpl /* , */);
+ else
+ break;
+ }
+ /* close the domain scope */
+ if (dpy->domain != NULL) close_scope(mpl, dpy->domain);
+ /* the display statement has been completely parsed */
+ if (mpl->token != T_SEMICOLON)
+ error(mpl, "syntax error in display statement");
+ get_token(mpl /* ; */);
+ return dpy;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- printf_statement - parse printf statement.
+--
+-- This routine parses print statement using the syntax:
+--
+-- <printf statement> ::= <printf clause> ;
+-- <printf statement> ::= <printf clause> > <file name> ;
+-- <printf statement> ::= <printf clause> >> <file name> ;
+-- <printf clause> ::= printf <domain> : <format> <printf list>
+-- <printf clause> ::= printf <domain> <format> <printf list>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <format> ::= <expression 5>
+-- <printf list> ::= <empty>
+-- <printf list> ::= <printf list> , <printf entry>
+-- <printf entry> ::= <expression 9>
+-- <file name> ::= <expression 5> */
+
+PRINTF *printf_statement(MPL *mpl)
+{ PRINTF *prt;
+ PRINTF1 *entry, *last_entry;
+ xassert(is_keyword(mpl, "printf"));
+ /* create printf descriptor */
+ prt = alloc(PRINTF);
+ prt->domain = NULL;
+ prt->fmt = NULL;
+ prt->list = last_entry = NULL;
+ get_token(mpl /* printf */);
+ /* parse optional indexing expression */
+ if (mpl->token == T_LBRACE)
+ { prt->domain = indexing_expression(mpl);
+#if 0
+ if (mpl->token != T_COLON)
+ error(mpl, "colon missing where expected");
+#endif
+ }
+ /* skip optional colon */
+ if (mpl->token == T_COLON) get_token(mpl /* : */);
+ /* parse expression for format string */
+ prt->fmt = expression_5(mpl);
+ /* convert it to symbolic type, if necessary */
+ if (prt->fmt->type == A_NUMERIC)
+ prt->fmt = make_unary(mpl, O_CVTSYM, prt->fmt, A_SYMBOLIC, 0);
+ /* check that now the expression is of symbolic type */
+ if (prt->fmt->type != A_SYMBOLIC)
+ error(mpl, "format expression has invalid type");
+ /* parse printf list */
+ while (mpl->token == T_COMMA)
+ { get_token(mpl /* , */);
+ /* create new printf entry */
+ entry = alloc(PRINTF1);
+ entry->code = NULL;
+ entry->next = NULL;
+ /* and append it to the printf list */
+ if (prt->list == NULL)
+ prt->list = entry;
+ else
+ last_entry->next = entry;
+ last_entry = entry;
+ /* parse printf entry */
+ entry->code = expression_9(mpl);
+ if (!(entry->code->type == A_NUMERIC ||
+ entry->code->type == A_SYMBOLIC ||
+ entry->code->type == A_LOGICAL))
+ error(mpl, "only numeric, symbolic, or logical expression a"
+ "llowed");
+ }
+ /* close the domain scope */
+ if (prt->domain != NULL) close_scope(mpl, prt->domain);
+#if 1 /* 14/VII-2006 */
+ /* parse optional redirection */
+ prt->fname = NULL, prt->app = 0;
+ if (mpl->token == T_GT || mpl->token == T_APPEND)
+ { prt->app = (mpl->token == T_APPEND);
+ get_token(mpl /* > or >> */);
+ /* parse expression for file name string */
+ prt->fname = expression_5(mpl);
+ /* convert it to symbolic type, if necessary */
+ if (prt->fname->type == A_NUMERIC)
+ prt->fname = make_unary(mpl, O_CVTSYM, prt->fname,
+ A_SYMBOLIC, 0);
+ /* check that now the expression is of symbolic type */
+ if (prt->fname->type != A_SYMBOLIC)
+ error(mpl, "file name expression has invalid type");
+ }
+#endif
+ /* the printf statement has been completely parsed */
+ if (mpl->token != T_SEMICOLON)
+ error(mpl, "syntax error in printf statement");
+ get_token(mpl /* ; */);
+ return prt;
+}
+
+/*----------------------------------------------------------------------
+-- for_statement - parse for statement.
+--
+-- This routine parses for statement using the syntax:
+--
+-- <for statement> ::= for <domain> <statement>
+-- <for statement> ::= for <domain> { <statement list> }
+-- <domain> ::= <indexing expression>
+-- <statement list> ::= <empty>
+-- <statement list> ::= <statement list> <statement>
+-- <statement> ::= <check statement>
+-- <statement> ::= <display statement>
+-- <statement> ::= <printf statement>
+-- <statement> ::= <for statement> */
+
+FOR *for_statement(MPL *mpl)
+{ FOR *fur;
+ STATEMENT *stmt, *last_stmt;
+ xassert(is_keyword(mpl, "for"));
+ /* create for descriptor */
+ fur = alloc(FOR);
+ fur->domain = NULL;
+ fur->list = last_stmt = NULL;
+ get_token(mpl /* for */);
+ /* parse indexing expression */
+ if (mpl->token != T_LBRACE)
+ error(mpl, "indexing expression missing where expected");
+ fur->domain = indexing_expression(mpl);
+ /* skip optional colon */
+ if (mpl->token == T_COLON) get_token(mpl /* : */);
+ /* parse for statement body */
+ if (mpl->token != T_LBRACE)
+ { /* parse simple statement */
+ fur->list = simple_statement(mpl, 1);
+ }
+ else
+ { /* parse compound statement */
+ get_token(mpl /* { */);
+ while (mpl->token != T_RBRACE)
+ { /* parse statement */
+ stmt = simple_statement(mpl, 1);
+ /* and append it to the end of the statement list */
+ if (last_stmt == NULL)
+ fur->list = stmt;
+ else
+ last_stmt->next = stmt;
+ last_stmt = stmt;
+ }
+ get_token(mpl /* } */);
+ }
+ /* close the domain scope */
+ xassert(fur->domain != NULL);
+ close_scope(mpl, fur->domain);
+ /* the for statement has been completely parsed */
+ return fur;
+}
+
+/*----------------------------------------------------------------------
+-- end_statement - parse end statement.
+--
+-- This routine parses end statement using the syntax:
+--
+-- <end statement> ::= end ; <eof> */
+
+void end_statement(MPL *mpl)
+{ if (!mpl->flag_d && is_keyword(mpl, "end") ||
+ mpl->flag_d && is_literal(mpl, "end"))
+ { get_token(mpl /* end */);
+ if (mpl->token == T_SEMICOLON)
+ get_token(mpl /* ; */);
+ else
+ warning(mpl, "no semicolon following end statement; missing"
+ " semicolon inserted");
+ }
+ else
+ warning(mpl, "unexpected end of file; missing end statement in"
+ "serted");
+ if (mpl->token != T_EOF)
+ warning(mpl, "some text detected beyond end statement; text ig"
+ "nored");
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- simple_statement - parse simple statement.
+--
+-- This routine parses simple statement using the syntax:
+--
+-- <statement> ::= <set statement>
+-- <statement> ::= <parameter statement>
+-- <statement> ::= <variable statement>
+-- <statement> ::= <constraint statement>
+-- <statement> ::= <objective statement>
+-- <statement> ::= <solve statement>
+-- <statement> ::= <check statement>
+-- <statement> ::= <display statement>
+-- <statement> ::= <printf statement>
+-- <statement> ::= <for statement>
+--
+-- If the flag spec is set, some statements cannot be used. */
+
+STATEMENT *simple_statement(MPL *mpl, int spec)
+{ STATEMENT *stmt;
+ stmt = alloc(STATEMENT);
+ stmt->line = mpl->line;
+ stmt->next = NULL;
+ if (is_keyword(mpl, "set"))
+ { if (spec)
+ error(mpl, "set statement not allowed here");
+ stmt->type = A_SET;
+ stmt->u.set = set_statement(mpl);
+ }
+ else if (is_keyword(mpl, "param"))
+ { if (spec)
+ error(mpl, "parameter statement not allowed here");
+ stmt->type = A_PARAMETER;
+ stmt->u.par = parameter_statement(mpl);
+ }
+ else if (is_keyword(mpl, "var"))
+ { if (spec)
+ error(mpl, "variable statement not allowed here");
+ stmt->type = A_VARIABLE;
+ stmt->u.var = variable_statement(mpl);
+ }
+ else if (is_keyword(mpl, "subject") ||
+ is_keyword(mpl, "subj") ||
+ mpl->token == T_SPTP)
+ { if (spec)
+ error(mpl, "constraint statement not allowed here");
+ stmt->type = A_CONSTRAINT;
+ stmt->u.con = constraint_statement(mpl);
+ }
+ else if (is_keyword(mpl, "minimize") ||
+ is_keyword(mpl, "maximize"))
+ { if (spec)
+ error(mpl, "objective statement not allowed here");
+ stmt->type = A_CONSTRAINT;
+ stmt->u.con = objective_statement(mpl);
+ }
+#if 1 /* 11/II-2008 */
+ else if (is_keyword(mpl, "table"))
+ { if (spec)
+ error(mpl, "table statement not allowed here");
+ stmt->type = A_TABLE;
+ stmt->u.tab = table_statement(mpl);
+ }
+#endif
+ else if (is_keyword(mpl, "solve"))
+ { if (spec)
+ error(mpl, "solve statement not allowed here");
+ stmt->type = A_SOLVE;
+ stmt->u.slv = solve_statement(mpl);
+ }
+ else if (is_keyword(mpl, "check"))
+ { stmt->type = A_CHECK;
+ stmt->u.chk = check_statement(mpl);
+ }
+ else if (is_keyword(mpl, "display"))
+ { stmt->type = A_DISPLAY;
+ stmt->u.dpy = display_statement(mpl);
+ }
+ else if (is_keyword(mpl, "printf"))
+ { stmt->type = A_PRINTF;
+ stmt->u.prt = printf_statement(mpl);
+ }
+ else if (is_keyword(mpl, "for"))
+ { stmt->type = A_FOR;
+ stmt->u.fur = for_statement(mpl);
+ }
+ else if (mpl->token == T_NAME)
+ { if (spec)
+ error(mpl, "constraint statement not allowed here");
+ stmt->type = A_CONSTRAINT;
+ stmt->u.con = constraint_statement(mpl);
+ }
+ else if (is_reserved(mpl))
+ error(mpl, "invalid use of reserved keyword %s", mpl->image);
+ else
+ error(mpl, "syntax error in model section");
+ return stmt;
+}
+
+/*----------------------------------------------------------------------
+-- model_section - parse model section.
+--
+-- This routine parses model section using the syntax:
+--
+-- <model section> ::= <empty>
+-- <model section> ::= <model section> <statement>
+--
+-- Parsing model section is terminated by either the keyword 'data', or
+-- the keyword 'end', or the end of file. */
+
+void model_section(MPL *mpl)
+{ STATEMENT *stmt, *last_stmt;
+ xassert(mpl->model == NULL);
+ last_stmt = NULL;
+ while (!(mpl->token == T_EOF || is_keyword(mpl, "data") ||
+ is_keyword(mpl, "end")))
+ { /* parse statement */
+ stmt = simple_statement(mpl, 0);
+ /* and append it to the end of the statement list */
+ if (last_stmt == NULL)
+ mpl->model = stmt;
+ else
+ last_stmt->next = stmt;
+ last_stmt = stmt;
+ }
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/mpl/mpl2.c b/test/monniaux/glpk-4.65/src/mpl/mpl2.c
new file mode 100644
index 00000000..0f99528b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/mpl/mpl2.c
@@ -0,0 +1,1202 @@
+/* mpl2.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2003-2016 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/>.
+***********************************************************************/
+
+#include "mpl.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 */
diff --git a/test/monniaux/glpk-4.65/src/mpl/mpl3.c b/test/monniaux/glpk-4.65/src/mpl/mpl3.c
new file mode 100644
index 00000000..2489db27
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/mpl/mpl3.c
@@ -0,0 +1,6100 @@
+/* mpl3.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2003-2016 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/>.
+***********************************************************************/
+
+#include "mpl.h"
+
+/**********************************************************************/
+/* * * FLOATING-POINT NUMBERS * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- fp_add - floating-point addition.
+--
+-- This routine computes the sum x + y. */
+
+double fp_add(MPL *mpl, double x, double y)
+{ if (x > 0.0 && y > 0.0 && x > + 0.999 * DBL_MAX - y ||
+ x < 0.0 && y < 0.0 && x < - 0.999 * DBL_MAX - y)
+ error(mpl, "%.*g + %.*g; floating-point overflow",
+ DBL_DIG, x, DBL_DIG, y);
+ return x + y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_sub - floating-point subtraction.
+--
+-- This routine computes the difference x - y. */
+
+double fp_sub(MPL *mpl, double x, double y)
+{ if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y ||
+ x < 0.0 && y > 0.0 && x < - 0.999 * DBL_MAX + y)
+ error(mpl, "%.*g - %.*g; floating-point overflow",
+ DBL_DIG, x, DBL_DIG, y);
+ return x - y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_less - floating-point non-negative subtraction.
+--
+-- This routine computes the non-negative difference max(0, x - y). */
+
+double fp_less(MPL *mpl, double x, double y)
+{ if (x < y) return 0.0;
+ if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y)
+ error(mpl, "%.*g less %.*g; floating-point overflow",
+ DBL_DIG, x, DBL_DIG, y);
+ return x - y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_mul - floating-point multiplication.
+--
+-- This routine computes the product x * y. */
+
+double fp_mul(MPL *mpl, double x, double y)
+{ if (fabs(y) > 1.0 && fabs(x) > (0.999 * DBL_MAX) / fabs(y))
+ error(mpl, "%.*g * %.*g; floating-point overflow",
+ DBL_DIG, x, DBL_DIG, y);
+ return x * y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_div - floating-point division.
+--
+-- This routine computes the quotient x / y. */
+
+double fp_div(MPL *mpl, double x, double y)
+{ if (fabs(y) < DBL_MIN)
+ error(mpl, "%.*g / %.*g; floating-point zero divide",
+ DBL_DIG, x, DBL_DIG, y);
+ if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
+ error(mpl, "%.*g / %.*g; floating-point overflow",
+ DBL_DIG, x, DBL_DIG, y);
+ return x / y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_idiv - floating-point quotient of exact division.
+--
+-- This routine computes the quotient of exact division x div y. */
+
+double fp_idiv(MPL *mpl, double x, double y)
+{ if (fabs(y) < DBL_MIN)
+ error(mpl, "%.*g div %.*g; floating-point zero divide",
+ DBL_DIG, x, DBL_DIG, y);
+ if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
+ error(mpl, "%.*g div %.*g; floating-point overflow",
+ DBL_DIG, x, DBL_DIG, y);
+ x /= y;
+ return x > 0.0 ? floor(x) : x < 0.0 ? ceil(x) : 0.0;
+}
+
+/*----------------------------------------------------------------------
+-- fp_mod - floating-point remainder of exact division.
+--
+-- This routine computes the remainder of exact division x mod y.
+--
+-- NOTE: By definition x mod y = x - y * floor(x / y). */
+
+double fp_mod(MPL *mpl, double x, double y)
+{ double r;
+ xassert(mpl == mpl);
+ if (x == 0.0)
+ r = 0.0;
+ else if (y == 0.0)
+ r = x;
+ else
+ { r = fmod(fabs(x), fabs(y));
+ if (r != 0.0)
+ { if (x < 0.0) r = - r;
+ if (x > 0.0 && y < 0.0 || x < 0.0 && y > 0.0) r += y;
+ }
+ }
+ return r;
+}
+
+/*----------------------------------------------------------------------
+-- fp_power - floating-point exponentiation (raise to power).
+--
+-- This routine computes the exponentiation x ** y. */
+
+double fp_power(MPL *mpl, double x, double y)
+{ double r;
+ if (x == 0.0 && y <= 0.0 || x < 0.0 && y != floor(y))
+ error(mpl, "%.*g ** %.*g; result undefined",
+ DBL_DIG, x, DBL_DIG, y);
+ if (x == 0.0) goto eval;
+ if (fabs(x) > 1.0 && y > +1.0 &&
+ +log(fabs(x)) > (0.999 * log(DBL_MAX)) / y ||
+ fabs(x) < 1.0 && y < -1.0 &&
+ +log(fabs(x)) < (0.999 * log(DBL_MAX)) / y)
+ error(mpl, "%.*g ** %.*g; floating-point overflow",
+ DBL_DIG, x, DBL_DIG, y);
+ if (fabs(x) > 1.0 && y < -1.0 &&
+ -log(fabs(x)) < (0.999 * log(DBL_MAX)) / y ||
+ fabs(x) < 1.0 && y > +1.0 &&
+ -log(fabs(x)) > (0.999 * log(DBL_MAX)) / y)
+ r = 0.0;
+ else
+eval: r = pow(x, y);
+ return r;
+}
+
+/*----------------------------------------------------------------------
+-- fp_exp - floating-point base-e exponential.
+--
+-- This routine computes the base-e exponential e ** x. */
+
+double fp_exp(MPL *mpl, double x)
+{ if (x > 0.999 * log(DBL_MAX))
+ error(mpl, "exp(%.*g); floating-point overflow", DBL_DIG, x);
+ return exp(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_log - floating-point natural logarithm.
+--
+-- This routine computes the natural logarithm log x. */
+
+double fp_log(MPL *mpl, double x)
+{ if (x <= 0.0)
+ error(mpl, "log(%.*g); non-positive argument", DBL_DIG, x);
+ return log(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_log10 - floating-point common (decimal) logarithm.
+--
+-- This routine computes the common (decimal) logarithm lg x. */
+
+double fp_log10(MPL *mpl, double x)
+{ if (x <= 0.0)
+ error(mpl, "log10(%.*g); non-positive argument", DBL_DIG, x);
+ return log10(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_sqrt - floating-point square root.
+--
+-- This routine computes the square root x ** 0.5. */
+
+double fp_sqrt(MPL *mpl, double x)
+{ if (x < 0.0)
+ error(mpl, "sqrt(%.*g); negative argument", DBL_DIG, x);
+ return sqrt(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_sin - floating-point trigonometric sine.
+--
+-- This routine computes the trigonometric sine sin(x). */
+
+double fp_sin(MPL *mpl, double x)
+{ if (!(-1e6 <= x && x <= +1e6))
+ error(mpl, "sin(%.*g); argument too large", DBL_DIG, x);
+ return sin(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_cos - floating-point trigonometric cosine.
+--
+-- This routine computes the trigonometric cosine cos(x). */
+
+double fp_cos(MPL *mpl, double x)
+{ if (!(-1e6 <= x && x <= +1e6))
+ error(mpl, "cos(%.*g); argument too large", DBL_DIG, x);
+ return cos(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_tan - floating-point trigonometric tangent.
+--
+-- This routine computes the trigonometric tangent tan(x). */
+
+double fp_tan(MPL *mpl, double x)
+{ if (!(-1e6 <= x && x <= +1e6))
+ error(mpl, "tan(%.*g); argument too large", DBL_DIG, x);
+ return tan(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_atan - floating-point trigonometric arctangent.
+--
+-- This routine computes the trigonometric arctangent atan(x). */
+
+double fp_atan(MPL *mpl, double x)
+{ xassert(mpl == mpl);
+ return atan(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_atan2 - floating-point trigonometric arctangent.
+--
+-- This routine computes the trigonometric arctangent atan(y / x). */
+
+double fp_atan2(MPL *mpl, double y, double x)
+{ xassert(mpl == mpl);
+ return atan2(y, x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_round - round floating-point value to n fractional digits.
+--
+-- This routine rounds given floating-point value x to n fractional
+-- digits with the formula:
+--
+-- round(x, n) = floor(x * 10^n + 0.5) / 10^n.
+--
+-- The parameter n is assumed to be integer. */
+
+double fp_round(MPL *mpl, double x, double n)
+{ double ten_to_n;
+ if (n != floor(n))
+ error(mpl, "round(%.*g, %.*g); non-integer second argument",
+ DBL_DIG, x, DBL_DIG, n);
+ if (n <= DBL_DIG + 2)
+ { ten_to_n = pow(10.0, n);
+ if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
+ { x = floor(x * ten_to_n + 0.5);
+ if (x != 0.0) x /= ten_to_n;
+ }
+ }
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- fp_trunc - truncate floating-point value to n fractional digits.
+--
+-- This routine truncates given floating-point value x to n fractional
+-- digits with the formula:
+--
+-- ( floor(x * 10^n) / 10^n, if x >= 0
+-- trunc(x, n) = <
+-- ( ceil(x * 10^n) / 10^n, if x < 0
+--
+-- The parameter n is assumed to be integer. */
+
+double fp_trunc(MPL *mpl, double x, double n)
+{ double ten_to_n;
+ if (n != floor(n))
+ error(mpl, "trunc(%.*g, %.*g); non-integer second argument",
+ DBL_DIG, x, DBL_DIG, n);
+ if (n <= DBL_DIG + 2)
+ { ten_to_n = pow(10.0, n);
+ if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
+ { x = (x >= 0.0 ? floor(x * ten_to_n) : ceil(x * ten_to_n));
+ if (x != 0.0) x /= ten_to_n;
+ }
+ }
+ return x;
+}
+
+/**********************************************************************/
+/* * * PSEUDO-RANDOM NUMBER GENERATORS * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- fp_irand224 - pseudo-random integer in the range [0, 2^24).
+--
+-- This routine returns a next pseudo-random integer (converted to
+-- floating-point) which is uniformly distributed between 0 and 2^24-1,
+-- inclusive. */
+
+#define two_to_the_24 0x1000000
+
+double fp_irand224(MPL *mpl)
+{ return
+ (double)rng_unif_rand(mpl->rand, two_to_the_24);
+}
+
+/*----------------------------------------------------------------------
+-- fp_uniform01 - pseudo-random number in the range [0, 1).
+--
+-- This routine returns a next pseudo-random number which is uniformly
+-- distributed in the range [0, 1). */
+
+#define two_to_the_31 ((unsigned int)0x80000000)
+
+double fp_uniform01(MPL *mpl)
+{ return
+ (double)rng_next_rand(mpl->rand) / (double)two_to_the_31;
+}
+
+/*----------------------------------------------------------------------
+-- fp_uniform - pseudo-random number in the range [a, b).
+--
+-- This routine returns a next pseudo-random number which is uniformly
+-- distributed in the range [a, b). */
+
+double fp_uniform(MPL *mpl, double a, double b)
+{ double x;
+ if (a >= b)
+ error(mpl, "Uniform(%.*g, %.*g); invalid range",
+ DBL_DIG, a, DBL_DIG, b);
+ x = fp_uniform01(mpl);
+#if 0
+ x = a * (1.0 - x) + b * x;
+#else
+ x = fp_add(mpl, a * (1.0 - x), b * x);
+#endif
+ return x;
+}
+
+/*----------------------------------------------------------------------
+-- fp_normal01 - Gaussian random variate with mu = 0 and sigma = 1.
+--
+-- This routine returns a Gaussian random variate with zero mean and
+-- unit standard deviation. The polar (Box-Mueller) method is used.
+--
+-- This code is a modified version of the routine gsl_ran_gaussian from
+-- the GNU Scientific Library Version 1.0. */
+
+double fp_normal01(MPL *mpl)
+{ double x, y, r2;
+ do
+ { /* choose x, y in uniform square (-1,-1) to (+1,+1) */
+ x = -1.0 + 2.0 * fp_uniform01(mpl);
+ y = -1.0 + 2.0 * fp_uniform01(mpl);
+ /* see if it is in the unit circle */
+ r2 = x * x + y * y;
+ } while (r2 > 1.0 || r2 == 0.0);
+ /* Box-Muller transform */
+ return y * sqrt(-2.0 * log (r2) / r2);
+}
+
+/*----------------------------------------------------------------------
+-- fp_normal - Gaussian random variate with specified mu and sigma.
+--
+-- This routine returns a Gaussian random variate with mean mu and
+-- standard deviation sigma. */
+
+double fp_normal(MPL *mpl, double mu, double sigma)
+{ double x;
+#if 0
+ x = mu + sigma * fp_normal01(mpl);
+#else
+ x = fp_add(mpl, mu, fp_mul(mpl, sigma, fp_normal01(mpl)));
+#endif
+ return x;
+}
+
+/**********************************************************************/
+/* * * SEGMENTED CHARACTER STRINGS * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_string - create character string.
+--
+-- This routine creates a segmented character string, which is exactly
+-- equivalent to specified character string. */
+
+STRING *create_string
+( MPL *mpl,
+ char buf[MAX_LENGTH+1] /* not changed */
+)
+#if 0
+{ STRING *head, *tail;
+ int i, j;
+ xassert(buf != NULL);
+ xassert(strlen(buf) <= MAX_LENGTH);
+ head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
+ for (i = j = 0; ; i++)
+ { if ((tail->seg[j++] = buf[i]) == '\0') break;
+ if (j == STRSEG_SIZE)
+tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING))), j = 0;
+ }
+ tail->next = NULL;
+ return head;
+}
+#else
+{ STRING *str;
+ xassert(strlen(buf) <= MAX_LENGTH);
+ str = dmp_get_atom(mpl->strings, strlen(buf)+1);
+ strcpy(str, buf);
+ return str;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- copy_string - make copy of character string.
+--
+-- This routine returns an exact copy of segmented character string. */
+
+STRING *copy_string
+( MPL *mpl,
+ STRING *str /* not changed */
+)
+#if 0
+{ STRING *head, *tail;
+ xassert(str != NULL);
+ head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
+ for (; str != NULL; str = str->next)
+ { memcpy(tail->seg, str->seg, STRSEG_SIZE);
+ if (str->next != NULL)
+tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING)));
+ }
+ tail->next = NULL;
+ return head;
+}
+#else
+{ xassert(mpl == mpl);
+ return create_string(mpl, str);
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- compare_strings - compare one character string with another.
+--
+-- This routine compares one segmented character strings with another
+-- and returns the result of comparison as follows:
+--
+-- = 0 - both strings are identical;
+-- < 0 - the first string precedes the second one;
+-- > 0 - the first string follows the second one. */
+
+int compare_strings
+( MPL *mpl,
+ STRING *str1, /* not changed */
+ STRING *str2 /* not changed */
+)
+#if 0
+{ int j, c1, c2;
+ xassert(mpl == mpl);
+ for (;; str1 = str1->next, str2 = str2->next)
+ { xassert(str1 != NULL);
+ xassert(str2 != NULL);
+ for (j = 0; j < STRSEG_SIZE; j++)
+ { c1 = (unsigned char)str1->seg[j];
+ c2 = (unsigned char)str2->seg[j];
+ if (c1 < c2) return -1;
+ if (c1 > c2) return +1;
+ if (c1 == '\0') goto done;
+ }
+ }
+done: return 0;
+}
+#else
+{ xassert(mpl == mpl);
+ return strcmp(str1, str2);
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- fetch_string - extract content of character string.
+--
+-- This routine returns a character string, which is exactly equivalent
+-- to specified segmented character string. */
+
+char *fetch_string
+( MPL *mpl,
+ STRING *str, /* not changed */
+ char buf[MAX_LENGTH+1] /* modified */
+)
+#if 0
+{ int i, j;
+ xassert(mpl == mpl);
+ xassert(buf != NULL);
+ for (i = 0; ; str = str->next)
+ { xassert(str != NULL);
+ for (j = 0; j < STRSEG_SIZE; j++)
+ if ((buf[i++] = str->seg[j]) == '\0') goto done;
+ }
+done: xassert(strlen(buf) <= MAX_LENGTH);
+ return buf;
+}
+#else
+{ xassert(mpl == mpl);
+ return strcpy(buf, str);
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- delete_string - delete character string.
+--
+-- This routine deletes specified segmented character string. */
+
+void delete_string
+( MPL *mpl,
+ STRING *str /* destroyed */
+)
+#if 0
+{ STRING *temp;
+ xassert(str != NULL);
+ while (str != NULL)
+ { temp = str;
+ str = str->next;
+ dmp_free_atom(mpl->strings, temp, sizeof(STRING));
+ }
+ return;
+}
+#else
+{ dmp_free_atom(mpl->strings, str, strlen(str)+1);
+ return;
+}
+#endif
+
+/**********************************************************************/
+/* * * SYMBOLS * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_symbol_num - create symbol of numeric type.
+--
+-- This routine creates a symbol, which has a numeric value specified
+-- as floating-point number. */
+
+SYMBOL *create_symbol_num(MPL *mpl, double num)
+{ SYMBOL *sym;
+ sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
+ sym->num = num;
+ sym->str = NULL;
+ return sym;
+}
+
+/*----------------------------------------------------------------------
+-- create_symbol_str - create symbol of abstract type.
+--
+-- This routine creates a symbol, which has an abstract value specified
+-- as segmented character string. */
+
+SYMBOL *create_symbol_str
+( MPL *mpl,
+ STRING *str /* destroyed */
+)
+{ SYMBOL *sym;
+ xassert(str != NULL);
+ sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
+ sym->num = 0.0;
+ sym->str = str;
+ return sym;
+}
+
+/*----------------------------------------------------------------------
+-- copy_symbol - make copy of symbol.
+--
+-- This routine returns an exact copy of symbol. */
+
+SYMBOL *copy_symbol
+( MPL *mpl,
+ SYMBOL *sym /* not changed */
+)
+{ SYMBOL *copy;
+ xassert(sym != NULL);
+ copy = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
+ if (sym->str == NULL)
+ { copy->num = sym->num;
+ copy->str = NULL;
+ }
+ else
+ { copy->num = 0.0;
+ copy->str = copy_string(mpl, sym->str);
+ }
+ return copy;
+}
+
+/*----------------------------------------------------------------------
+-- compare_symbols - compare one symbol with another.
+--
+-- This routine compares one symbol with another and returns the result
+-- of comparison as follows:
+--
+-- = 0 - both symbols are identical;
+-- < 0 - the first symbol precedes the second one;
+-- > 0 - the first symbol follows the second one.
+--
+-- Note that the linear order, in which symbols follow each other, is
+-- implementation-dependent. It may be not an alphabetical order. */
+
+int compare_symbols
+( MPL *mpl,
+ SYMBOL *sym1, /* not changed */
+ SYMBOL *sym2 /* not changed */
+)
+{ xassert(sym1 != NULL);
+ xassert(sym2 != NULL);
+ /* let all numeric quantities precede all symbolic quantities */
+ if (sym1->str == NULL && sym2->str == NULL)
+ { if (sym1->num < sym2->num) return -1;
+ if (sym1->num > sym2->num) return +1;
+ return 0;
+ }
+ if (sym1->str == NULL) return -1;
+ if (sym2->str == NULL) return +1;
+ return compare_strings(mpl, sym1->str, sym2->str);
+}
+
+/*----------------------------------------------------------------------
+-- delete_symbol - delete symbol.
+--
+-- This routine deletes specified symbol. */
+
+void delete_symbol
+( MPL *mpl,
+ SYMBOL *sym /* destroyed */
+)
+{ xassert(sym != NULL);
+ if (sym->str != NULL) delete_string(mpl, sym->str);
+ dmp_free_atom(mpl->symbols, sym, sizeof(SYMBOL));
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- format_symbol - format symbol for displaying or printing.
+--
+-- This routine converts specified symbol to a charater string, which
+-- is suitable for displaying or printing.
+--
+-- The resultant string is never longer than 255 characters. If it gets
+-- longer, it is truncated from the right and appended by dots. */
+
+char *format_symbol
+( MPL *mpl,
+ SYMBOL *sym /* not changed */
+)
+{ char *buf = mpl->sym_buf;
+ xassert(sym != NULL);
+ if (sym->str == NULL)
+ sprintf(buf, "%.*g", DBL_DIG, sym->num);
+ else
+ { char str[MAX_LENGTH+1];
+ int quoted, j, len;
+ fetch_string(mpl, sym->str, str);
+ if (!(isalpha((unsigned char)str[0]) || str[0] == '_'))
+ quoted = 1;
+ else
+ { quoted = 0;
+ for (j = 1; str[j] != '\0'; j++)
+ { if (!(isalnum((unsigned char)str[j]) ||
+ strchr("+-._", (unsigned char)str[j]) != NULL))
+ { quoted = 1;
+ break;
+ }
+ }
+ }
+# define safe_append(c) \
+ (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
+ buf[0] = '\0', len = 0;
+ if (quoted) safe_append('\'');
+ for (j = 0; str[j] != '\0'; j++)
+ { if (quoted && str[j] == '\'') safe_append('\'');
+ safe_append(str[j]);
+ }
+ if (quoted) safe_append('\'');
+# undef safe_append
+ buf[len] = '\0';
+ if (len == 255) strcpy(buf+252, "...");
+ }
+ xassert(strlen(buf) <= 255);
+ return buf;
+}
+
+/*----------------------------------------------------------------------
+-- concat_symbols - concatenate one symbol with another.
+--
+-- This routine concatenates values of two given symbols and assigns
+-- the resultant character string to a new symbol, which is returned on
+-- exit. Both original symbols are destroyed. */
+
+SYMBOL *concat_symbols
+( MPL *mpl,
+ SYMBOL *sym1, /* destroyed */
+ SYMBOL *sym2 /* destroyed */
+)
+{ char str1[MAX_LENGTH+1], str2[MAX_LENGTH+1];
+ xassert(MAX_LENGTH >= DBL_DIG + DBL_DIG);
+ if (sym1->str == NULL)
+ sprintf(str1, "%.*g", DBL_DIG, sym1->num);
+ else
+ fetch_string(mpl, sym1->str, str1);
+ if (sym2->str == NULL)
+ sprintf(str2, "%.*g", DBL_DIG, sym2->num);
+ else
+ fetch_string(mpl, sym2->str, str2);
+ if (strlen(str1) + strlen(str2) > MAX_LENGTH)
+ { char buf[255+1];
+ strcpy(buf, format_symbol(mpl, sym1));
+ xassert(strlen(buf) < sizeof(buf));
+ error(mpl, "%s & %s; resultant symbol exceeds %d characters",
+ buf, format_symbol(mpl, sym2), MAX_LENGTH);
+ }
+ delete_symbol(mpl, sym1);
+ delete_symbol(mpl, sym2);
+ return create_symbol_str(mpl, create_string(mpl, strcat(str1,
+ str2)));
+}
+
+/**********************************************************************/
+/* * * N-TUPLES * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_tuple - create n-tuple.
+--
+-- This routine creates a n-tuple, which initially has no components,
+-- i.e. which is 0-tuple. */
+
+TUPLE *create_tuple(MPL *mpl)
+{ TUPLE *tuple;
+ xassert(mpl == mpl);
+ tuple = NULL;
+ return tuple;
+}
+
+/*----------------------------------------------------------------------
+-- expand_tuple - append symbol to n-tuple.
+--
+-- This routine expands n-tuple appending to it a given symbol, which
+-- becomes its new last component. */
+
+TUPLE *expand_tuple
+( MPL *mpl,
+ TUPLE *tuple, /* destroyed */
+ SYMBOL *sym /* destroyed */
+)
+{ TUPLE *tail, *temp;
+ xassert(sym != NULL);
+ /* create a new component */
+ tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
+ tail->sym = sym;
+ tail->next = NULL;
+ /* and append it to the component list */
+ if (tuple == NULL)
+ tuple = tail;
+ else
+ { for (temp = tuple; temp->next != NULL; temp = temp->next);
+ temp->next = tail;
+ }
+ return tuple;
+}
+
+/*----------------------------------------------------------------------
+-- tuple_dimen - determine dimension of n-tuple.
+--
+-- This routine returns dimension of n-tuple, i.e. number of components
+-- in the n-tuple. */
+
+int tuple_dimen
+( MPL *mpl,
+ TUPLE *tuple /* not changed */
+)
+{ TUPLE *temp;
+ int dim = 0;
+ xassert(mpl == mpl);
+ for (temp = tuple; temp != NULL; temp = temp->next) dim++;
+ return dim;
+}
+
+/*----------------------------------------------------------------------
+-- copy_tuple - make copy of n-tuple.
+--
+-- This routine returns an exact copy of n-tuple. */
+
+TUPLE *copy_tuple
+( MPL *mpl,
+ TUPLE *tuple /* not changed */
+)
+{ TUPLE *head, *tail;
+ if (tuple == NULL)
+ head = NULL;
+ else
+ { head = tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
+ for (; tuple != NULL; tuple = tuple->next)
+ { xassert(tuple->sym != NULL);
+ tail->sym = copy_symbol(mpl, tuple->sym);
+ if (tuple->next != NULL)
+tail = (tail->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
+ }
+ tail->next = NULL;
+ }
+ return head;
+}
+
+/*----------------------------------------------------------------------
+-- compare_tuples - compare one n-tuple with another.
+--
+-- This routine compares two given n-tuples, which must have the same
+-- dimension (not checked for the sake of efficiency), and returns one
+-- of the following codes:
+--
+-- = 0 - both n-tuples are identical;
+-- < 0 - the first n-tuple precedes the second one;
+-- > 0 - the first n-tuple follows the second one.
+--
+-- Note that the linear order, in which n-tuples follow each other, is
+-- implementation-dependent. It may be not an alphabetical order. */
+
+int compare_tuples
+( MPL *mpl,
+ TUPLE *tuple1, /* not changed */
+ TUPLE *tuple2 /* not changed */
+)
+{ TUPLE *item1, *item2;
+ int ret;
+ xassert(mpl == mpl);
+ for (item1 = tuple1, item2 = tuple2; item1 != NULL;
+ item1 = item1->next, item2 = item2->next)
+ { xassert(item2 != NULL);
+ xassert(item1->sym != NULL);
+ xassert(item2->sym != NULL);
+ ret = compare_symbols(mpl, item1->sym, item2->sym);
+ if (ret != 0) return ret;
+ }
+ xassert(item2 == NULL);
+ return 0;
+}
+
+/*----------------------------------------------------------------------
+-- build_subtuple - build subtuple of given n-tuple.
+--
+-- This routine builds subtuple, which consists of first dim components
+-- of given n-tuple. */
+
+TUPLE *build_subtuple
+( MPL *mpl,
+ TUPLE *tuple, /* not changed */
+ int dim
+)
+{ TUPLE *head, *temp;
+ int j;
+ head = create_tuple(mpl);
+ for (j = 1, temp = tuple; j <= dim; j++, temp = temp->next)
+ { xassert(temp != NULL);
+ head = expand_tuple(mpl, head, copy_symbol(mpl, temp->sym));
+ }
+ return head;
+}
+
+/*----------------------------------------------------------------------
+-- delete_tuple - delete n-tuple.
+--
+-- This routine deletes specified n-tuple. */
+
+void delete_tuple
+( MPL *mpl,
+ TUPLE *tuple /* destroyed */
+)
+{ TUPLE *temp;
+ while (tuple != NULL)
+ { temp = tuple;
+ tuple = temp->next;
+ xassert(temp->sym != NULL);
+ delete_symbol(mpl, temp->sym);
+ dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- format_tuple - format n-tuple for displaying or printing.
+--
+-- This routine converts specified n-tuple to a character string, which
+-- is suitable for displaying or printing.
+--
+-- The resultant string is never longer than 255 characters. If it gets
+-- longer, it is truncated from the right and appended by dots. */
+
+char *format_tuple
+( MPL *mpl,
+ int c,
+ TUPLE *tuple /* not changed */
+)
+{ TUPLE *temp;
+ int dim, j, len;
+ char *buf = mpl->tup_buf, str[255+1], *save;
+# define safe_append(c) \
+ (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
+ buf[0] = '\0', len = 0;
+ dim = tuple_dimen(mpl, tuple);
+ if (c == '[' && dim > 0) safe_append('[');
+ if (c == '(' && dim > 1) safe_append('(');
+ for (temp = tuple; temp != NULL; temp = temp->next)
+ { if (temp != tuple) safe_append(',');
+ xassert(temp->sym != NULL);
+ save = mpl->sym_buf;
+ mpl->sym_buf = str;
+ format_symbol(mpl, temp->sym);
+ mpl->sym_buf = save;
+ xassert(strlen(str) < sizeof(str));
+ for (j = 0; str[j] != '\0'; j++) safe_append(str[j]);
+ }
+ if (c == '[' && dim > 0) safe_append(']');
+ if (c == '(' && dim > 1) safe_append(')');
+# undef safe_append
+ buf[len] = '\0';
+ if (len == 255) strcpy(buf+252, "...");
+ xassert(strlen(buf) <= 255);
+ return buf;
+}
+
+/**********************************************************************/
+/* * * ELEMENTAL SETS * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_elemset - create elemental set.
+--
+-- This routine creates an elemental set, whose members are n-tuples of
+-- specified dimension. Being created the set is initially empty. */
+
+ELEMSET *create_elemset(MPL *mpl, int dim)
+{ ELEMSET *set;
+ xassert(dim > 0);
+ set = create_array(mpl, A_NONE, dim);
+ return set;
+}
+
+/*----------------------------------------------------------------------
+-- find_tuple - check if elemental set contains given n-tuple.
+--
+-- This routine finds given n-tuple in specified elemental set in order
+-- to check if the set contains that n-tuple. If the n-tuple is found,
+-- the routine returns pointer to corresponding array member. Otherwise
+-- null pointer is returned. */
+
+MEMBER *find_tuple
+( MPL *mpl,
+ ELEMSET *set, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ xassert(set != NULL);
+ xassert(set->type == A_NONE);
+ xassert(set->dim == tuple_dimen(mpl, tuple));
+ return find_member(mpl, set, tuple);
+}
+
+/*----------------------------------------------------------------------
+-- add_tuple - add new n-tuple to elemental set.
+--
+-- This routine adds given n-tuple to specified elemental set.
+--
+-- For the sake of efficiency this routine doesn't check whether the
+-- set already contains the same n-tuple or not. Therefore the calling
+-- program should use the routine find_tuple (if necessary) in order to
+-- make sure that the given n-tuple is not contained in the set, since
+-- duplicate n-tuples within the same set are not allowed. */
+
+MEMBER *add_tuple
+( MPL *mpl,
+ ELEMSET *set, /* modified */
+ TUPLE *tuple /* destroyed */
+)
+{ MEMBER *memb;
+ xassert(set != NULL);
+ xassert(set->type == A_NONE);
+ xassert(set->dim == tuple_dimen(mpl, tuple));
+ memb = add_member(mpl, set, tuple);
+ memb->value.none = NULL;
+ return memb;
+}
+
+/*----------------------------------------------------------------------
+-- check_then_add - check and add new n-tuple to elemental set.
+--
+-- This routine is equivalent to the routine add_tuple except that it
+-- does check for duplicate n-tuples. */
+
+MEMBER *check_then_add
+( MPL *mpl,
+ ELEMSET *set, /* modified */
+ TUPLE *tuple /* destroyed */
+)
+{ if (find_tuple(mpl, set, tuple) != NULL)
+ error(mpl, "duplicate tuple %s detected", format_tuple(mpl,
+ '(', tuple));
+ return add_tuple(mpl, set, tuple);
+}
+
+/*----------------------------------------------------------------------
+-- copy_elemset - make copy of elemental set.
+--
+-- This routine makes an exact copy of elemental set. */
+
+ELEMSET *copy_elemset
+( MPL *mpl,
+ ELEMSET *set /* not changed */
+)
+{ ELEMSET *copy;
+ MEMBER *memb;
+ xassert(set != NULL);
+ xassert(set->type == A_NONE);
+ xassert(set->dim > 0);
+ copy = create_elemset(mpl, set->dim);
+ for (memb = set->head; memb != NULL; memb = memb->next)
+ add_tuple(mpl, copy, copy_tuple(mpl, memb->tuple));
+ return copy;
+}
+
+/*----------------------------------------------------------------------
+-- delete_elemset - delete elemental set.
+--
+-- This routine deletes specified elemental set. */
+
+void delete_elemset
+( MPL *mpl,
+ ELEMSET *set /* destroyed */
+)
+{ xassert(set != NULL);
+ xassert(set->type == A_NONE);
+ delete_array(mpl, set);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- arelset_size - compute size of "arithmetic" elemental set.
+--
+-- This routine computes the size of "arithmetic" elemental set, which
+-- is specified in the form of arithmetic progression:
+--
+-- { t0 .. tf by dt }.
+--
+-- The size is computed using the formula:
+--
+-- n = max(0, floor((tf - t0) / dt) + 1). */
+
+int arelset_size(MPL *mpl, double t0, double tf, double dt)
+{ double temp;
+ if (dt == 0.0)
+ error(mpl, "%.*g .. %.*g by %.*g; zero stride not allowed",
+ DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
+ if (tf > 0.0 && t0 < 0.0 && tf > + 0.999 * DBL_MAX + t0)
+ temp = +DBL_MAX;
+ else if (tf < 0.0 && t0 > 0.0 && tf < - 0.999 * DBL_MAX + t0)
+ temp = -DBL_MAX;
+ else
+ temp = tf - t0;
+ if (fabs(dt) < 1.0 && fabs(temp) > (0.999 * DBL_MAX) * fabs(dt))
+ { if (temp > 0.0 && dt > 0.0 || temp < 0.0 && dt < 0.0)
+ temp = +DBL_MAX;
+ else
+ temp = 0.0;
+ }
+ else
+ { temp = floor(temp / dt) + 1.0;
+ if (temp < 0.0) temp = 0.0;
+ }
+ xassert(temp >= 0.0);
+ if (temp > (double)(INT_MAX - 1))
+ error(mpl, "%.*g .. %.*g by %.*g; set too large",
+ DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
+ return (int)(temp + 0.5);
+}
+
+/*----------------------------------------------------------------------
+-- arelset_member - compute member of "arithmetic" elemental set.
+--
+-- This routine returns a numeric value of symbol, which is equivalent
+-- to j-th member of given "arithmetic" elemental set specified in the
+-- form of arithmetic progression:
+--
+-- { t0 .. tf by dt }.
+--
+-- The symbol value is computed with the formula:
+--
+-- j-th member = t0 + (j - 1) * dt,
+--
+-- The number j must satisfy to the restriction 1 <= j <= n, where n is
+-- the set size computed by the routine arelset_size. */
+
+double arelset_member(MPL *mpl, double t0, double tf, double dt, int j)
+{ xassert(1 <= j && j <= arelset_size(mpl, t0, tf, dt));
+ return t0 + (double)(j - 1) * dt;
+}
+
+/*----------------------------------------------------------------------
+-- create_arelset - create "arithmetic" elemental set.
+--
+-- This routine creates "arithmetic" elemental set, which is specified
+-- in the form of arithmetic progression:
+--
+-- { t0 .. tf by dt }.
+--
+-- Components of this set are 1-tuples. */
+
+ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt)
+{ ELEMSET *set;
+ int j, n;
+ set = create_elemset(mpl, 1);
+ n = arelset_size(mpl, t0, tf, dt);
+ for (j = 1; j <= n; j++)
+ { add_tuple
+ ( mpl,
+ set,
+ expand_tuple
+ ( mpl,
+ create_tuple(mpl),
+ create_symbol_num
+ ( mpl,
+ arelset_member(mpl, t0, tf, dt, j)
+ )
+ )
+ );
+ }
+ return set;
+}
+
+/*----------------------------------------------------------------------
+-- set_union - union of two elemental sets.
+--
+-- This routine computes the union:
+--
+-- X U Y = { j | (j in X) or (j in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_union
+( MPL *mpl,
+ ELEMSET *X, /* destroyed */
+ ELEMSET *Y /* destroyed */
+)
+{ MEMBER *memb;
+ xassert(X != NULL);
+ xassert(X->type == A_NONE);
+ xassert(X->dim > 0);
+ xassert(Y != NULL);
+ xassert(Y->type == A_NONE);
+ xassert(Y->dim > 0);
+ xassert(X->dim == Y->dim);
+ for (memb = Y->head; memb != NULL; memb = memb->next)
+ { if (find_tuple(mpl, X, memb->tuple) == NULL)
+ add_tuple(mpl, X, copy_tuple(mpl, memb->tuple));
+ }
+ delete_elemset(mpl, Y);
+ return X;
+}
+
+/*----------------------------------------------------------------------
+-- set_diff - difference between two elemental sets.
+--
+-- This routine computes the difference:
+--
+-- X \ Y = { j | (j in X) and (j not in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_diff
+( MPL *mpl,
+ ELEMSET *X, /* destroyed */
+ ELEMSET *Y /* destroyed */
+)
+{ ELEMSET *Z;
+ MEMBER *memb;
+ xassert(X != NULL);
+ xassert(X->type == A_NONE);
+ xassert(X->dim > 0);
+ xassert(Y != NULL);
+ xassert(Y->type == A_NONE);
+ xassert(Y->dim > 0);
+ xassert(X->dim == Y->dim);
+ Z = create_elemset(mpl, X->dim);
+ for (memb = X->head; memb != NULL; memb = memb->next)
+ { if (find_tuple(mpl, Y, memb->tuple) == NULL)
+ add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+ }
+ delete_elemset(mpl, X);
+ delete_elemset(mpl, Y);
+ return Z;
+}
+
+/*----------------------------------------------------------------------
+-- set_symdiff - symmetric difference between two elemental sets.
+--
+-- This routine computes the symmetric difference:
+--
+-- X (+) Y = (X \ Y) U (Y \ X),
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_symdiff
+( MPL *mpl,
+ ELEMSET *X, /* destroyed */
+ ELEMSET *Y /* destroyed */
+)
+{ ELEMSET *Z;
+ MEMBER *memb;
+ xassert(X != NULL);
+ xassert(X->type == A_NONE);
+ xassert(X->dim > 0);
+ xassert(Y != NULL);
+ xassert(Y->type == A_NONE);
+ xassert(Y->dim > 0);
+ xassert(X->dim == Y->dim);
+ /* Z := X \ Y */
+ Z = create_elemset(mpl, X->dim);
+ for (memb = X->head; memb != NULL; memb = memb->next)
+ { if (find_tuple(mpl, Y, memb->tuple) == NULL)
+ add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+ }
+ /* Z := Z U (Y \ X) */
+ for (memb = Y->head; memb != NULL; memb = memb->next)
+ { if (find_tuple(mpl, X, memb->tuple) == NULL)
+ add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+ }
+ delete_elemset(mpl, X);
+ delete_elemset(mpl, Y);
+ return Z;
+}
+
+/*----------------------------------------------------------------------
+-- set_inter - intersection of two elemental sets.
+--
+-- This routine computes the intersection:
+--
+-- X ^ Y = { j | (j in X) and (j in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_inter
+( MPL *mpl,
+ ELEMSET *X, /* destroyed */
+ ELEMSET *Y /* destroyed */
+)
+{ ELEMSET *Z;
+ MEMBER *memb;
+ xassert(X != NULL);
+ xassert(X->type == A_NONE);
+ xassert(X->dim > 0);
+ xassert(Y != NULL);
+ xassert(Y->type == A_NONE);
+ xassert(Y->dim > 0);
+ xassert(X->dim == Y->dim);
+ Z = create_elemset(mpl, X->dim);
+ for (memb = X->head; memb != NULL; memb = memb->next)
+ { if (find_tuple(mpl, Y, memb->tuple) != NULL)
+ add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+ }
+ delete_elemset(mpl, X);
+ delete_elemset(mpl, Y);
+ return Z;
+}
+
+/*----------------------------------------------------------------------
+-- set_cross - cross (Cartesian) product of two elemental sets.
+--
+-- This routine computes the cross (Cartesian) product:
+--
+-- X x Y = { (i,j) | (i in X) and (j in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_cross
+( MPL *mpl,
+ ELEMSET *X, /* destroyed */
+ ELEMSET *Y /* destroyed */
+)
+{ ELEMSET *Z;
+ MEMBER *memx, *memy;
+ TUPLE *tuple, *temp;
+ xassert(X != NULL);
+ xassert(X->type == A_NONE);
+ xassert(X->dim > 0);
+ xassert(Y != NULL);
+ xassert(Y->type == A_NONE);
+ xassert(Y->dim > 0);
+ Z = create_elemset(mpl, X->dim + Y->dim);
+ for (memx = X->head; memx != NULL; memx = memx->next)
+ { for (memy = Y->head; memy != NULL; memy = memy->next)
+ { tuple = copy_tuple(mpl, memx->tuple);
+ for (temp = memy->tuple; temp != NULL; temp = temp->next)
+ tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
+ temp->sym));
+ add_tuple(mpl, Z, tuple);
+ }
+ }
+ delete_elemset(mpl, X);
+ delete_elemset(mpl, Y);
+ return Z;
+}
+
+/**********************************************************************/
+/* * * ELEMENTAL VARIABLES * * */
+/**********************************************************************/
+
+/* (there are no specific routines for elemental variables) */
+
+/**********************************************************************/
+/* * * LINEAR FORMS * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- constant_term - create constant term.
+--
+-- This routine creates the linear form, which is a constant term. */
+
+FORMULA *constant_term(MPL *mpl, double coef)
+{ FORMULA *form;
+ if (coef == 0.0)
+ form = NULL;
+ else
+ { form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+ form->coef = coef;
+ form->var = NULL;
+ form->next = NULL;
+ }
+ return form;
+}
+
+/*----------------------------------------------------------------------
+-- single_variable - create single variable.
+--
+-- This routine creates the linear form, which is a single elemental
+-- variable. */
+
+FORMULA *single_variable
+( MPL *mpl,
+ ELEMVAR *var /* referenced */
+)
+{ FORMULA *form;
+ xassert(var != NULL);
+ form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+ form->coef = 1.0;
+ form->var = var;
+ form->next = NULL;
+ return form;
+}
+
+/*----------------------------------------------------------------------
+-- copy_formula - make copy of linear form.
+--
+-- This routine returns an exact copy of linear form. */
+
+FORMULA *copy_formula
+( MPL *mpl,
+ FORMULA *form /* not changed */
+)
+{ FORMULA *head, *tail;
+ if (form == NULL)
+ head = NULL;
+ else
+ { head = tail = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+ for (; form != NULL; form = form->next)
+ { tail->coef = form->coef;
+ tail->var = form->var;
+ if (form->next != NULL)
+tail = (tail->next = dmp_get_atom(mpl->formulae, sizeof(FORMULA)));
+ }
+ tail->next = NULL;
+ }
+ return head;
+}
+
+/*----------------------------------------------------------------------
+-- delete_formula - delete linear form.
+--
+-- This routine deletes specified linear form. */
+
+void delete_formula
+( MPL *mpl,
+ FORMULA *form /* destroyed */
+)
+{ FORMULA *temp;
+ while (form != NULL)
+ { temp = form;
+ form = form->next;
+ dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- linear_comb - linear combination of two linear forms.
+--
+-- This routine computes the linear combination:
+--
+-- a * fx + b * fy,
+--
+-- where a and b are numeric coefficients, fx and fy are linear forms
+-- (destroyed on exit). */
+
+FORMULA *linear_comb
+( MPL *mpl,
+ double a, FORMULA *fx, /* destroyed */
+ double b, FORMULA *fy /* destroyed */
+)
+{ FORMULA *form = NULL, *term, *temp;
+ double c0 = 0.0;
+ for (term = fx; term != NULL; term = term->next)
+ { if (term->var == NULL)
+ c0 = fp_add(mpl, c0, fp_mul(mpl, a, term->coef));
+ else
+ term->var->temp =
+ fp_add(mpl, term->var->temp, fp_mul(mpl, a, term->coef));
+ }
+ for (term = fy; term != NULL; term = term->next)
+ { if (term->var == NULL)
+ c0 = fp_add(mpl, c0, fp_mul(mpl, b, term->coef));
+ else
+ term->var->temp =
+ fp_add(mpl, term->var->temp, fp_mul(mpl, b, term->coef));
+ }
+ for (term = fx; term != NULL; term = term->next)
+ { if (term->var != NULL && term->var->temp != 0.0)
+ { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+ temp->coef = term->var->temp, temp->var = term->var;
+ temp->next = form, form = temp;
+ term->var->temp = 0.0;
+ }
+ }
+ for (term = fy; term != NULL; term = term->next)
+ { if (term->var != NULL && term->var->temp != 0.0)
+ { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+ temp->coef = term->var->temp, temp->var = term->var;
+ temp->next = form, form = temp;
+ term->var->temp = 0.0;
+ }
+ }
+ if (c0 != 0.0)
+ { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+ temp->coef = c0, temp->var = NULL;
+ temp->next = form, form = temp;
+ }
+ delete_formula(mpl, fx);
+ delete_formula(mpl, fy);
+ return form;
+}
+
+/*----------------------------------------------------------------------
+-- remove_constant - remove constant term from linear form.
+--
+-- This routine removes constant term from linear form and stores its
+-- value to given location. */
+
+FORMULA *remove_constant
+( MPL *mpl,
+ FORMULA *form, /* destroyed */
+ double *coef /* modified */
+)
+{ FORMULA *head = NULL, *temp;
+ *coef = 0.0;
+ while (form != NULL)
+ { temp = form;
+ form = form->next;
+ if (temp->var == NULL)
+ { /* constant term */
+ *coef = fp_add(mpl, *coef, temp->coef);
+ dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
+ }
+ else
+ { /* linear term */
+ temp->next = head;
+ head = temp;
+ }
+ }
+ return head;
+}
+
+/*----------------------------------------------------------------------
+-- reduce_terms - reduce identical terms in linear form.
+--
+-- This routine reduces identical terms in specified linear form. */
+
+FORMULA *reduce_terms
+( MPL *mpl,
+ FORMULA *form /* destroyed */
+)
+{ FORMULA *term, *next_term;
+ double c0 = 0.0;
+ for (term = form; term != NULL; term = term->next)
+ { if (term->var == NULL)
+ c0 = fp_add(mpl, c0, term->coef);
+ else
+ term->var->temp = fp_add(mpl, term->var->temp, term->coef);
+ }
+ next_term = form, form = NULL;
+ for (term = next_term; term != NULL; term = next_term)
+ { next_term = term->next;
+ if (term->var == NULL && c0 != 0.0)
+ { term->coef = c0, c0 = 0.0;
+ term->next = form, form = term;
+ }
+ else if (term->var != NULL && term->var->temp != 0.0)
+ { term->coef = term->var->temp, term->var->temp = 0.0;
+ term->next = form, form = term;
+ }
+ else
+ dmp_free_atom(mpl->formulae, term, sizeof(FORMULA));
+ }
+ return form;
+}
+
+/**********************************************************************/
+/* * * ELEMENTAL CONSTRAINTS * * */
+/**********************************************************************/
+
+/* (there are no specific routines for elemental constraints) */
+
+/**********************************************************************/
+/* * * GENERIC VALUES * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- delete_value - delete generic value.
+--
+-- This routine deletes specified generic value.
+--
+-- NOTE: The generic value to be deleted must be valid. */
+
+void delete_value
+( MPL *mpl,
+ int type,
+ VALUE *value /* content destroyed */
+)
+{ xassert(value != NULL);
+ switch (type)
+ { case A_NONE:
+ value->none = NULL;
+ break;
+ case A_NUMERIC:
+ value->num = 0.0;
+ break;
+ case A_SYMBOLIC:
+ delete_symbol(mpl, value->sym), value->sym = NULL;
+ break;
+ case A_LOGICAL:
+ value->bit = 0;
+ break;
+ case A_TUPLE:
+ delete_tuple(mpl, value->tuple), value->tuple = NULL;
+ break;
+ case A_ELEMSET:
+ delete_elemset(mpl, value->set), value->set = NULL;
+ break;
+ case A_ELEMVAR:
+ value->var = NULL;
+ break;
+ case A_FORMULA:
+ delete_formula(mpl, value->form), value->form = NULL;
+ break;
+ case A_ELEMCON:
+ value->con = NULL;
+ break;
+ default:
+ xassert(type != type);
+ }
+ return;
+}
+
+/**********************************************************************/
+/* * * SYMBOLICALLY INDEXED ARRAYS * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_array - create array.
+--
+-- This routine creates an array of specified type and dimension. Being
+-- created the array is initially empty.
+--
+-- The type indicator determines generic values, which can be assigned
+-- to the array members:
+--
+-- A_NONE - none (members have no assigned values)
+-- A_NUMERIC - floating-point numbers
+-- A_SYMBOLIC - symbols
+-- A_ELEMSET - elemental sets
+-- A_ELEMVAR - elemental variables
+-- A_ELEMCON - elemental constraints
+--
+-- The dimension may be 0, in which case the array consists of the only
+-- member (such arrays represent 0-dimensional objects). */
+
+ARRAY *create_array(MPL *mpl, int type, int dim)
+{ ARRAY *array;
+ xassert(type == A_NONE || type == A_NUMERIC ||
+ type == A_SYMBOLIC || type == A_ELEMSET ||
+ type == A_ELEMVAR || type == A_ELEMCON);
+ xassert(dim >= 0);
+ array = dmp_get_atom(mpl->arrays, sizeof(ARRAY));
+ array->type = type;
+ array->dim = dim;
+ array->size = 0;
+ array->head = NULL;
+ array->tail = NULL;
+ array->tree = NULL;
+ array->prev = NULL;
+ array->next = mpl->a_list;
+ /* include the array in the global array list */
+ if (array->next != NULL) array->next->prev = array;
+ mpl->a_list = array;
+ return array;
+}
+
+/*----------------------------------------------------------------------
+-- find_member - find array member with given n-tuple.
+--
+-- This routine finds an array member, which has given n-tuple. If the
+-- array is short, the linear search is used. Otherwise the routine
+-- autimatically creates the search tree (i.e. the array index) to find
+-- members for logarithmic time. */
+
+static int compare_member_tuples(void *info, const void *key1,
+ const void *key2)
+{ /* this is an auxiliary routine used to compare keys, which are
+ n-tuples assigned to array members */
+ return compare_tuples((MPL *)info, (TUPLE *)key1, (TUPLE *)key2);
+}
+
+MEMBER *find_member
+( MPL *mpl,
+ ARRAY *array, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ MEMBER *memb;
+ xassert(array != NULL);
+ /* the n-tuple must have the same dimension as the array */
+ xassert(tuple_dimen(mpl, tuple) == array->dim);
+ /* if the array is large enough, create the search tree and index
+ all existing members of the array */
+ if (array->size > 30 && array->tree == NULL)
+ { array->tree = avl_create_tree(compare_member_tuples, mpl);
+ for (memb = array->head; memb != NULL; memb = memb->next)
+avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
+ (void *)memb);
+ }
+ /* find a member, which has the given tuple */
+ if (array->tree == NULL)
+ { /* the search tree doesn't exist; use the linear search */
+ for (memb = array->head; memb != NULL; memb = memb->next)
+ if (compare_tuples(mpl, memb->tuple, tuple) == 0) break;
+ }
+ else
+ { /* the search tree exists; use the binary search */
+ AVLNODE *node;
+ node = avl_find_node(array->tree, tuple);
+memb = (MEMBER *)(node == NULL ? NULL : avl_get_node_link(node));
+ }
+ return memb;
+}
+
+/*----------------------------------------------------------------------
+-- add_member - add new member to array.
+--
+-- This routine creates a new member with given n-tuple and adds it to
+-- specified array.
+--
+-- For the sake of efficiency this routine doesn't check whether the
+-- array already contains a member with the given n-tuple or not. Thus,
+-- if necessary, the calling program should use the routine find_member
+-- in order to be sure that the array contains no member with the same
+-- n-tuple, because members with duplicate n-tuples are not allowed.
+--
+-- This routine assigns no generic value to the new member, because the
+-- calling program must do that. */
+
+MEMBER *add_member
+( MPL *mpl,
+ ARRAY *array, /* modified */
+ TUPLE *tuple /* destroyed */
+)
+{ MEMBER *memb;
+ xassert(array != NULL);
+ /* the n-tuple must have the same dimension as the array */
+ xassert(tuple_dimen(mpl, tuple) == array->dim);
+ /* create new member */
+ memb = dmp_get_atom(mpl->members, sizeof(MEMBER));
+ memb->tuple = tuple;
+ memb->next = NULL;
+ memset(&memb->value, '?', sizeof(VALUE));
+ /* and append it to the member list */
+ array->size++;
+ if (array->head == NULL)
+ array->head = memb;
+ else
+ array->tail->next = memb;
+ array->tail = memb;
+ /* if the search tree exists, index the new member */
+ if (array->tree != NULL)
+avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
+ (void *)memb);
+ return memb;
+}
+
+/*----------------------------------------------------------------------
+-- delete_array - delete array.
+--
+-- This routine deletes specified array.
+--
+-- Generic values assigned to the array members are not deleted by this
+-- routine. The calling program itself must delete all assigned generic
+-- values before deleting the array. */
+
+void delete_array
+( MPL *mpl,
+ ARRAY *array /* destroyed */
+)
+{ MEMBER *memb;
+ xassert(array != NULL);
+ /* delete all existing array members */
+ while (array->head != NULL)
+ { memb = array->head;
+ array->head = memb->next;
+ delete_tuple(mpl, memb->tuple);
+ dmp_free_atom(mpl->members, memb, sizeof(MEMBER));
+ }
+ /* if the search tree exists, also delete it */
+ if (array->tree != NULL) avl_delete_tree(array->tree);
+ /* remove the array from the global array list */
+ if (array->prev == NULL)
+ mpl->a_list = array->next;
+ else
+ array->prev->next = array->next;
+ if (array->next == NULL)
+ ;
+ else
+ array->next->prev = array->prev;
+ /* delete the array descriptor */
+ dmp_free_atom(mpl->arrays, array, sizeof(ARRAY));
+ return;
+}
+
+/**********************************************************************/
+/* * * DOMAINS AND DUMMY INDICES * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- assign_dummy_index - assign new value to dummy index.
+--
+-- This routine assigns new value to specified dummy index and, that is
+-- important, invalidates all temporary resultant values, which depends
+-- on that dummy index. */
+
+void assign_dummy_index
+( MPL *mpl,
+ DOMAIN_SLOT *slot, /* modified */
+ SYMBOL *value /* not changed */
+)
+{ CODE *leaf, *code;
+ xassert(slot != NULL);
+ xassert(value != NULL);
+ /* delete the current value assigned to the dummy index */
+ if (slot->value != NULL)
+ { /* if the current value and the new one are identical, actual
+ assignment is not needed */
+ if (compare_symbols(mpl, slot->value, value) == 0) goto done;
+ /* delete a symbol, which is the current value */
+ delete_symbol(mpl, slot->value), slot->value = NULL;
+ }
+ /* now walk through all the pseudo-codes with op = O_INDEX, which
+ refer to the dummy index to be changed (these pseudo-codes are
+ leaves in the forest of *all* expressions in the database) */
+ for (leaf = slot->list; leaf != NULL; leaf = leaf->arg.index.
+ next)
+ { xassert(leaf->op == O_INDEX);
+ /* invalidate all resultant values, which depend on the dummy
+ index, walking from the current leaf toward the root of the
+ corresponding expression tree */
+ for (code = leaf; code != NULL; code = code->up)
+ { if (code->valid)
+ { /* invalidate and delete resultant value */
+ code->valid = 0;
+ delete_value(mpl, code->type, &code->value);
+ }
+ }
+ }
+ /* assign new value to the dummy index */
+ slot->value = copy_symbol(mpl, value);
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- update_dummy_indices - update current values of dummy indices.
+--
+-- This routine assigns components of "backup" n-tuple to dummy indices
+-- of specified domain block. If no "backup" n-tuple is defined for the
+-- domain block, values of the dummy indices remain untouched. */
+
+void update_dummy_indices
+( MPL *mpl,
+ DOMAIN_BLOCK *block /* not changed */
+)
+{ DOMAIN_SLOT *slot;
+ TUPLE *temp;
+ if (block->backup != NULL)
+ { for (slot = block->list, temp = block->backup; slot != NULL;
+ slot = slot->next, temp = temp->next)
+ { xassert(temp != NULL);
+ xassert(temp->sym != NULL);
+ assign_dummy_index(mpl, slot, temp->sym);
+ }
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- enter_domain_block - enter domain block.
+--
+-- Let specified domain block have the form:
+--
+-- { ..., (j1, j2, ..., jn) in J, ... }
+--
+-- where j1, j2, ..., jn are dummy indices, J is a basic set.
+--
+-- This routine does the following:
+--
+-- 1. Checks if the given n-tuple is a member of the basic set J. Note
+-- that J being *out of the scope* of the domain block cannot depend
+-- on the dummy indices in the same and inner domain blocks, so it
+-- can be computed before the dummy indices are assigned new values.
+-- If this check fails, the routine returns with non-zero code.
+--
+-- 2. Saves current values of the dummy indices j1, j2, ..., jn.
+--
+-- 3. Assigns new values, which are components of the given n-tuple, to
+-- the dummy indices j1, j2, ..., jn. If dimension of the n-tuple is
+-- larger than n, its extra components n+1, n+2, ... are not used.
+--
+-- 4. Calls the formal routine func which either enters the next domain
+-- block or evaluates some code within the domain scope.
+--
+-- 5. Restores former values of the dummy indices j1, j2, ..., jn.
+--
+-- Since current values assigned to the dummy indices on entry to this
+-- routine are restored on exit, the formal routine func is allowed to
+-- call this routine recursively. */
+
+int enter_domain_block
+( MPL *mpl,
+ DOMAIN_BLOCK *block, /* not changed */
+ TUPLE *tuple, /* not changed */
+ void *info, void (*func)(MPL *mpl, void *info)
+)
+{ TUPLE *backup;
+ int ret = 0;
+ /* check if the given n-tuple is a member of the basic set */
+ xassert(block->code != NULL);
+ if (!is_member(mpl, block->code, tuple))
+ { ret = 1;
+ goto done;
+ }
+ /* save reference to "backup" n-tuple, which was used to assign
+ current values of the dummy indices (it is sufficient to save
+ reference, not value, because that n-tuple is defined in some
+ outer level of recursion and therefore cannot be changed on
+ this and deeper recursive calls) */
+ backup = block->backup;
+ /* set up new "backup" n-tuple, which defines new values of the
+ dummy indices */
+ block->backup = tuple;
+ /* assign new values to the dummy indices */
+ update_dummy_indices(mpl, block);
+ /* call the formal routine that does the rest part of the job */
+ func(mpl, info);
+ /* restore reference to the former "backup" n-tuple */
+ block->backup = backup;
+ /* restore former values of the dummy indices; note that if the
+ domain block just escaped has no other active instances which
+ may exist due to recursion (it is indicated by a null pointer
+ to the former n-tuple), former values of the dummy indices are
+ undefined; therefore in this case the routine keeps currently
+ assigned values of the dummy indices that involves keeping all
+ dependent temporary results and thereby, if this domain block
+ is not used recursively, allows improving efficiency */
+ update_dummy_indices(mpl, block);
+done: return ret;
+}
+
+/*----------------------------------------------------------------------
+-- eval_within_domain - perform evaluation within domain scope.
+--
+-- This routine assigns new values (symbols) to all dummy indices of
+-- specified domain and calls the formal routine func, which is used to
+-- evaluate some code in the domain scope. Each free dummy index in the
+-- domain is assigned a value specified in the corresponding component
+-- of given n-tuple. Non-free dummy indices are assigned values, which
+-- are computed by this routine.
+--
+-- Number of components in the given n-tuple must be the same as number
+-- of free indices in the domain.
+--
+-- If the given n-tuple is not a member of the domain set, the routine
+-- func is not called, and non-zero code is returned.
+--
+-- For the sake of convenience it is allowed to specify domain as NULL
+-- (then n-tuple also must be 0-tuple, i.e. empty), in which case this
+-- routine just calls the routine func and returns zero.
+--
+-- This routine allows recursive calls from the routine func providing
+-- correct values of dummy indices for each instance.
+--
+-- NOTE: The n-tuple passed to this routine must not be changed by any
+-- other routines called from the formal routine func until this
+-- routine has returned. */
+
+struct eval_domain_info
+{ /* working info used by the routine eval_within_domain */
+ DOMAIN *domain;
+ /* domain, which has to be entered */
+ DOMAIN_BLOCK *block;
+ /* domain block, which is currently processed */
+ TUPLE *tuple;
+ /* tail of original n-tuple, whose components have to be assigned
+ to free dummy indices in the current domain block */
+ void *info;
+ /* transit pointer passed to the formal routine func */
+ void (*func)(MPL *mpl, void *info);
+ /* routine, which has to be executed in the domain scope */
+ int failure;
+ /* this flag indicates that given n-tuple is not a member of the
+ domain set */
+};
+
+static void eval_domain_func(MPL *mpl, void *_my_info)
+{ /* this routine recursively enters into the domain scope and then
+ calls the routine func */
+ struct eval_domain_info *my_info = _my_info;
+ if (my_info->block != NULL)
+ { /* the current domain block to be entered exists */
+ DOMAIN_BLOCK *block;
+ DOMAIN_SLOT *slot;
+ TUPLE *tuple = NULL, *temp = NULL;
+ /* save pointer to the current domain block */
+ block = my_info->block;
+ /* and get ready to enter the next block (if it exists) */
+ my_info->block = block->next;
+ /* construct temporary n-tuple, whose components correspond to
+ dummy indices (slots) of the current domain; components of
+ the temporary n-tuple that correspond to free dummy indices
+ are assigned references (not values!) to symbols specified
+ in the corresponding components of the given n-tuple, while
+ other components that correspond to non-free dummy indices
+ are assigned symbolic values computed here */
+ for (slot = block->list; slot != NULL; slot = slot->next)
+ { /* create component that corresponds to the current slot */
+ if (tuple == NULL)
+ tuple = temp = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
+ else
+temp = (temp->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
+ if (slot->code == NULL)
+ { /* dummy index is free; take reference to symbol, which
+ is specified in the corresponding component of given
+ n-tuple */
+ xassert(my_info->tuple != NULL);
+ temp->sym = my_info->tuple->sym;
+ xassert(temp->sym != NULL);
+ my_info->tuple = my_info->tuple->next;
+ }
+ else
+ { /* dummy index is non-free; compute symbolic value to be
+ temporarily assigned to the dummy index */
+ temp->sym = eval_symbolic(mpl, slot->code);
+ }
+ }
+ temp->next = NULL;
+ /* enter the current domain block */
+ if (enter_domain_block(mpl, block, tuple, my_info,
+ eval_domain_func)) my_info->failure = 1;
+ /* delete temporary n-tuple as well as symbols that correspond
+ to non-free dummy indices (they were computed here) */
+ for (slot = block->list; slot != NULL; slot = slot->next)
+ { xassert(tuple != NULL);
+ temp = tuple;
+ tuple = tuple->next;
+ if (slot->code != NULL)
+ { /* dummy index is non-free; delete symbolic value */
+ delete_symbol(mpl, temp->sym);
+ }
+ /* delete component that corresponds to the current slot */
+ dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
+ }
+ }
+ else
+ { /* there are no more domain blocks, i.e. we have reached the
+ domain scope */
+ xassert(my_info->tuple == NULL);
+ /* check optional predicate specified for the domain */
+ if (my_info->domain->code != NULL && !eval_logical(mpl,
+ my_info->domain->code))
+ { /* the predicate is false */
+ my_info->failure = 2;
+ }
+ else
+ { /* the predicate is true; do the job */
+ my_info->func(mpl, my_info->info);
+ }
+ }
+ return;
+}
+
+int eval_within_domain
+( MPL *mpl,
+ DOMAIN *domain, /* not changed */
+ TUPLE *tuple, /* not changed */
+ void *info, void (*func)(MPL *mpl, void *info)
+)
+{ /* this routine performs evaluation within domain scope */
+ struct eval_domain_info _my_info, *my_info = &_my_info;
+ if (domain == NULL)
+ { xassert(tuple == NULL);
+ func(mpl, info);
+ my_info->failure = 0;
+ }
+ else
+ { xassert(tuple != NULL);
+ my_info->domain = domain;
+ my_info->block = domain->list;
+ my_info->tuple = tuple;
+ my_info->info = info;
+ my_info->func = func;
+ my_info->failure = 0;
+ /* enter the very first domain block */
+ eval_domain_func(mpl, my_info);
+ }
+ return my_info->failure;
+}
+
+/*----------------------------------------------------------------------
+-- loop_within_domain - perform iterations within domain scope.
+--
+-- This routine iteratively assigns new values (symbols) to the dummy
+-- indices of specified domain by enumerating all n-tuples, which are
+-- members of the domain set, and for every n-tuple it calls the formal
+-- routine func to evaluate some code within the domain scope.
+--
+-- If the routine func returns non-zero, enumeration within the domain
+-- is prematurely terminated.
+--
+-- For the sake of convenience it is allowed to specify domain as NULL,
+-- in which case this routine just calls the routine func only once and
+-- returns zero.
+--
+-- This routine allows recursive calls from the routine func providing
+-- correct values of dummy indices for each instance. */
+
+struct loop_domain_info
+{ /* working info used by the routine loop_within_domain */
+ DOMAIN *domain;
+ /* domain, which has to be entered */
+ DOMAIN_BLOCK *block;
+ /* domain block, which is currently processed */
+ int looping;
+ /* clearing this flag leads to terminating enumeration */
+ void *info;
+ /* transit pointer passed to the formal routine func */
+ int (*func)(MPL *mpl, void *info);
+ /* routine, which needs to be executed in the domain scope */
+};
+
+static void loop_domain_func(MPL *mpl, void *_my_info)
+{ /* this routine enumerates all n-tuples in the basic set of the
+ current domain block, enters recursively into the domain scope
+ for every n-tuple, and then calls the routine func */
+ struct loop_domain_info *my_info = _my_info;
+ if (my_info->block != NULL)
+ { /* the current domain block to be entered exists */
+ DOMAIN_BLOCK *block;
+ DOMAIN_SLOT *slot;
+ TUPLE *bound;
+ /* save pointer to the current domain block */
+ block = my_info->block;
+ /* and get ready to enter the next block (if it exists) */
+ my_info->block = block->next;
+ /* compute symbolic values, at which non-free dummy indices of
+ the current domain block are bound; since that values don't
+ depend on free dummy indices of the current block, they can
+ be computed once out of the enumeration loop */
+ bound = create_tuple(mpl);
+ for (slot = block->list; slot != NULL; slot = slot->next)
+ { if (slot->code != NULL)
+ bound = expand_tuple(mpl, bound, eval_symbolic(mpl,
+ slot->code));
+ }
+ /* start enumeration */
+ xassert(block->code != NULL);
+ if (block->code->op == O_DOTS)
+ { /* the basic set is "arithmetic", in which case it doesn't
+ need to be computed explicitly */
+ TUPLE *tuple;
+ int n, j;
+ double t0, tf, dt;
+ /* compute "parameters" of the basic set */
+ t0 = eval_numeric(mpl, block->code->arg.arg.x);
+ tf = eval_numeric(mpl, block->code->arg.arg.y);
+ if (block->code->arg.arg.z == NULL)
+ dt = 1.0;
+ else
+ dt = eval_numeric(mpl, block->code->arg.arg.z);
+ /* determine cardinality of the basic set */
+ n = arelset_size(mpl, t0, tf, dt);
+ /* create dummy 1-tuple for members of the basic set */
+ tuple = expand_tuple(mpl, create_tuple(mpl),
+ create_symbol_num(mpl, 0.0));
+ /* in case of "arithmetic" set there is exactly one dummy
+ index, which cannot be non-free */
+ xassert(bound == NULL);
+ /* walk through 1-tuples of the basic set */
+ for (j = 1; j <= n && my_info->looping; j++)
+ { /* construct dummy 1-tuple for the current member */
+ tuple->sym->num = arelset_member(mpl, t0, tf, dt, j);
+ /* enter the current domain block */
+ enter_domain_block(mpl, block, tuple, my_info,
+ loop_domain_func);
+ }
+ /* delete dummy 1-tuple */
+ delete_tuple(mpl, tuple);
+ }
+ else
+ { /* the basic set is of general kind, in which case it needs
+ to be explicitly computed */
+ ELEMSET *set;
+ MEMBER *memb;
+ TUPLE *temp1, *temp2;
+ /* compute the basic set */
+ set = eval_elemset(mpl, block->code);
+ /* walk through all n-tuples of the basic set */
+ for (memb = set->head; memb != NULL && my_info->looping;
+ memb = memb->next)
+ { /* all components of the current n-tuple that correspond
+ to non-free dummy indices must be feasible; otherwise
+ the n-tuple is not in the basic set */
+ temp1 = memb->tuple;
+ temp2 = bound;
+ for (slot = block->list; slot != NULL; slot = slot->next)
+ { xassert(temp1 != NULL);
+ if (slot->code != NULL)
+ { /* non-free dummy index */
+ xassert(temp2 != NULL);
+ if (compare_symbols(mpl, temp1->sym, temp2->sym)
+ != 0)
+ { /* the n-tuple is not in the basic set */
+ goto skip;
+ }
+ temp2 = temp2->next;
+ }
+ temp1 = temp1->next;
+ }
+ xassert(temp1 == NULL);
+ xassert(temp2 == NULL);
+ /* enter the current domain block */
+ enter_domain_block(mpl, block, memb->tuple, my_info,
+ loop_domain_func);
+skip: ;
+ }
+ /* delete the basic set */
+ delete_elemset(mpl, set);
+ }
+ /* delete symbolic values binding non-free dummy indices */
+ delete_tuple(mpl, bound);
+ /* restore pointer to the current domain block */
+ my_info->block = block;
+ }
+ else
+ { /* there are no more domain blocks, i.e. we have reached the
+ domain scope */
+ /* check optional predicate specified for the domain */
+ if (my_info->domain->code != NULL && !eval_logical(mpl,
+ my_info->domain->code))
+ { /* the predicate is false */
+ /* nop */;
+ }
+ else
+ { /* the predicate is true; do the job */
+ my_info->looping = !my_info->func(mpl, my_info->info);
+ }
+ }
+ return;
+}
+
+void loop_within_domain
+( MPL *mpl,
+ DOMAIN *domain, /* not changed */
+ void *info, int (*func)(MPL *mpl, void *info)
+)
+{ /* this routine performs iterations within domain scope */
+ struct loop_domain_info _my_info, *my_info = &_my_info;
+ if (domain == NULL)
+ func(mpl, info);
+ else
+ { my_info->domain = domain;
+ my_info->block = domain->list;
+ my_info->looping = 1;
+ my_info->info = info;
+ my_info->func = func;
+ /* enter the very first domain block */
+ loop_domain_func(mpl, my_info);
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- out_of_domain - raise domain exception.
+--
+-- This routine is called when a reference is made to a member of some
+-- model object, but its n-tuple is out of the object domain. */
+
+void out_of_domain
+( MPL *mpl,
+ char *name, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ xassert(name != NULL);
+ xassert(tuple != NULL);
+ error(mpl, "%s%s out of domain", name, format_tuple(mpl, '[',
+ tuple));
+ /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- get_domain_tuple - obtain current n-tuple from domain.
+--
+-- This routine constructs n-tuple, whose components are current values
+-- assigned to *free* dummy indices of specified domain.
+--
+-- For the sake of convenience it is allowed to specify domain as NULL,
+-- in which case this routine returns 0-tuple.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+TUPLE *get_domain_tuple
+( MPL *mpl,
+ DOMAIN *domain /* not changed */
+)
+{ DOMAIN_BLOCK *block;
+ DOMAIN_SLOT *slot;
+ TUPLE *tuple;
+ tuple = create_tuple(mpl);
+ if (domain != NULL)
+ { for (block = domain->list; block != NULL; block = block->next)
+ { for (slot = block->list; slot != NULL; slot = slot->next)
+ { if (slot->code == NULL)
+ { xassert(slot->value != NULL);
+ tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
+ slot->value));
+ }
+ }
+ }
+ }
+ return tuple;
+}
+
+/*----------------------------------------------------------------------
+-- clean_domain - clean domain.
+--
+-- This routine cleans specified domain that assumes deleting all stuff
+-- dynamically allocated during the generation phase. */
+
+void clean_domain(MPL *mpl, DOMAIN *domain)
+{ DOMAIN_BLOCK *block;
+ DOMAIN_SLOT *slot;
+ /* if no domain is specified, do nothing */
+ if (domain == NULL) goto done;
+ /* clean all domain blocks */
+ for (block = domain->list; block != NULL; block = block->next)
+ { /* clean all domain slots */
+ for (slot = block->list; slot != NULL; slot = slot->next)
+ { /* clean pseudo-code for computing bound value */
+ clean_code(mpl, slot->code);
+ /* delete symbolic value assigned to dummy index */
+ if (slot->value != NULL)
+ delete_symbol(mpl, slot->value), slot->value = NULL;
+ }
+ /* clean pseudo-code for computing basic set */
+ clean_code(mpl, block->code);
+ }
+ /* clean pseudo-code for computing domain predicate */
+ clean_code(mpl, domain->code);
+done: return;
+}
+
+/**********************************************************************/
+/* * * MODEL SETS * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- check_elem_set - check elemental set assigned to set member.
+--
+-- This routine checks if given elemental set being assigned to member
+-- of specified model set satisfies to all restrictions.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+void check_elem_set
+( MPL *mpl,
+ SET *set, /* not changed */
+ TUPLE *tuple, /* not changed */
+ ELEMSET *refer /* not changed */
+)
+{ WITHIN *within;
+ MEMBER *memb;
+ int eqno;
+ /* elemental set must be within all specified supersets */
+ for (within = set->within, eqno = 1; within != NULL; within =
+ within->next, eqno++)
+ { xassert(within->code != NULL);
+ for (memb = refer->head; memb != NULL; memb = memb->next)
+ { if (!is_member(mpl, within->code, memb->tuple))
+ { char buf[255+1];
+ strcpy(buf, format_tuple(mpl, '(', memb->tuple));
+ xassert(strlen(buf) < sizeof(buf));
+ error(mpl, "%s%s contains %s which not within specified "
+ "set; see (%d)", set->name, format_tuple(mpl, '[',
+ tuple), buf, eqno);
+ }
+ }
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- take_member_set - obtain elemental set assigned to set member.
+--
+-- This routine obtains a reference to elemental set assigned to given
+-- member of specified model set and returns it on exit.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+ELEMSET *take_member_set /* returns reference, not value */
+( MPL *mpl,
+ SET *set, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ MEMBER *memb;
+ ELEMSET *refer;
+ /* find member in the set array */
+ memb = find_member(mpl, set->array, tuple);
+ if (memb != NULL)
+ { /* member exists, so just take the reference */
+ refer = memb->value.set;
+ }
+ else if (set->assign != NULL)
+ { /* compute value using assignment expression */
+ refer = eval_elemset(mpl, set->assign);
+add: /* check that the elemental set satisfies to all restrictions,
+ assign it to new member, and add the member to the array */
+ check_elem_set(mpl, set, tuple, refer);
+ memb = add_member(mpl, set->array, copy_tuple(mpl, tuple));
+ memb->value.set = refer;
+ }
+ else if (set->option != NULL)
+ { /* compute default elemental set */
+ refer = eval_elemset(mpl, set->option);
+ goto add;
+ }
+ else
+ { /* no value (elemental set) is provided */
+ error(mpl, "no value for %s%s", set->name, format_tuple(mpl,
+ '[', tuple));
+ }
+ return refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_set - evaluate elemental set assigned to set member.
+--
+-- This routine evaluates a reference to elemental set assigned to given
+-- member of specified model set and returns it on exit. */
+
+struct eval_set_info
+{ /* working info used by the routine eval_member_set */
+ SET *set;
+ /* model set */
+ TUPLE *tuple;
+ /* n-tuple, which defines set member */
+ MEMBER *memb;
+ /* normally this pointer is NULL; the routine uses this pointer
+ to check data provided in the data section, in which case it
+ points to a member currently checked; this check is performed
+ automatically only once when a reference to any member occurs
+ for the first time */
+ ELEMSET *refer;
+ /* evaluated reference to elemental set */
+};
+
+static void eval_set_func(MPL *mpl, void *_info)
+{ /* this is auxiliary routine to work within domain scope */
+ struct eval_set_info *info = _info;
+ if (info->memb != NULL)
+ { /* checking call; check elemental set being assigned */
+ check_elem_set(mpl, info->set, info->memb->tuple,
+ info->memb->value.set);
+ }
+ else
+ { /* normal call; evaluate member, which has given n-tuple */
+ info->refer = take_member_set(mpl, info->set, info->tuple);
+ }
+ return;
+}
+
+#if 1 /* 12/XII-2008 */
+static void saturate_set(MPL *mpl, SET *set)
+{ GADGET *gadget = set->gadget;
+ ELEMSET *data;
+ MEMBER *elem, *memb;
+ TUPLE *tuple, *work[20];
+ int i;
+ xprintf("Generating %s...\n", set->name);
+ eval_whole_set(mpl, gadget->set);
+ /* gadget set must have exactly one member */
+ xassert(gadget->set->array != NULL);
+ xassert(gadget->set->array->head != NULL);
+ xassert(gadget->set->array->head == gadget->set->array->tail);
+ data = gadget->set->array->head->value.set;
+ xassert(data->type == A_NONE);
+ xassert(data->dim == gadget->set->dimen);
+ /* walk thru all elements of the plain set */
+ for (elem = data->head; elem != NULL; elem = elem->next)
+ { /* create a copy of n-tuple */
+ tuple = copy_tuple(mpl, elem->tuple);
+ /* rearrange component of the n-tuple */
+ for (i = 0; i < gadget->set->dimen; i++)
+ work[i] = NULL;
+ for (i = 0; tuple != NULL; tuple = tuple->next)
+ work[gadget->ind[i++]-1] = tuple;
+ xassert(i == gadget->set->dimen);
+ for (i = 0; i < gadget->set->dimen; i++)
+ { xassert(work[i] != NULL);
+ work[i]->next = work[i+1];
+ }
+ /* construct subscript list from first set->dim components */
+ if (set->dim == 0)
+ tuple = NULL;
+ else
+ tuple = work[0], work[set->dim-1]->next = NULL;
+ /* find corresponding member of the set to be initialized */
+ memb = find_member(mpl, set->array, tuple);
+ if (memb == NULL)
+ { /* not found; 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);
+ }
+ else
+ { /* found; free subscript list */
+ delete_tuple(mpl, tuple);
+ }
+ /* construct new n-tuple from rest set->dimen components */
+ tuple = work[set->dim];
+ xassert(set->dim + set->dimen == gadget->set->dimen);
+ work[gadget->set->dimen-1]->next = NULL;
+ /* and add it to the elemental set assigned to the member
+ (no check for duplicates is needed) */
+ add_tuple(mpl, memb->value.set, tuple);
+ }
+ /* the set has been saturated with data */
+ set->data = 1;
+ return;
+}
+#endif
+
+ELEMSET *eval_member_set /* returns reference, not value */
+( MPL *mpl,
+ SET *set, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ /* this routine evaluates set member */
+ struct eval_set_info _info, *info = &_info;
+ xassert(set->dim == tuple_dimen(mpl, tuple));
+ info->set = set;
+ info->tuple = tuple;
+#if 1 /* 12/XII-2008 */
+ if (set->gadget != NULL && set->data == 0)
+ { /* initialize the set with data from a plain set */
+ saturate_set(mpl, set);
+ }
+#endif
+ if (set->data == 1)
+ { /* check data, which are provided in the data section, but not
+ checked yet */
+ /* save pointer to the last array member; note that during the
+ check new members may be added beyond the last member due to
+ references to the same parameter from default expression as
+ well as from expressions that define restricting supersets;
+ however, values assigned to the new members will be checked
+ by other routine, so we don't need to check them here */
+ MEMBER *tail = set->array->tail;
+ /* change the data status to prevent infinite recursive loop
+ due to references to the same set during the check */
+ set->data = 2;
+ /* check elemental sets assigned to array members in the data
+ section until the marked member has been reached */
+ for (info->memb = set->array->head; info->memb != NULL;
+ info->memb = info->memb->next)
+ { if (eval_within_domain(mpl, set->domain, info->memb->tuple,
+ info, eval_set_func))
+ out_of_domain(mpl, set->name, info->memb->tuple);
+ if (info->memb == tail) break;
+ }
+ /* the check has been finished */
+ }
+ /* evaluate member, which has given n-tuple */
+ info->memb = NULL;
+ if (eval_within_domain(mpl, info->set->domain, info->tuple, info,
+ eval_set_func))
+ out_of_domain(mpl, set->name, info->tuple);
+ /* bring evaluated reference to the calling program */
+ return info->refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_set - evaluate model set over entire domain.
+--
+-- This routine evaluates all members of specified model set over entire
+-- domain. */
+
+static int whole_set_func(MPL *mpl, void *info)
+{ /* this is auxiliary routine to work within domain scope */
+ SET *set = (SET *)info;
+ TUPLE *tuple = get_domain_tuple(mpl, set->domain);
+ eval_member_set(mpl, set, tuple);
+ delete_tuple(mpl, tuple);
+ return 0;
+}
+
+void eval_whole_set(MPL *mpl, SET *set)
+{ loop_within_domain(mpl, set->domain, set, whole_set_func);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- clean set - clean model set.
+--
+-- This routine cleans specified model set that assumes deleting all
+-- stuff dynamically allocated during the generation phase. */
+
+void clean_set(MPL *mpl, SET *set)
+{ WITHIN *within;
+ MEMBER *memb;
+ /* clean subscript domain */
+ clean_domain(mpl, set->domain);
+ /* clean pseudo-code for computing supersets */
+ for (within = set->within; within != NULL; within = within->next)
+ clean_code(mpl, within->code);
+ /* clean pseudo-code for computing assigned value */
+ clean_code(mpl, set->assign);
+ /* clean pseudo-code for computing default value */
+ clean_code(mpl, set->option);
+ /* reset data status flag */
+ set->data = 0;
+ /* delete content array */
+ for (memb = set->array->head; memb != NULL; memb = memb->next)
+ delete_value(mpl, set->array->type, &memb->value);
+ delete_array(mpl, set->array), set->array = NULL;
+ return;
+}
+
+/**********************************************************************/
+/* * * MODEL PARAMETERS * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- check_value_num - check numeric value assigned to parameter member.
+--
+-- This routine checks if numeric value being assigned to some member
+-- of specified numeric model parameter satisfies to all restrictions.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+void check_value_num
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple, /* not changed */
+ double value
+)
+{ CONDITION *cond;
+ WITHIN *in;
+ int eqno;
+ /* the value must satisfy to the parameter type */
+ switch (par->type)
+ { case A_NUMERIC:
+ break;
+ case A_INTEGER:
+ if (value != floor(value))
+ error(mpl, "%s%s = %.*g not integer", par->name,
+ format_tuple(mpl, '[', tuple), DBL_DIG, value);
+ break;
+ case A_BINARY:
+ if (!(value == 0.0 || value == 1.0))
+ error(mpl, "%s%s = %.*g not binary", par->name,
+ format_tuple(mpl, '[', tuple), DBL_DIG, value);
+ break;
+ default:
+ xassert(par != par);
+ }
+ /* the value must satisfy to all specified conditions */
+ for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
+ eqno++)
+ { double bound;
+ char *rho;
+ xassert(cond->code != NULL);
+ bound = eval_numeric(mpl, cond->code);
+ switch (cond->rho)
+ { case O_LT:
+ if (!(value < bound))
+ { rho = "<";
+err: error(mpl, "%s%s = %.*g not %s %.*g; see (%d)",
+ par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
+ value, rho, DBL_DIG, bound, eqno);
+ }
+ break;
+ case O_LE:
+ if (!(value <= bound)) { rho = "<="; goto err; }
+ break;
+ case O_EQ:
+ if (!(value == bound)) { rho = "="; goto err; }
+ break;
+ case O_GE:
+ if (!(value >= bound)) { rho = ">="; goto err; }
+ break;
+ case O_GT:
+ if (!(value > bound)) { rho = ">"; goto err; }
+ break;
+ case O_NE:
+ if (!(value != bound)) { rho = "<>"; goto err; }
+ break;
+ default:
+ xassert(cond != cond);
+ }
+ }
+ /* the value must be in all specified supersets */
+ for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
+ { TUPLE *dummy;
+ xassert(in->code != NULL);
+ xassert(in->code->dim == 1);
+ dummy = expand_tuple(mpl, create_tuple(mpl),
+ create_symbol_num(mpl, value));
+ if (!is_member(mpl, in->code, dummy))
+ error(mpl, "%s%s = %.*g not in specified set; see (%d)",
+ par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
+ value, eqno);
+ delete_tuple(mpl, dummy);
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- take_member_num - obtain num. value assigned to parameter member.
+--
+-- This routine obtains a numeric value assigned to member of specified
+-- numeric model parameter and returns it on exit.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+double take_member_num
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ MEMBER *memb;
+ double value;
+ /* find member in the parameter array */
+ memb = find_member(mpl, par->array, tuple);
+ if (memb != NULL)
+ { /* member exists, so just take its value */
+ value = memb->value.num;
+ }
+ else if (par->assign != NULL)
+ { /* compute value using assignment expression */
+ value = eval_numeric(mpl, par->assign);
+add: /* check that the value satisfies to all restrictions, assign
+ it to new member, and add the member to the array */
+ check_value_num(mpl, par, tuple, value);
+ memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
+ memb->value.num = value;
+ }
+ else if (par->option != NULL)
+ { /* compute default value */
+ value = eval_numeric(mpl, par->option);
+ goto add;
+ }
+ else if (par->defval != NULL)
+ { /* take default value provided in the data section */
+ if (par->defval->str != NULL)
+ error(mpl, "cannot convert %s to floating-point number",
+ format_symbol(mpl, par->defval));
+ value = par->defval->num;
+ goto add;
+ }
+ else
+ { /* no value is provided */
+ error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
+ '[', tuple));
+ }
+ return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_num - evaluate num. value assigned to parameter member.
+--
+-- This routine evaluates a numeric value assigned to given member of
+-- specified numeric model parameter and returns it on exit. */
+
+struct eval_num_info
+{ /* working info used by the routine eval_member_num */
+ PARAMETER *par;
+ /* model parameter */
+ TUPLE *tuple;
+ /* n-tuple, which defines parameter member */
+ MEMBER *memb;
+ /* normally this pointer is NULL; the routine uses this pointer
+ to check data provided in the data section, in which case it
+ points to a member currently checked; this check is performed
+ automatically only once when a reference to any member occurs
+ for the first time */
+ double value;
+ /* evaluated numeric value */
+};
+
+static void eval_num_func(MPL *mpl, void *_info)
+{ /* this is auxiliary routine to work within domain scope */
+ struct eval_num_info *info = _info;
+ if (info->memb != NULL)
+ { /* checking call; check numeric value being assigned */
+ check_value_num(mpl, info->par, info->memb->tuple,
+ info->memb->value.num);
+ }
+ else
+ { /* normal call; evaluate member, which has given n-tuple */
+ info->value = take_member_num(mpl, info->par, info->tuple);
+ }
+ return;
+}
+
+double eval_member_num
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ /* this routine evaluates numeric parameter member */
+ struct eval_num_info _info, *info = &_info;
+ xassert(par->type == A_NUMERIC || par->type == A_INTEGER ||
+ par->type == A_BINARY);
+ xassert(par->dim == tuple_dimen(mpl, tuple));
+ info->par = par;
+ info->tuple = tuple;
+ if (par->data == 1)
+ { /* check data, which are provided in the data section, but not
+ checked yet */
+ /* save pointer to the last array member; note that during the
+ check new members may be added beyond the last member due to
+ references to the same parameter from default expression as
+ well as from expressions that define restricting conditions;
+ however, values assigned to the new members will be checked
+ by other routine, so we don't need to check them here */
+ MEMBER *tail = par->array->tail;
+ /* change the data status to prevent infinite recursive loop
+ due to references to the same parameter during the check */
+ par->data = 2;
+ /* check values assigned to array members in the data section
+ until the marked member has been reached */
+ for (info->memb = par->array->head; info->memb != NULL;
+ info->memb = info->memb->next)
+ { if (eval_within_domain(mpl, par->domain, info->memb->tuple,
+ info, eval_num_func))
+ out_of_domain(mpl, par->name, info->memb->tuple);
+ if (info->memb == tail) break;
+ }
+ /* the check has been finished */
+ }
+ /* evaluate member, which has given n-tuple */
+ info->memb = NULL;
+ if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
+ eval_num_func))
+ out_of_domain(mpl, par->name, info->tuple);
+ /* bring evaluated value to the calling program */
+ return info->value;
+}
+
+/*----------------------------------------------------------------------
+-- check_value_sym - check symbolic value assigned to parameter member.
+--
+-- This routine checks if symbolic value being assigned to some member
+-- of specified symbolic model parameter satisfies to all restrictions.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+void check_value_sym
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple, /* not changed */
+ SYMBOL *value /* not changed */
+)
+{ CONDITION *cond;
+ WITHIN *in;
+ int eqno;
+ /* the value must satisfy to all specified conditions */
+ for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
+ eqno++)
+ { SYMBOL *bound;
+ char buf[255+1];
+ xassert(cond->code != NULL);
+ bound = eval_symbolic(mpl, cond->code);
+ switch (cond->rho)
+ {
+#if 1 /* 13/VIII-2008 */
+ case O_LT:
+ if (!(compare_symbols(mpl, value, bound) < 0))
+ { strcpy(buf, format_symbol(mpl, bound));
+ xassert(strlen(buf) < sizeof(buf));
+ error(mpl, "%s%s = %s not < %s",
+ par->name, format_tuple(mpl, '[', tuple),
+ format_symbol(mpl, value), buf, eqno);
+ }
+ break;
+ case O_LE:
+ if (!(compare_symbols(mpl, value, bound) <= 0))
+ { strcpy(buf, format_symbol(mpl, bound));
+ xassert(strlen(buf) < sizeof(buf));
+ error(mpl, "%s%s = %s not <= %s",
+ par->name, format_tuple(mpl, '[', tuple),
+ format_symbol(mpl, value), buf, eqno);
+ }
+ break;
+#endif
+ case O_EQ:
+ if (!(compare_symbols(mpl, value, bound) == 0))
+ { strcpy(buf, format_symbol(mpl, bound));
+ xassert(strlen(buf) < sizeof(buf));
+ error(mpl, "%s%s = %s not = %s",
+ par->name, format_tuple(mpl, '[', tuple),
+ format_symbol(mpl, value), buf, eqno);
+ }
+ break;
+#if 1 /* 13/VIII-2008 */
+ case O_GE:
+ if (!(compare_symbols(mpl, value, bound) >= 0))
+ { strcpy(buf, format_symbol(mpl, bound));
+ xassert(strlen(buf) < sizeof(buf));
+ error(mpl, "%s%s = %s not >= %s",
+ par->name, format_tuple(mpl, '[', tuple),
+ format_symbol(mpl, value), buf, eqno);
+ }
+ break;
+ case O_GT:
+ if (!(compare_symbols(mpl, value, bound) > 0))
+ { strcpy(buf, format_symbol(mpl, bound));
+ xassert(strlen(buf) < sizeof(buf));
+ error(mpl, "%s%s = %s not > %s",
+ par->name, format_tuple(mpl, '[', tuple),
+ format_symbol(mpl, value), buf, eqno);
+ }
+ break;
+#endif
+ case O_NE:
+ if (!(compare_symbols(mpl, value, bound) != 0))
+ { strcpy(buf, format_symbol(mpl, bound));
+ xassert(strlen(buf) < sizeof(buf));
+ error(mpl, "%s%s = %s not <> %s",
+ par->name, format_tuple(mpl, '[', tuple),
+ format_symbol(mpl, value), buf, eqno);
+ }
+ break;
+ default:
+ xassert(cond != cond);
+ }
+ delete_symbol(mpl, bound);
+ }
+ /* the value must be in all specified supersets */
+ for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
+ { TUPLE *dummy;
+ xassert(in->code != NULL);
+ xassert(in->code->dim == 1);
+ dummy = expand_tuple(mpl, create_tuple(mpl), copy_symbol(mpl,
+ value));
+ if (!is_member(mpl, in->code, dummy))
+ error(mpl, "%s%s = %s not in specified set; see (%d)",
+ par->name, format_tuple(mpl, '[', tuple),
+ format_symbol(mpl, value), eqno);
+ delete_tuple(mpl, dummy);
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- take_member_sym - obtain symb. value assigned to parameter member.
+--
+-- This routine obtains a symbolic value assigned to member of specified
+-- symbolic model parameter and returns it on exit.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+SYMBOL *take_member_sym /* returns value, not reference */
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ MEMBER *memb;
+ SYMBOL *value;
+ /* find member in the parameter array */
+ memb = find_member(mpl, par->array, tuple);
+ if (memb != NULL)
+ { /* member exists, so just take its value */
+ value = copy_symbol(mpl, memb->value.sym);
+ }
+ else if (par->assign != NULL)
+ { /* compute value using assignment expression */
+ value = eval_symbolic(mpl, par->assign);
+add: /* check that the value satisfies to all restrictions, assign
+ it to new member, and add the member to the array */
+ check_value_sym(mpl, par, tuple, value);
+ memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
+ memb->value.sym = copy_symbol(mpl, value);
+ }
+ else if (par->option != NULL)
+ { /* compute default value */
+ value = eval_symbolic(mpl, par->option);
+ goto add;
+ }
+ else if (par->defval != NULL)
+ { /* take default value provided in the data section */
+ value = copy_symbol(mpl, par->defval);
+ goto add;
+ }
+ else
+ { /* no value is provided */
+ error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
+ '[', tuple));
+ }
+ return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_sym - evaluate symb. value assigned to parameter member.
+--
+-- This routine evaluates a symbolic value assigned to given member of
+-- specified symbolic model parameter and returns it on exit. */
+
+struct eval_sym_info
+{ /* working info used by the routine eval_member_sym */
+ PARAMETER *par;
+ /* model parameter */
+ TUPLE *tuple;
+ /* n-tuple, which defines parameter member */
+ MEMBER *memb;
+ /* normally this pointer is NULL; the routine uses this pointer
+ to check data provided in the data section, in which case it
+ points to a member currently checked; this check is performed
+ automatically only once when a reference to any member occurs
+ for the first time */
+ SYMBOL *value;
+ /* evaluated symbolic value */
+};
+
+static void eval_sym_func(MPL *mpl, void *_info)
+{ /* this is auxiliary routine to work within domain scope */
+ struct eval_sym_info *info = _info;
+ if (info->memb != NULL)
+ { /* checking call; check symbolic value being assigned */
+ check_value_sym(mpl, info->par, info->memb->tuple,
+ info->memb->value.sym);
+ }
+ else
+ { /* normal call; evaluate member, which has given n-tuple */
+ info->value = take_member_sym(mpl, info->par, info->tuple);
+ }
+ return;
+}
+
+SYMBOL *eval_member_sym /* returns value, not reference */
+( MPL *mpl,
+ PARAMETER *par, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ /* this routine evaluates symbolic parameter member */
+ struct eval_sym_info _info, *info = &_info;
+ xassert(par->type == A_SYMBOLIC);
+ xassert(par->dim == tuple_dimen(mpl, tuple));
+ info->par = par;
+ info->tuple = tuple;
+ if (par->data == 1)
+ { /* check data, which are provided in the data section, but not
+ checked yet */
+ /* save pointer to the last array member; note that during the
+ check new members may be added beyond the last member due to
+ references to the same parameter from default expression as
+ well as from expressions that define restricting conditions;
+ however, values assigned to the new members will be checked
+ by other routine, so we don't need to check them here */
+ MEMBER *tail = par->array->tail;
+ /* change the data status to prevent infinite recursive loop
+ due to references to the same parameter during the check */
+ par->data = 2;
+ /* check values assigned to array members in the data section
+ until the marked member has been reached */
+ for (info->memb = par->array->head; info->memb != NULL;
+ info->memb = info->memb->next)
+ { if (eval_within_domain(mpl, par->domain, info->memb->tuple,
+ info, eval_sym_func))
+ out_of_domain(mpl, par->name, info->memb->tuple);
+ if (info->memb == tail) break;
+ }
+ /* the check has been finished */
+ }
+ /* evaluate member, which has given n-tuple */
+ info->memb = NULL;
+ if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
+ eval_sym_func))
+ out_of_domain(mpl, par->name, info->tuple);
+ /* bring evaluated value to the calling program */
+ return info->value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_par - evaluate model parameter over entire domain.
+--
+-- This routine evaluates all members of specified model parameter over
+-- entire domain. */
+
+static int whole_par_func(MPL *mpl, void *info)
+{ /* this is auxiliary routine to work within domain scope */
+ PARAMETER *par = (PARAMETER *)info;
+ TUPLE *tuple = get_domain_tuple(mpl, par->domain);
+ switch (par->type)
+ { case A_NUMERIC:
+ case A_INTEGER:
+ case A_BINARY:
+ eval_member_num(mpl, par, tuple);
+ break;
+ case A_SYMBOLIC:
+ delete_symbol(mpl, eval_member_sym(mpl, par, tuple));
+ break;
+ default:
+ xassert(par != par);
+ }
+ delete_tuple(mpl, tuple);
+ return 0;
+}
+
+void eval_whole_par(MPL *mpl, PARAMETER *par)
+{ loop_within_domain(mpl, par->domain, par, whole_par_func);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_parameter - clean model parameter.
+--
+-- This routine cleans specified model parameter that assumes deleting
+-- all stuff dynamically allocated during the generation phase. */
+
+void clean_parameter(MPL *mpl, PARAMETER *par)
+{ CONDITION *cond;
+ WITHIN *in;
+ MEMBER *memb;
+ /* clean subscript domain */
+ clean_domain(mpl, par->domain);
+ /* clean pseudo-code for computing restricting conditions */
+ for (cond = par->cond; cond != NULL; cond = cond->next)
+ clean_code(mpl, cond->code);
+ /* clean pseudo-code for computing restricting supersets */
+ for (in = par->in; in != NULL; in = in->next)
+ clean_code(mpl, in->code);
+ /* clean pseudo-code for computing assigned value */
+ clean_code(mpl, par->assign);
+ /* clean pseudo-code for computing default value */
+ clean_code(mpl, par->option);
+ /* reset data status flag */
+ par->data = 0;
+ /* delete default symbolic value */
+ if (par->defval != NULL)
+ delete_symbol(mpl, par->defval), par->defval = NULL;
+ /* delete content array */
+ for (memb = par->array->head; memb != NULL; memb = memb->next)
+ delete_value(mpl, par->array->type, &memb->value);
+ delete_array(mpl, par->array), par->array = NULL;
+ return;
+}
+
+/**********************************************************************/
+/* * * MODEL VARIABLES * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- take_member_var - obtain reference to elemental variable.
+--
+-- This routine obtains a reference to elemental variable assigned to
+-- given member of specified model variable and returns it on exit. If
+-- necessary, new elemental variable is created.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+ELEMVAR *take_member_var /* returns reference */
+( MPL *mpl,
+ VARIABLE *var, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ MEMBER *memb;
+ ELEMVAR *refer;
+ /* find member in the variable array */
+ memb = find_member(mpl, var->array, tuple);
+ if (memb != NULL)
+ { /* member exists, so just take the reference */
+ refer = memb->value.var;
+ }
+ else
+ { /* member is referenced for the first time and therefore does
+ not exist; create new elemental variable, assign it to new
+ member, and add the member to the variable array */
+ memb = add_member(mpl, var->array, copy_tuple(mpl, tuple));
+ refer = (memb->value.var =
+ dmp_get_atom(mpl->elemvars, sizeof(ELEMVAR)));
+ refer->j = 0;
+ refer->var = var;
+ refer->memb = memb;
+ /* compute lower bound */
+ if (var->lbnd == NULL)
+ refer->lbnd = 0.0;
+ else
+ refer->lbnd = eval_numeric(mpl, var->lbnd);
+ /* compute upper bound */
+ if (var->ubnd == NULL)
+ refer->ubnd = 0.0;
+ else if (var->ubnd == var->lbnd)
+ refer->ubnd = refer->lbnd;
+ else
+ refer->ubnd = eval_numeric(mpl, var->ubnd);
+ /* nullify working quantity */
+ refer->temp = 0.0;
+#if 1 /* 15/V-2010 */
+ /* solution has not been obtained by the solver yet */
+ refer->stat = 0;
+ refer->prim = refer->dual = 0.0;
+#endif
+ }
+ return refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_var - evaluate reference to elemental variable.
+--
+-- This routine evaluates a reference to elemental variable assigned to
+-- member of specified model variable and returns it on exit. */
+
+struct eval_var_info
+{ /* working info used by the routine eval_member_var */
+ VARIABLE *var;
+ /* model variable */
+ TUPLE *tuple;
+ /* n-tuple, which defines variable member */
+ ELEMVAR *refer;
+ /* evaluated reference to elemental variable */
+};
+
+static void eval_var_func(MPL *mpl, void *_info)
+{ /* this is auxiliary routine to work within domain scope */
+ struct eval_var_info *info = _info;
+ info->refer = take_member_var(mpl, info->var, info->tuple);
+ return;
+}
+
+ELEMVAR *eval_member_var /* returns reference */
+( MPL *mpl,
+ VARIABLE *var, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ /* this routine evaluates variable member */
+ struct eval_var_info _info, *info = &_info;
+ xassert(var->dim == tuple_dimen(mpl, tuple));
+ info->var = var;
+ info->tuple = tuple;
+ /* evaluate member, which has given n-tuple */
+ if (eval_within_domain(mpl, info->var->domain, info->tuple, info,
+ eval_var_func))
+ out_of_domain(mpl, var->name, info->tuple);
+ /* bring evaluated reference to the calling program */
+ return info->refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_var - evaluate model variable over entire domain.
+--
+-- This routine evaluates all members of specified model variable over
+-- entire domain. */
+
+static int whole_var_func(MPL *mpl, void *info)
+{ /* this is auxiliary routine to work within domain scope */
+ VARIABLE *var = (VARIABLE *)info;
+ TUPLE *tuple = get_domain_tuple(mpl, var->domain);
+ eval_member_var(mpl, var, tuple);
+ delete_tuple(mpl, tuple);
+ return 0;
+}
+
+void eval_whole_var(MPL *mpl, VARIABLE *var)
+{ loop_within_domain(mpl, var->domain, var, whole_var_func);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_variable - clean model variable.
+--
+-- This routine cleans specified model variable that assumes deleting
+-- all stuff dynamically allocated during the generation phase. */
+
+void clean_variable(MPL *mpl, VARIABLE *var)
+{ MEMBER *memb;
+ /* clean subscript domain */
+ clean_domain(mpl, var->domain);
+ /* clean code for computing lower bound */
+ clean_code(mpl, var->lbnd);
+ /* clean code for computing upper bound */
+ if (var->ubnd != var->lbnd) clean_code(mpl, var->ubnd);
+ /* delete content array */
+ for (memb = var->array->head; memb != NULL; memb = memb->next)
+ dmp_free_atom(mpl->elemvars, memb->value.var, sizeof(ELEMVAR));
+ delete_array(mpl, var->array), var->array = NULL;
+ return;
+}
+
+/**********************************************************************/
+/* * * MODEL CONSTRAINTS AND OBJECTIVES * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- take_member_con - obtain reference to elemental constraint.
+--
+-- This routine obtains a reference to elemental constraint assigned
+-- to given member of specified model constraint and returns it on exit.
+-- If necessary, new elemental constraint is created.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+ELEMCON *take_member_con /* returns reference */
+( MPL *mpl,
+ CONSTRAINT *con, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ MEMBER *memb;
+ ELEMCON *refer;
+ /* find member in the constraint array */
+ memb = find_member(mpl, con->array, tuple);
+ if (memb != NULL)
+ { /* member exists, so just take the reference */
+ refer = memb->value.con;
+ }
+ else
+ { /* member is referenced for the first time and therefore does
+ not exist; create new elemental constraint, assign it to new
+ member, and add the member to the constraint array */
+ memb = add_member(mpl, con->array, copy_tuple(mpl, tuple));
+ refer = (memb->value.con =
+ dmp_get_atom(mpl->elemcons, sizeof(ELEMCON)));
+ refer->i = 0;
+ refer->con = con;
+ refer->memb = memb;
+ /* compute linear form */
+ xassert(con->code != NULL);
+ refer->form = eval_formula(mpl, con->code);
+ /* compute lower and upper bounds */
+ if (con->lbnd == NULL && con->ubnd == NULL)
+ { /* objective has no bounds */
+ double temp;
+ xassert(con->type == A_MINIMIZE || con->type == A_MAXIMIZE);
+ /* carry the constant term to the right-hand side */
+ refer->form = remove_constant(mpl, refer->form, &temp);
+ refer->lbnd = refer->ubnd = - temp;
+ }
+ else if (con->lbnd != NULL && con->ubnd == NULL)
+ { /* constraint a * x + b >= c * y + d is transformed to the
+ standard form a * x - c * y >= d - b */
+ double temp;
+ xassert(con->type == A_CONSTRAINT);
+ refer->form = linear_comb(mpl,
+ +1.0, refer->form,
+ -1.0, eval_formula(mpl, con->lbnd));
+ refer->form = remove_constant(mpl, refer->form, &temp);
+ refer->lbnd = - temp;
+ refer->ubnd = 0.0;
+ }
+ else if (con->lbnd == NULL && con->ubnd != NULL)
+ { /* constraint a * x + b <= c * y + d is transformed to the
+ standard form a * x - c * y <= d - b */
+ double temp;
+ xassert(con->type == A_CONSTRAINT);
+ refer->form = linear_comb(mpl,
+ +1.0, refer->form,
+ -1.0, eval_formula(mpl, con->ubnd));
+ refer->form = remove_constant(mpl, refer->form, &temp);
+ refer->lbnd = 0.0;
+ refer->ubnd = - temp;
+ }
+ else if (con->lbnd == con->ubnd)
+ { /* constraint a * x + b = c * y + d is transformed to the
+ standard form a * x - c * y = d - b */
+ double temp;
+ xassert(con->type == A_CONSTRAINT);
+ refer->form = linear_comb(mpl,
+ +1.0, refer->form,
+ -1.0, eval_formula(mpl, con->lbnd));
+ refer->form = remove_constant(mpl, refer->form, &temp);
+ refer->lbnd = refer->ubnd = - temp;
+ }
+ else
+ { /* ranged constraint c <= a * x + b <= d is transformed to
+ the standard form c - b <= a * x <= d - b */
+ double temp, temp1, temp2;
+ xassert(con->type == A_CONSTRAINT);
+ refer->form = remove_constant(mpl, refer->form, &temp);
+ xassert(remove_constant(mpl, eval_formula(mpl, con->lbnd),
+ &temp1) == NULL);
+ xassert(remove_constant(mpl, eval_formula(mpl, con->ubnd),
+ &temp2) == NULL);
+ refer->lbnd = fp_sub(mpl, temp1, temp);
+ refer->ubnd = fp_sub(mpl, temp2, temp);
+ }
+#if 1 /* 15/V-2010 */
+ /* solution has not been obtained by the solver yet */
+ refer->stat = 0;
+ refer->prim = refer->dual = 0.0;
+#endif
+ }
+ return refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_con - evaluate reference to elemental constraint.
+--
+-- This routine evaluates a reference to elemental constraint assigned
+-- to member of specified model constraint and returns it on exit. */
+
+struct eval_con_info
+{ /* working info used by the routine eval_member_con */
+ CONSTRAINT *con;
+ /* model constraint */
+ TUPLE *tuple;
+ /* n-tuple, which defines constraint member */
+ ELEMCON *refer;
+ /* evaluated reference to elemental constraint */
+};
+
+static void eval_con_func(MPL *mpl, void *_info)
+{ /* this is auxiliary routine to work within domain scope */
+ struct eval_con_info *info = _info;
+ info->refer = take_member_con(mpl, info->con, info->tuple);
+ return;
+}
+
+ELEMCON *eval_member_con /* returns reference */
+( MPL *mpl,
+ CONSTRAINT *con, /* not changed */
+ TUPLE *tuple /* not changed */
+)
+{ /* this routine evaluates constraint member */
+ struct eval_con_info _info, *info = &_info;
+ xassert(con->dim == tuple_dimen(mpl, tuple));
+ info->con = con;
+ info->tuple = tuple;
+ /* evaluate member, which has given n-tuple */
+ if (eval_within_domain(mpl, info->con->domain, info->tuple, info,
+ eval_con_func))
+ out_of_domain(mpl, con->name, info->tuple);
+ /* bring evaluated reference to the calling program */
+ return info->refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_con - evaluate model constraint over entire domain.
+--
+-- This routine evaluates all members of specified model constraint over
+-- entire domain. */
+
+static int whole_con_func(MPL *mpl, void *info)
+{ /* this is auxiliary routine to work within domain scope */
+ CONSTRAINT *con = (CONSTRAINT *)info;
+ TUPLE *tuple = get_domain_tuple(mpl, con->domain);
+ eval_member_con(mpl, con, tuple);
+ delete_tuple(mpl, tuple);
+ return 0;
+}
+
+void eval_whole_con(MPL *mpl, CONSTRAINT *con)
+{ loop_within_domain(mpl, con->domain, con, whole_con_func);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_constraint - clean model constraint.
+--
+-- This routine cleans specified model constraint that assumes deleting
+-- all stuff dynamically allocated during the generation phase. */
+
+void clean_constraint(MPL *mpl, CONSTRAINT *con)
+{ MEMBER *memb;
+ /* clean subscript domain */
+ clean_domain(mpl, con->domain);
+ /* clean code for computing main linear form */
+ clean_code(mpl, con->code);
+ /* clean code for computing lower bound */
+ clean_code(mpl, con->lbnd);
+ /* clean code for computing upper bound */
+ if (con->ubnd != con->lbnd) clean_code(mpl, con->ubnd);
+ /* delete content array */
+ for (memb = con->array->head; memb != NULL; memb = memb->next)
+ { delete_formula(mpl, memb->value.con->form);
+ dmp_free_atom(mpl->elemcons, memb->value.con, sizeof(ELEMCON));
+ }
+ delete_array(mpl, con->array), con->array = NULL;
+ return;
+}
+
+/**********************************************************************/
+/* * * PSEUDO-CODE * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- eval_numeric - evaluate pseudo-code to determine numeric value.
+--
+-- This routine evaluates specified pseudo-code to determine resultant
+-- numeric value, which is returned on exit. */
+
+struct iter_num_info
+{ /* working info used by the routine iter_num_func */
+ CODE *code;
+ /* pseudo-code for iterated operation to be performed */
+ double value;
+ /* resultant value */
+};
+
+static int iter_num_func(MPL *mpl, void *_info)
+{ /* this is auxiliary routine used to perform iterated operation
+ on numeric "integrand" within domain scope */
+ struct iter_num_info *info = _info;
+ double temp;
+ temp = eval_numeric(mpl, info->code->arg.loop.x);
+ switch (info->code->op)
+ { case O_SUM:
+ /* summation over domain */
+ info->value = fp_add(mpl, info->value, temp);
+ break;
+ case O_PROD:
+ /* multiplication over domain */
+ info->value = fp_mul(mpl, info->value, temp);
+ break;
+ case O_MINIMUM:
+ /* minimum over domain */
+ if (info->value > temp) info->value = temp;
+ break;
+ case O_MAXIMUM:
+ /* maximum over domain */
+ if (info->value < temp) info->value = temp;
+ break;
+ default:
+ xassert(info != info);
+ }
+ return 0;
+}
+
+double eval_numeric(MPL *mpl, CODE *code)
+{ double value;
+ xassert(code != NULL);
+ xassert(code->type == A_NUMERIC);
+ xassert(code->dim == 0);
+ /* if the operation has a side effect, invalidate and delete the
+ resultant value */
+ if (code->vflag && code->valid)
+ { code->valid = 0;
+ delete_value(mpl, code->type, &code->value);
+ }
+ /* if resultant value is valid, no evaluation is needed */
+ if (code->valid)
+ { value = code->value.num;
+ goto done;
+ }
+ /* evaluate pseudo-code recursively */
+ switch (code->op)
+ { case O_NUMBER:
+ /* take floating-point number */
+ value = code->arg.num;
+ break;
+ case O_MEMNUM:
+ /* take member of numeric parameter */
+ { TUPLE *tuple;
+ ARG_LIST *e;
+ tuple = create_tuple(mpl);
+ for (e = code->arg.par.list; e != NULL; e = e->next)
+ tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+ e->x));
+ value = eval_member_num(mpl, code->arg.par.par, tuple);
+ delete_tuple(mpl, tuple);
+ }
+ break;
+ case O_MEMVAR:
+ /* take computed value of elemental variable */
+ { TUPLE *tuple;
+ ARG_LIST *e;
+#if 1 /* 15/V-2010 */
+ ELEMVAR *var;
+#endif
+ tuple = create_tuple(mpl);
+ for (e = code->arg.var.list; e != NULL; e = e->next)
+ tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+ e->x));
+#if 0 /* 15/V-2010 */
+ value = eval_member_var(mpl, code->arg.var.var, tuple)
+ ->value;
+#else
+ var = eval_member_var(mpl, code->arg.var.var, tuple);
+ switch (code->arg.var.suff)
+ { case DOT_LB:
+ if (var->var->lbnd == NULL)
+ value = -DBL_MAX;
+ else
+ value = var->lbnd;
+ break;
+ case DOT_UB:
+ if (var->var->ubnd == NULL)
+ value = +DBL_MAX;
+ else
+ value = var->ubnd;
+ break;
+ case DOT_STATUS:
+ value = var->stat;
+ break;
+ case DOT_VAL:
+ value = var->prim;
+ break;
+ case DOT_DUAL:
+ value = var->dual;
+ break;
+ default:
+ xassert(code != code);
+ }
+#endif
+ delete_tuple(mpl, tuple);
+ }
+ break;
+#if 1 /* 15/V-2010 */
+ case O_MEMCON:
+ /* take computed value of elemental constraint */
+ { TUPLE *tuple;
+ ARG_LIST *e;
+ ELEMCON *con;
+ tuple = create_tuple(mpl);
+ for (e = code->arg.con.list; e != NULL; e = e->next)
+ tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+ e->x));
+ con = eval_member_con(mpl, code->arg.con.con, tuple);
+ switch (code->arg.con.suff)
+ { case DOT_LB:
+ if (con->con->lbnd == NULL)
+ value = -DBL_MAX;
+ else
+ value = con->lbnd;
+ break;
+ case DOT_UB:
+ if (con->con->ubnd == NULL)
+ value = +DBL_MAX;
+ else
+ value = con->ubnd;
+ break;
+ case DOT_STATUS:
+ value = con->stat;
+ break;
+ case DOT_VAL:
+ value = con->prim;
+ break;
+ case DOT_DUAL:
+ value = con->dual;
+ break;
+ default:
+ xassert(code != code);
+ }
+ delete_tuple(mpl, tuple);
+ }
+ break;
+#endif
+ case O_IRAND224:
+ /* pseudo-random in [0, 2^24-1] */
+ value = fp_irand224(mpl);
+ break;
+ case O_UNIFORM01:
+ /* pseudo-random in [0, 1) */
+ value = fp_uniform01(mpl);
+ break;
+ case O_NORMAL01:
+ /* gaussian random, mu = 0, sigma = 1 */
+ value = fp_normal01(mpl);
+ break;
+ case O_GMTIME:
+ /* current calendar time */
+ value = fn_gmtime(mpl);
+ break;
+ case O_CVTNUM:
+ /* conversion to numeric */
+ { SYMBOL *sym;
+ sym = eval_symbolic(mpl, code->arg.arg.x);
+#if 0 /* 23/XI-2008 */
+ if (sym->str != NULL)
+ error(mpl, "cannot convert %s to floating-point numbe"
+ "r", format_symbol(mpl, sym));
+ value = sym->num;
+#else
+ if (sym->str == NULL)
+ value = sym->num;
+ else
+ { if (str2num(sym->str, &value))
+ error(mpl, "cannot convert %s to floating-point nu"
+ "mber", format_symbol(mpl, sym));
+ }
+#endif
+ delete_symbol(mpl, sym);
+ }
+ break;
+ case O_PLUS:
+ /* unary plus */
+ value = + eval_numeric(mpl, code->arg.arg.x);
+ break;
+ case O_MINUS:
+ /* unary minus */
+ value = - eval_numeric(mpl, code->arg.arg.x);
+ break;
+ case O_ABS:
+ /* absolute value */
+ value = fabs(eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_CEIL:
+ /* round upward ("ceiling of x") */
+ value = ceil(eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_FLOOR:
+ /* round downward ("floor of x") */
+ value = floor(eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_EXP:
+ /* base-e exponential */
+ value = fp_exp(mpl, eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_LOG:
+ /* natural logarithm */
+ value = fp_log(mpl, eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_LOG10:
+ /* common (decimal) logarithm */
+ value = fp_log10(mpl, eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_SQRT:
+ /* square root */
+ value = fp_sqrt(mpl, eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_SIN:
+ /* trigonometric sine */
+ value = fp_sin(mpl, eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_COS:
+ /* trigonometric cosine */
+ value = fp_cos(mpl, eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_TAN:
+ /* trigonometric tangent */
+ value = fp_tan(mpl, eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_ATAN:
+ /* trigonometric arctangent (one argument) */
+ value = fp_atan(mpl, eval_numeric(mpl, code->arg.arg.x));
+ break;
+ case O_ATAN2:
+ /* trigonometric arctangent (two arguments) */
+ value = fp_atan2(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_ROUND:
+ /* round to nearest integer */
+ value = fp_round(mpl,
+ eval_numeric(mpl, code->arg.arg.x), 0.0);
+ break;
+ case O_ROUND2:
+ /* round to n fractional digits */
+ value = fp_round(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_TRUNC:
+ /* truncate to nearest integer */
+ value = fp_trunc(mpl,
+ eval_numeric(mpl, code->arg.arg.x), 0.0);
+ break;
+ case O_TRUNC2:
+ /* truncate to n fractional digits */
+ value = fp_trunc(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_ADD:
+ /* addition */
+ value = fp_add(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_SUB:
+ /* subtraction */
+ value = fp_sub(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_LESS:
+ /* non-negative subtraction */
+ value = fp_less(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_MUL:
+ /* multiplication */
+ value = fp_mul(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_DIV:
+ /* division */
+ value = fp_div(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_IDIV:
+ /* quotient of exact division */
+ value = fp_idiv(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_MOD:
+ /* remainder of exact division */
+ value = fp_mod(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_POWER:
+ /* exponentiation (raise to power) */
+ value = fp_power(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_UNIFORM:
+ /* pseudo-random in [a, b) */
+ value = fp_uniform(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_NORMAL:
+ /* gaussian random, given mu and sigma */
+ value = fp_normal(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y));
+ break;
+ case O_CARD:
+ { ELEMSET *set;
+ set = eval_elemset(mpl, code->arg.arg.x);
+ value = set->size;
+ delete_array(mpl, set);
+ }
+ break;
+ case O_LENGTH:
+ { SYMBOL *sym;
+ char str[MAX_LENGTH+1];
+ sym = eval_symbolic(mpl, code->arg.arg.x);
+ if (sym->str == NULL)
+ sprintf(str, "%.*g", DBL_DIG, sym->num);
+ else
+ fetch_string(mpl, sym->str, str);
+ delete_symbol(mpl, sym);
+ value = strlen(str);
+ }
+ break;
+ case O_STR2TIME:
+ { SYMBOL *sym;
+ char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
+ sym = eval_symbolic(mpl, code->arg.arg.x);
+ if (sym->str == NULL)
+ sprintf(str, "%.*g", DBL_DIG, sym->num);
+ else
+ fetch_string(mpl, sym->str, str);
+ delete_symbol(mpl, sym);
+ sym = eval_symbolic(mpl, code->arg.arg.y);
+ if (sym->str == NULL)
+ sprintf(fmt, "%.*g", DBL_DIG, sym->num);
+ else
+ fetch_string(mpl, sym->str, fmt);
+ delete_symbol(mpl, sym);
+ value = fn_str2time(mpl, str, fmt);
+ }
+ break;
+ case O_FORK:
+ /* if-then-else */
+ if (eval_logical(mpl, code->arg.arg.x))
+ value = eval_numeric(mpl, code->arg.arg.y);
+ else if (code->arg.arg.z == NULL)
+ value = 0.0;
+ else
+ value = eval_numeric(mpl, code->arg.arg.z);
+ break;
+ case O_MIN:
+ /* minimal value (n-ary) */
+ { ARG_LIST *e;
+ double temp;
+ value = +DBL_MAX;
+ for (e = code->arg.list; e != NULL; e = e->next)
+ { temp = eval_numeric(mpl, e->x);
+ if (value > temp) value = temp;
+ }
+ }
+ break;
+ case O_MAX:
+ /* maximal value (n-ary) */
+ { ARG_LIST *e;
+ double temp;
+ value = -DBL_MAX;
+ for (e = code->arg.list; e != NULL; e = e->next)
+ { temp = eval_numeric(mpl, e->x);
+ if (value < temp) value = temp;
+ }
+ }
+ break;
+ case O_SUM:
+ /* summation over domain */
+ { struct iter_num_info _info, *info = &_info;
+ info->code = code;
+ info->value = 0.0;
+ loop_within_domain(mpl, code->arg.loop.domain, info,
+ iter_num_func);
+ value = info->value;
+ }
+ break;
+ case O_PROD:
+ /* multiplication over domain */
+ { struct iter_num_info _info, *info = &_info;
+ info->code = code;
+ info->value = 1.0;
+ loop_within_domain(mpl, code->arg.loop.domain, info,
+ iter_num_func);
+ value = info->value;
+ }
+ break;
+ case O_MINIMUM:
+ /* minimum over domain */
+ { struct iter_num_info _info, *info = &_info;
+ info->code = code;
+ info->value = +DBL_MAX;
+ loop_within_domain(mpl, code->arg.loop.domain, info,
+ iter_num_func);
+ if (info->value == +DBL_MAX)
+ error(mpl, "min{} over empty set; result undefined");
+ value = info->value;
+ }
+ break;
+ case O_MAXIMUM:
+ /* maximum over domain */
+ { struct iter_num_info _info, *info = &_info;
+ info->code = code;
+ info->value = -DBL_MAX;
+ loop_within_domain(mpl, code->arg.loop.domain, info,
+ iter_num_func);
+ if (info->value == -DBL_MAX)
+ error(mpl, "max{} over empty set; result undefined");
+ value = info->value;
+ }
+ break;
+ default:
+ xassert(code != code);
+ }
+ /* save resultant value */
+ xassert(!code->valid);
+ code->valid = 1;
+ code->value.num = value;
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_symbolic - evaluate pseudo-code to determine symbolic value.
+--
+-- This routine evaluates specified pseudo-code to determine resultant
+-- symbolic value, which is returned on exit. */
+
+SYMBOL *eval_symbolic(MPL *mpl, CODE *code)
+{ SYMBOL *value;
+ xassert(code != NULL);
+ xassert(code->type == A_SYMBOLIC);
+ xassert(code->dim == 0);
+ /* if the operation has a side effect, invalidate and delete the
+ resultant value */
+ if (code->vflag && code->valid)
+ { code->valid = 0;
+ delete_value(mpl, code->type, &code->value);
+ }
+ /* if resultant value is valid, no evaluation is needed */
+ if (code->valid)
+ { value = copy_symbol(mpl, code->value.sym);
+ goto done;
+ }
+ /* evaluate pseudo-code recursively */
+ switch (code->op)
+ { case O_STRING:
+ /* take character string */
+ value = create_symbol_str(mpl, create_string(mpl,
+ code->arg.str));
+ break;
+ case O_INDEX:
+ /* take dummy index */
+ xassert(code->arg.index.slot->value != NULL);
+ value = copy_symbol(mpl, code->arg.index.slot->value);
+ break;
+ case O_MEMSYM:
+ /* take member of symbolic parameter */
+ { TUPLE *tuple;
+ ARG_LIST *e;
+ tuple = create_tuple(mpl);
+ for (e = code->arg.par.list; e != NULL; e = e->next)
+ tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+ e->x));
+ value = eval_member_sym(mpl, code->arg.par.par, tuple);
+ delete_tuple(mpl, tuple);
+ }
+ break;
+ case O_CVTSYM:
+ /* conversion to symbolic */
+ value = create_symbol_num(mpl, eval_numeric(mpl,
+ code->arg.arg.x));
+ break;
+ case O_CONCAT:
+ /* concatenation */
+ value = concat_symbols(mpl,
+ eval_symbolic(mpl, code->arg.arg.x),
+ eval_symbolic(mpl, code->arg.arg.y));
+ break;
+ case O_FORK:
+ /* if-then-else */
+ if (eval_logical(mpl, code->arg.arg.x))
+ value = eval_symbolic(mpl, code->arg.arg.y);
+ else if (code->arg.arg.z == NULL)
+ value = create_symbol_num(mpl, 0.0);
+ else
+ value = eval_symbolic(mpl, code->arg.arg.z);
+ break;
+ case O_SUBSTR:
+ case O_SUBSTR3:
+ { double pos, len;
+ char str[MAX_LENGTH+1];
+ value = eval_symbolic(mpl, code->arg.arg.x);
+ if (value->str == NULL)
+ sprintf(str, "%.*g", DBL_DIG, value->num);
+ else
+ fetch_string(mpl, value->str, str);
+ delete_symbol(mpl, value);
+ if (code->op == O_SUBSTR)
+ { pos = eval_numeric(mpl, code->arg.arg.y);
+ if (pos != floor(pos))
+ error(mpl, "substr('...', %.*g); non-integer secon"
+ "d argument", DBL_DIG, pos);
+ if (pos < 1 || pos > strlen(str) + 1)
+ error(mpl, "substr('...', %.*g); substring out of "
+ "range", DBL_DIG, pos);
+ }
+ else
+ { pos = eval_numeric(mpl, code->arg.arg.y);
+ len = eval_numeric(mpl, code->arg.arg.z);
+ if (pos != floor(pos) || len != floor(len))
+ error(mpl, "substr('...', %.*g, %.*g); non-integer"
+ " second and/or third argument", DBL_DIG, pos,
+ DBL_DIG, len);
+ if (pos < 1 || len < 0 || pos + len > strlen(str) + 1)
+ error(mpl, "substr('...', %.*g, %.*g); substring o"
+ "ut of range", DBL_DIG, pos, DBL_DIG, len);
+ str[(int)pos + (int)len - 1] = '\0';
+ }
+ value = create_symbol_str(mpl, create_string(mpl, str +
+ (int)pos - 1));
+ }
+ break;
+ case O_TIME2STR:
+ { double num;
+ SYMBOL *sym;
+ char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
+ num = eval_numeric(mpl, code->arg.arg.x);
+ sym = eval_symbolic(mpl, code->arg.arg.y);
+ if (sym->str == NULL)
+ sprintf(fmt, "%.*g", DBL_DIG, sym->num);
+ else
+ fetch_string(mpl, sym->str, fmt);
+ delete_symbol(mpl, sym);
+ fn_time2str(mpl, str, num, fmt);
+ value = create_symbol_str(mpl, create_string(mpl, str));
+ }
+ break;
+ default:
+ xassert(code != code);
+ }
+ /* save resultant value */
+ xassert(!code->valid);
+ code->valid = 1;
+ code->value.sym = copy_symbol(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_logical - evaluate pseudo-code to determine logical value.
+--
+-- This routine evaluates specified pseudo-code to determine resultant
+-- logical value, which is returned on exit. */
+
+struct iter_log_info
+{ /* working info used by the routine iter_log_func */
+ CODE *code;
+ /* pseudo-code for iterated operation to be performed */
+ int value;
+ /* resultant value */
+};
+
+static int iter_log_func(MPL *mpl, void *_info)
+{ /* this is auxiliary routine used to perform iterated operation
+ on logical "integrand" within domain scope */
+ struct iter_log_info *info = _info;
+ int ret = 0;
+ switch (info->code->op)
+ { case O_FORALL:
+ /* conjunction over domain */
+ info->value &= eval_logical(mpl, info->code->arg.loop.x);
+ if (!info->value) ret = 1;
+ break;
+ case O_EXISTS:
+ /* disjunction over domain */
+ info->value |= eval_logical(mpl, info->code->arg.loop.x);
+ if (info->value) ret = 1;
+ break;
+ default:
+ xassert(info != info);
+ }
+ return ret;
+}
+
+int eval_logical(MPL *mpl, CODE *code)
+{ int value;
+ xassert(code->type == A_LOGICAL);
+ xassert(code->dim == 0);
+ /* if the operation has a side effect, invalidate and delete the
+ resultant value */
+ if (code->vflag && code->valid)
+ { code->valid = 0;
+ delete_value(mpl, code->type, &code->value);
+ }
+ /* if resultant value is valid, no evaluation is needed */
+ if (code->valid)
+ { value = code->value.bit;
+ goto done;
+ }
+ /* evaluate pseudo-code recursively */
+ switch (code->op)
+ { case O_CVTLOG:
+ /* conversion to logical */
+ value = (eval_numeric(mpl, code->arg.arg.x) != 0.0);
+ break;
+ case O_NOT:
+ /* negation (logical "not") */
+ value = !eval_logical(mpl, code->arg.arg.x);
+ break;
+ case O_LT:
+ /* comparison on 'less than' */
+#if 0 /* 02/VIII-2008 */
+ value = (eval_numeric(mpl, code->arg.arg.x) <
+ eval_numeric(mpl, code->arg.arg.y));
+#else
+ xassert(code->arg.arg.x != NULL);
+ if (code->arg.arg.x->type == A_NUMERIC)
+ value = (eval_numeric(mpl, code->arg.arg.x) <
+ eval_numeric(mpl, code->arg.arg.y));
+ else
+ { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+ SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+ value = (compare_symbols(mpl, sym1, sym2) < 0);
+ delete_symbol(mpl, sym1);
+ delete_symbol(mpl, sym2);
+ }
+#endif
+ break;
+ case O_LE:
+ /* comparison on 'not greater than' */
+#if 0 /* 02/VIII-2008 */
+ value = (eval_numeric(mpl, code->arg.arg.x) <=
+ eval_numeric(mpl, code->arg.arg.y));
+#else
+ xassert(code->arg.arg.x != NULL);
+ if (code->arg.arg.x->type == A_NUMERIC)
+ value = (eval_numeric(mpl, code->arg.arg.x) <=
+ eval_numeric(mpl, code->arg.arg.y));
+ else
+ { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+ SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+ value = (compare_symbols(mpl, sym1, sym2) <= 0);
+ delete_symbol(mpl, sym1);
+ delete_symbol(mpl, sym2);
+ }
+#endif
+ break;
+ case O_EQ:
+ /* comparison on 'equal to' */
+ xassert(code->arg.arg.x != NULL);
+ if (code->arg.arg.x->type == A_NUMERIC)
+ value = (eval_numeric(mpl, code->arg.arg.x) ==
+ eval_numeric(mpl, code->arg.arg.y));
+ else
+ { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+ SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+ value = (compare_symbols(mpl, sym1, sym2) == 0);
+ delete_symbol(mpl, sym1);
+ delete_symbol(mpl, sym2);
+ }
+ break;
+ case O_GE:
+ /* comparison on 'not less than' */
+#if 0 /* 02/VIII-2008 */
+ value = (eval_numeric(mpl, code->arg.arg.x) >=
+ eval_numeric(mpl, code->arg.arg.y));
+#else
+ xassert(code->arg.arg.x != NULL);
+ if (code->arg.arg.x->type == A_NUMERIC)
+ value = (eval_numeric(mpl, code->arg.arg.x) >=
+ eval_numeric(mpl, code->arg.arg.y));
+ else
+ { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+ SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+ value = (compare_symbols(mpl, sym1, sym2) >= 0);
+ delete_symbol(mpl, sym1);
+ delete_symbol(mpl, sym2);
+ }
+#endif
+ break;
+ case O_GT:
+ /* comparison on 'greater than' */
+#if 0 /* 02/VIII-2008 */
+ value = (eval_numeric(mpl, code->arg.arg.x) >
+ eval_numeric(mpl, code->arg.arg.y));
+#else
+ xassert(code->arg.arg.x != NULL);
+ if (code->arg.arg.x->type == A_NUMERIC)
+ value = (eval_numeric(mpl, code->arg.arg.x) >
+ eval_numeric(mpl, code->arg.arg.y));
+ else
+ { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+ SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+ value = (compare_symbols(mpl, sym1, sym2) > 0);
+ delete_symbol(mpl, sym1);
+ delete_symbol(mpl, sym2);
+ }
+#endif
+ break;
+ case O_NE:
+ /* comparison on 'not equal to' */
+ xassert(code->arg.arg.x != NULL);
+ if (code->arg.arg.x->type == A_NUMERIC)
+ value = (eval_numeric(mpl, code->arg.arg.x) !=
+ eval_numeric(mpl, code->arg.arg.y));
+ else
+ { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+ SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+ value = (compare_symbols(mpl, sym1, sym2) != 0);
+ delete_symbol(mpl, sym1);
+ delete_symbol(mpl, sym2);
+ }
+ break;
+ case O_AND:
+ /* conjunction (logical "and") */
+ value = eval_logical(mpl, code->arg.arg.x) &&
+ eval_logical(mpl, code->arg.arg.y);
+ break;
+ case O_OR:
+ /* disjunction (logical "or") */
+ value = eval_logical(mpl, code->arg.arg.x) ||
+ eval_logical(mpl, code->arg.arg.y);
+ break;
+ case O_IN:
+ /* test on 'x in Y' */
+ { TUPLE *tuple;
+ tuple = eval_tuple(mpl, code->arg.arg.x);
+ value = is_member(mpl, code->arg.arg.y, tuple);
+ delete_tuple(mpl, tuple);
+ }
+ break;
+ case O_NOTIN:
+ /* test on 'x not in Y' */
+ { TUPLE *tuple;
+ tuple = eval_tuple(mpl, code->arg.arg.x);
+ value = !is_member(mpl, code->arg.arg.y, tuple);
+ delete_tuple(mpl, tuple);
+ }
+ break;
+ case O_WITHIN:
+ /* test on 'X within Y' */
+ { ELEMSET *set;
+ MEMBER *memb;
+ set = eval_elemset(mpl, code->arg.arg.x);
+ value = 1;
+ for (memb = set->head; memb != NULL; memb = memb->next)
+ { if (!is_member(mpl, code->arg.arg.y, memb->tuple))
+ { value = 0;
+ break;
+ }
+ }
+ delete_elemset(mpl, set);
+ }
+ break;
+ case O_NOTWITHIN:
+ /* test on 'X not within Y' */
+ { ELEMSET *set;
+ MEMBER *memb;
+ set = eval_elemset(mpl, code->arg.arg.x);
+ value = 1;
+ for (memb = set->head; memb != NULL; memb = memb->next)
+ { if (is_member(mpl, code->arg.arg.y, memb->tuple))
+ { value = 0;
+ break;
+ }
+ }
+ delete_elemset(mpl, set);
+ }
+ break;
+ case O_FORALL:
+ /* conjunction (A-quantification) */
+ { struct iter_log_info _info, *info = &_info;
+ info->code = code;
+ info->value = 1;
+ loop_within_domain(mpl, code->arg.loop.domain, info,
+ iter_log_func);
+ value = info->value;
+ }
+ break;
+ case O_EXISTS:
+ /* disjunction (E-quantification) */
+ { struct iter_log_info _info, *info = &_info;
+ info->code = code;
+ info->value = 0;
+ loop_within_domain(mpl, code->arg.loop.domain, info,
+ iter_log_func);
+ value = info->value;
+ }
+ break;
+ default:
+ xassert(code != code);
+ }
+ /* save resultant value */
+ xassert(!code->valid);
+ code->valid = 1;
+ code->value.bit = value;
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_tuple - evaluate pseudo-code to construct n-tuple.
+--
+-- This routine evaluates specified pseudo-code to construct resultant
+-- n-tuple, which is returned on exit. */
+
+TUPLE *eval_tuple(MPL *mpl, CODE *code)
+{ TUPLE *value;
+ xassert(code != NULL);
+ xassert(code->type == A_TUPLE);
+ xassert(code->dim > 0);
+ /* if the operation has a side effect, invalidate and delete the
+ resultant value */
+ if (code->vflag && code->valid)
+ { code->valid = 0;
+ delete_value(mpl, code->type, &code->value);
+ }
+ /* if resultant value is valid, no evaluation is needed */
+ if (code->valid)
+ { value = copy_tuple(mpl, code->value.tuple);
+ goto done;
+ }
+ /* evaluate pseudo-code recursively */
+ switch (code->op)
+ { case O_TUPLE:
+ /* make n-tuple */
+ { ARG_LIST *e;
+ value = create_tuple(mpl);
+ for (e = code->arg.list; e != NULL; e = e->next)
+ value = expand_tuple(mpl, value, eval_symbolic(mpl,
+ e->x));
+ }
+ break;
+ case O_CVTTUP:
+ /* convert to 1-tuple */
+ value = expand_tuple(mpl, create_tuple(mpl),
+ eval_symbolic(mpl, code->arg.arg.x));
+ break;
+ default:
+ xassert(code != code);
+ }
+ /* save resultant value */
+ xassert(!code->valid);
+ code->valid = 1;
+ code->value.tuple = copy_tuple(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_elemset - evaluate pseudo-code to construct elemental set.
+--
+-- This routine evaluates specified pseudo-code to construct resultant
+-- elemental set, which is returned on exit. */
+
+struct iter_set_info
+{ /* working info used by the routine iter_set_func */
+ CODE *code;
+ /* pseudo-code for iterated operation to be performed */
+ ELEMSET *value;
+ /* resultant value */
+};
+
+static int iter_set_func(MPL *mpl, void *_info)
+{ /* this is auxiliary routine used to perform iterated operation
+ on n-tuple "integrand" within domain scope */
+ struct iter_set_info *info = _info;
+ TUPLE *tuple;
+ switch (info->code->op)
+ { case O_SETOF:
+ /* compute next n-tuple and add it to the set; in this case
+ duplicate n-tuples are silently ignored */
+ tuple = eval_tuple(mpl, info->code->arg.loop.x);
+ if (find_tuple(mpl, info->value, tuple) == NULL)
+ add_tuple(mpl, info->value, tuple);
+ else
+ delete_tuple(mpl, tuple);
+ break;
+ case O_BUILD:
+ /* construct next n-tuple using current values assigned to
+ *free* dummy indices as its components and add it to the
+ set; in this case duplicate n-tuples cannot appear */
+ add_tuple(mpl, info->value, get_domain_tuple(mpl,
+ info->code->arg.loop.domain));
+ break;
+ default:
+ xassert(info != info);
+ }
+ return 0;
+}
+
+ELEMSET *eval_elemset(MPL *mpl, CODE *code)
+{ ELEMSET *value;
+ xassert(code != NULL);
+ xassert(code->type == A_ELEMSET);
+ xassert(code->dim > 0);
+ /* if the operation has a side effect, invalidate and delete the
+ resultant value */
+ if (code->vflag && code->valid)
+ { code->valid = 0;
+ delete_value(mpl, code->type, &code->value);
+ }
+ /* if resultant value is valid, no evaluation is needed */
+ if (code->valid)
+ { value = copy_elemset(mpl, code->value.set);
+ goto done;
+ }
+ /* evaluate pseudo-code recursively */
+ switch (code->op)
+ { case O_MEMSET:
+ /* take member of set */
+ { TUPLE *tuple;
+ ARG_LIST *e;
+ tuple = create_tuple(mpl);
+ for (e = code->arg.set.list; e != NULL; e = e->next)
+ tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+ e->x));
+ value = copy_elemset(mpl,
+ eval_member_set(mpl, code->arg.set.set, tuple));
+ delete_tuple(mpl, tuple);
+ }
+ break;
+ case O_MAKE:
+ /* make elemental set of n-tuples */
+ { ARG_LIST *e;
+ value = create_elemset(mpl, code->dim);
+ for (e = code->arg.list; e != NULL; e = e->next)
+ check_then_add(mpl, value, eval_tuple(mpl, e->x));
+ }
+ break;
+ case O_UNION:
+ /* union of two elemental sets */
+ value = set_union(mpl,
+ eval_elemset(mpl, code->arg.arg.x),
+ eval_elemset(mpl, code->arg.arg.y));
+ break;
+ case O_DIFF:
+ /* difference between two elemental sets */
+ value = set_diff(mpl,
+ eval_elemset(mpl, code->arg.arg.x),
+ eval_elemset(mpl, code->arg.arg.y));
+ break;
+ case O_SYMDIFF:
+ /* symmetric difference between two elemental sets */
+ value = set_symdiff(mpl,
+ eval_elemset(mpl, code->arg.arg.x),
+ eval_elemset(mpl, code->arg.arg.y));
+ break;
+ case O_INTER:
+ /* intersection of two elemental sets */
+ value = set_inter(mpl,
+ eval_elemset(mpl, code->arg.arg.x),
+ eval_elemset(mpl, code->arg.arg.y));
+ break;
+ case O_CROSS:
+ /* cross (Cartesian) product of two elemental sets */
+ value = set_cross(mpl,
+ eval_elemset(mpl, code->arg.arg.x),
+ eval_elemset(mpl, code->arg.arg.y));
+ break;
+ case O_DOTS:
+ /* build "arithmetic" elemental set */
+ value = create_arelset(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_numeric(mpl, code->arg.arg.y),
+ code->arg.arg.z == NULL ? 1.0 : eval_numeric(mpl,
+ code->arg.arg.z));
+ break;
+ case O_FORK:
+ /* if-then-else */
+ if (eval_logical(mpl, code->arg.arg.x))
+ value = eval_elemset(mpl, code->arg.arg.y);
+ else
+ value = eval_elemset(mpl, code->arg.arg.z);
+ break;
+ case O_SETOF:
+ /* compute elemental set */
+ { struct iter_set_info _info, *info = &_info;
+ info->code = code;
+ info->value = create_elemset(mpl, code->dim);
+ loop_within_domain(mpl, code->arg.loop.domain, info,
+ iter_set_func);
+ value = info->value;
+ }
+ break;
+ case O_BUILD:
+ /* build elemental set identical to domain set */
+ { struct iter_set_info _info, *info = &_info;
+ info->code = code;
+ info->value = create_elemset(mpl, code->dim);
+ loop_within_domain(mpl, code->arg.loop.domain, info,
+ iter_set_func);
+ value = info->value;
+ }
+ break;
+ default:
+ xassert(code != code);
+ }
+ /* save resultant value */
+ xassert(!code->valid);
+ code->valid = 1;
+ code->value.set = copy_elemset(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- is_member - check if n-tuple is in set specified by pseudo-code.
+--
+-- This routine checks if given n-tuple is a member of elemental set
+-- specified in the form of pseudo-code (i.e. by expression).
+--
+-- The n-tuple may have more components that dimension of the elemental
+-- set, in which case the extra components are ignored. */
+
+static void null_func(MPL *mpl, void *info)
+{ /* this is dummy routine used to enter the domain scope */
+ xassert(mpl == mpl);
+ xassert(info == NULL);
+ return;
+}
+
+int is_member(MPL *mpl, CODE *code, TUPLE *tuple)
+{ int value;
+ xassert(code != NULL);
+ xassert(code->type == A_ELEMSET);
+ xassert(code->dim > 0);
+ xassert(tuple != NULL);
+ switch (code->op)
+ { case O_MEMSET:
+ /* check if given n-tuple is member of elemental set, which
+ is assigned to member of model set */
+ { ARG_LIST *e;
+ TUPLE *temp;
+ ELEMSET *set;
+ /* evaluate reference to elemental set */
+ temp = create_tuple(mpl);
+ for (e = code->arg.set.list; e != NULL; e = e->next)
+ temp = expand_tuple(mpl, temp, eval_symbolic(mpl,
+ e->x));
+ set = eval_member_set(mpl, code->arg.set.set, temp);
+ delete_tuple(mpl, temp);
+ /* check if the n-tuple is contained in the set array */
+ temp = build_subtuple(mpl, tuple, set->dim);
+ value = (find_tuple(mpl, set, temp) != NULL);
+ delete_tuple(mpl, temp);
+ }
+ break;
+ case O_MAKE:
+ /* check if given n-tuple is member of literal set */
+ { ARG_LIST *e;
+ TUPLE *temp, *that;
+ value = 0;
+ temp = build_subtuple(mpl, tuple, code->dim);
+ for (e = code->arg.list; e != NULL; e = e->next)
+ { that = eval_tuple(mpl, e->x);
+ value = (compare_tuples(mpl, temp, that) == 0);
+ delete_tuple(mpl, that);
+ if (value) break;
+ }
+ delete_tuple(mpl, temp);
+ }
+ break;
+ case O_UNION:
+ value = is_member(mpl, code->arg.arg.x, tuple) ||
+ is_member(mpl, code->arg.arg.y, tuple);
+ break;
+ case O_DIFF:
+ value = is_member(mpl, code->arg.arg.x, tuple) &&
+ !is_member(mpl, code->arg.arg.y, tuple);
+ break;
+ case O_SYMDIFF:
+ { int in1 = is_member(mpl, code->arg.arg.x, tuple);
+ int in2 = is_member(mpl, code->arg.arg.y, tuple);
+ value = (in1 && !in2) || (!in1 && in2);
+ }
+ break;
+ case O_INTER:
+ value = is_member(mpl, code->arg.arg.x, tuple) &&
+ is_member(mpl, code->arg.arg.y, tuple);
+ break;
+ case O_CROSS:
+ { int j;
+ value = is_member(mpl, code->arg.arg.x, tuple);
+ if (value)
+ { for (j = 1; j <= code->arg.arg.x->dim; j++)
+ { xassert(tuple != NULL);
+ tuple = tuple->next;
+ }
+ value = is_member(mpl, code->arg.arg.y, tuple);
+ }
+ }
+ break;
+ case O_DOTS:
+ /* check if given 1-tuple is member of "arithmetic" set */
+ { int j;
+ double x, t0, tf, dt;
+ xassert(code->dim == 1);
+ /* compute "parameters" of the "arithmetic" set */
+ t0 = eval_numeric(mpl, code->arg.arg.x);
+ tf = eval_numeric(mpl, code->arg.arg.y);
+ if (code->arg.arg.z == NULL)
+ dt = 1.0;
+ else
+ dt = eval_numeric(mpl, code->arg.arg.z);
+ /* make sure the parameters are correct */
+ arelset_size(mpl, t0, tf, dt);
+ /* if component of 1-tuple is symbolic, not numeric, the
+ 1-tuple cannot be member of "arithmetic" set */
+ xassert(tuple->sym != NULL);
+ if (tuple->sym->str != NULL)
+ { value = 0;
+ break;
+ }
+ /* determine numeric value of the component */
+ x = tuple->sym->num;
+ /* if the component value is out of the set range, the
+ 1-tuple is not in the set */
+ if (dt > 0.0 && !(t0 <= x && x <= tf) ||
+ dt < 0.0 && !(tf <= x && x <= t0))
+ { value = 0;
+ break;
+ }
+ /* estimate ordinal number of the 1-tuple in the set */
+ j = (int)(((x - t0) / dt) + 0.5) + 1;
+ /* perform the main check */
+ value = (arelset_member(mpl, t0, tf, dt, j) == x);
+ }
+ break;
+ case O_FORK:
+ /* check if given n-tuple is member of conditional set */
+ if (eval_logical(mpl, code->arg.arg.x))
+ value = is_member(mpl, code->arg.arg.y, tuple);
+ else
+ value = is_member(mpl, code->arg.arg.z, tuple);
+ break;
+ case O_SETOF:
+ /* check if given n-tuple is member of computed set */
+ /* it is not clear how to efficiently perform the check not
+ computing the entire elemental set :+( */
+ error(mpl, "implementation restriction; in/within setof{} n"
+ "ot allowed");
+ break;
+ case O_BUILD:
+ /* check if given n-tuple is member of domain set */
+ { TUPLE *temp;
+ temp = build_subtuple(mpl, tuple, code->dim);
+ /* try to enter the domain scope; if it is successful,
+ the n-tuple is in the domain set */
+ value = (eval_within_domain(mpl, code->arg.loop.domain,
+ temp, NULL, null_func) == 0);
+ delete_tuple(mpl, temp);
+ }
+ break;
+ default:
+ xassert(code != code);
+ }
+ return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_formula - evaluate pseudo-code to construct linear form.
+--
+-- This routine evaluates specified pseudo-code to construct resultant
+-- linear form, which is returned on exit. */
+
+struct iter_form_info
+{ /* working info used by the routine iter_form_func */
+ CODE *code;
+ /* pseudo-code for iterated operation to be performed */
+ FORMULA *value;
+ /* resultant value */
+ FORMULA *tail;
+ /* pointer to the last term */
+};
+
+static int iter_form_func(MPL *mpl, void *_info)
+{ /* this is auxiliary routine used to perform iterated operation
+ on linear form "integrand" within domain scope */
+ struct iter_form_info *info = _info;
+ switch (info->code->op)
+ { case O_SUM:
+ /* summation over domain */
+#if 0
+ info->value =
+ linear_comb(mpl,
+ +1.0, info->value,
+ +1.0, eval_formula(mpl, info->code->arg.loop.x));
+#else
+ /* the routine linear_comb needs to look through all terms
+ of both linear forms to reduce identical terms, so using
+ it here is not a good idea (for example, evaluation of
+ sum{i in 1..n} x[i] required quadratic time); the better
+ idea is to gather all terms of the integrand in one list
+ and reduce identical terms only once after all terms of
+ the resultant linear form have been evaluated */
+ { FORMULA *form, *term;
+ form = eval_formula(mpl, info->code->arg.loop.x);
+ if (info->value == NULL)
+ { xassert(info->tail == NULL);
+ info->value = form;
+ }
+ else
+ { xassert(info->tail != NULL);
+ info->tail->next = form;
+ }
+ for (term = form; term != NULL; term = term->next)
+ info->tail = term;
+ }
+#endif
+ break;
+ default:
+ xassert(info != info);
+ }
+ return 0;
+}
+
+FORMULA *eval_formula(MPL *mpl, CODE *code)
+{ FORMULA *value;
+ xassert(code != NULL);
+ xassert(code->type == A_FORMULA);
+ xassert(code->dim == 0);
+ /* if the operation has a side effect, invalidate and delete the
+ resultant value */
+ if (code->vflag && code->valid)
+ { code->valid = 0;
+ delete_value(mpl, code->type, &code->value);
+ }
+ /* if resultant value is valid, no evaluation is needed */
+ if (code->valid)
+ { value = copy_formula(mpl, code->value.form);
+ goto done;
+ }
+ /* evaluate pseudo-code recursively */
+ switch (code->op)
+ { case O_MEMVAR:
+ /* take member of variable */
+ { TUPLE *tuple;
+ ARG_LIST *e;
+ tuple = create_tuple(mpl);
+ for (e = code->arg.var.list; e != NULL; e = e->next)
+ tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+ e->x));
+#if 1 /* 15/V-2010 */
+ xassert(code->arg.var.suff == DOT_NONE);
+#endif
+ value = single_variable(mpl,
+ eval_member_var(mpl, code->arg.var.var, tuple));
+ delete_tuple(mpl, tuple);
+ }
+ break;
+ case O_CVTLFM:
+ /* convert to linear form */
+ value = constant_term(mpl, eval_numeric(mpl,
+ code->arg.arg.x));
+ break;
+ case O_PLUS:
+ /* unary plus */
+ value = linear_comb(mpl,
+ 0.0, constant_term(mpl, 0.0),
+ +1.0, eval_formula(mpl, code->arg.arg.x));
+ break;
+ case O_MINUS:
+ /* unary minus */
+ value = linear_comb(mpl,
+ 0.0, constant_term(mpl, 0.0),
+ -1.0, eval_formula(mpl, code->arg.arg.x));
+ break;
+ case O_ADD:
+ /* addition */
+ value = linear_comb(mpl,
+ +1.0, eval_formula(mpl, code->arg.arg.x),
+ +1.0, eval_formula(mpl, code->arg.arg.y));
+ break;
+ case O_SUB:
+ /* subtraction */
+ value = linear_comb(mpl,
+ +1.0, eval_formula(mpl, code->arg.arg.x),
+ -1.0, eval_formula(mpl, code->arg.arg.y));
+ break;
+ case O_MUL:
+ /* multiplication */
+ xassert(code->arg.arg.x != NULL);
+ xassert(code->arg.arg.y != NULL);
+ if (code->arg.arg.x->type == A_NUMERIC)
+ { xassert(code->arg.arg.y->type == A_FORMULA);
+ value = linear_comb(mpl,
+ eval_numeric(mpl, code->arg.arg.x),
+ eval_formula(mpl, code->arg.arg.y),
+ 0.0, constant_term(mpl, 0.0));
+ }
+ else
+ { xassert(code->arg.arg.x->type == A_FORMULA);
+ xassert(code->arg.arg.y->type == A_NUMERIC);
+ value = linear_comb(mpl,
+ eval_numeric(mpl, code->arg.arg.y),
+ eval_formula(mpl, code->arg.arg.x),
+ 0.0, constant_term(mpl, 0.0));
+ }
+ break;
+ case O_DIV:
+ /* division */
+ value = linear_comb(mpl,
+ fp_div(mpl, 1.0, eval_numeric(mpl, code->arg.arg.y)),
+ eval_formula(mpl, code->arg.arg.x),
+ 0.0, constant_term(mpl, 0.0));
+ break;
+ case O_FORK:
+ /* if-then-else */
+ if (eval_logical(mpl, code->arg.arg.x))
+ value = eval_formula(mpl, code->arg.arg.y);
+ else if (code->arg.arg.z == NULL)
+ value = constant_term(mpl, 0.0);
+ else
+ value = eval_formula(mpl, code->arg.arg.z);
+ break;
+ case O_SUM:
+ /* summation over domain */
+ { struct iter_form_info _info, *info = &_info;
+ info->code = code;
+ info->value = constant_term(mpl, 0.0);
+ info->tail = NULL;
+ loop_within_domain(mpl, code->arg.loop.domain, info,
+ iter_form_func);
+ value = reduce_terms(mpl, info->value);
+ }
+ break;
+ default:
+ xassert(code != code);
+ }
+ /* save resultant value */
+ xassert(!code->valid);
+ code->valid = 1;
+ code->value.form = copy_formula(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- clean_code - clean pseudo-code.
+--
+-- This routine recursively cleans specified pseudo-code that assumes
+-- deleting all temporary resultant values. */
+
+void clean_code(MPL *mpl, CODE *code)
+{ ARG_LIST *e;
+ /* if no pseudo-code is specified, do nothing */
+ if (code == NULL) goto done;
+ /* if resultant value is valid (exists), delete it */
+ if (code->valid)
+ { code->valid = 0;
+ delete_value(mpl, code->type, &code->value);
+ }
+ /* recursively clean pseudo-code for operands */
+ switch (code->op)
+ { case O_NUMBER:
+ case O_STRING:
+ case O_INDEX:
+ break;
+ case O_MEMNUM:
+ case O_MEMSYM:
+ for (e = code->arg.par.list; e != NULL; e = e->next)
+ clean_code(mpl, e->x);
+ break;
+ case O_MEMSET:
+ for (e = code->arg.set.list; e != NULL; e = e->next)
+ clean_code(mpl, e->x);
+ break;
+ case O_MEMVAR:
+ for (e = code->arg.var.list; e != NULL; e = e->next)
+ clean_code(mpl, e->x);
+ break;
+#if 1 /* 15/V-2010 */
+ case O_MEMCON:
+ for (e = code->arg.con.list; e != NULL; e = e->next)
+ clean_code(mpl, e->x);
+ break;
+#endif
+ case O_TUPLE:
+ case O_MAKE:
+ for (e = code->arg.list; e != NULL; e = e->next)
+ clean_code(mpl, e->x);
+ break;
+ case O_SLICE:
+ xassert(code != code);
+ case O_IRAND224:
+ case O_UNIFORM01:
+ case O_NORMAL01:
+ case O_GMTIME:
+ break;
+ case O_CVTNUM:
+ case O_CVTSYM:
+ case O_CVTLOG:
+ case O_CVTTUP:
+ case O_CVTLFM:
+ case O_PLUS:
+ case O_MINUS:
+ case O_NOT:
+ case O_ABS:
+ case O_CEIL:
+ case O_FLOOR:
+ case O_EXP:
+ case O_LOG:
+ case O_LOG10:
+ case O_SQRT:
+ case O_SIN:
+ case O_COS:
+ case O_TAN:
+ case O_ATAN:
+ case O_ROUND:
+ case O_TRUNC:
+ case O_CARD:
+ case O_LENGTH:
+ /* unary operation */
+ clean_code(mpl, code->arg.arg.x);
+ break;
+ case O_ADD:
+ case O_SUB:
+ case O_LESS:
+ case O_MUL:
+ case O_DIV:
+ case O_IDIV:
+ case O_MOD:
+ case O_POWER:
+ case O_ATAN2:
+ case O_ROUND2:
+ case O_TRUNC2:
+ case O_UNIFORM:
+ case O_NORMAL:
+ case O_CONCAT:
+ case O_LT:
+ case O_LE:
+ case O_EQ:
+ case O_GE:
+ case O_GT:
+ case O_NE:
+ case O_AND:
+ case O_OR:
+ case O_UNION:
+ case O_DIFF:
+ case O_SYMDIFF:
+ case O_INTER:
+ case O_CROSS:
+ case O_IN:
+ case O_NOTIN:
+ case O_WITHIN:
+ case O_NOTWITHIN:
+ case O_SUBSTR:
+ case O_STR2TIME:
+ case O_TIME2STR:
+ /* binary operation */
+ clean_code(mpl, code->arg.arg.x);
+ clean_code(mpl, code->arg.arg.y);
+ break;
+ case O_DOTS:
+ case O_FORK:
+ case O_SUBSTR3:
+ /* ternary operation */
+ clean_code(mpl, code->arg.arg.x);
+ clean_code(mpl, code->arg.arg.y);
+ clean_code(mpl, code->arg.arg.z);
+ break;
+ case O_MIN:
+ case O_MAX:
+ /* n-ary operation */
+ for (e = code->arg.list; e != NULL; e = e->next)
+ clean_code(mpl, e->x);
+ break;
+ case O_SUM:
+ case O_PROD:
+ case O_MINIMUM:
+ case O_MAXIMUM:
+ case O_FORALL:
+ case O_EXISTS:
+ case O_SETOF:
+ case O_BUILD:
+ /* iterated operation */
+ clean_domain(mpl, code->arg.loop.domain);
+ clean_code(mpl, code->arg.loop.x);
+ break;
+ default:
+ xassert(code->op != code->op);
+ }
+done: return;
+}
+
+#if 1 /* 11/II-2008 */
+/**********************************************************************/
+/* * * DATA TABLES * * */
+/**********************************************************************/
+
+int mpl_tab_num_args(TABDCA *dca)
+{ /* returns the number of arguments */
+ return dca->na;
+}
+
+const char *mpl_tab_get_arg(TABDCA *dca, int k)
+{ /* returns pointer to k-th argument */
+ xassert(1 <= k && k <= dca->na);
+ return dca->arg[k];
+}
+
+int mpl_tab_num_flds(TABDCA *dca)
+{ /* returns the number of fields */
+ return dca->nf;
+}
+
+const char *mpl_tab_get_name(TABDCA *dca, int k)
+{ /* returns pointer to name of k-th field */
+ xassert(1 <= k && k <= dca->nf);
+ return dca->name[k];
+}
+
+int mpl_tab_get_type(TABDCA *dca, int k)
+{ /* returns type of k-th field */
+ xassert(1 <= k && k <= dca->nf);
+ return dca->type[k];
+}
+
+double mpl_tab_get_num(TABDCA *dca, int k)
+{ /* returns numeric value of k-th field */
+ xassert(1 <= k && k <= dca->nf);
+ xassert(dca->type[k] == 'N');
+ return dca->num[k];
+}
+
+const char *mpl_tab_get_str(TABDCA *dca, int k)
+{ /* returns pointer to string value of k-th field */
+ xassert(1 <= k && k <= dca->nf);
+ xassert(dca->type[k] == 'S');
+ xassert(dca->str[k] != NULL);
+ return dca->str[k];
+}
+
+void mpl_tab_set_num(TABDCA *dca, int k, double num)
+{ /* assign numeric value to k-th field */
+ xassert(1 <= k && k <= dca->nf);
+ xassert(dca->type[k] == '?');
+ dca->type[k] = 'N';
+ dca->num[k] = num;
+ return;
+}
+
+void mpl_tab_set_str(TABDCA *dca, int k, const char *str)
+{ /* assign string value to k-th field */
+ xassert(1 <= k && k <= dca->nf);
+ xassert(dca->type[k] == '?');
+ xassert(strlen(str) <= MAX_LENGTH);
+ xassert(dca->str[k] != NULL);
+ dca->type[k] = 'S';
+ strcpy(dca->str[k], str);
+ return;
+}
+
+static int write_func(MPL *mpl, void *info)
+{ /* this is auxiliary routine to work within domain scope */
+ TABLE *tab = info;
+ TABDCA *dca = mpl->dca;
+ TABOUT *out;
+ SYMBOL *sym;
+ int k;
+ char buf[MAX_LENGTH+1];
+ /* evaluate field values */
+ k = 0;
+ for (out = tab->u.out.list; out != NULL; out = out->next)
+ { k++;
+ switch (out->code->type)
+ { case A_NUMERIC:
+ dca->type[k] = 'N';
+ dca->num[k] = eval_numeric(mpl, out->code);
+ dca->str[k][0] = '\0';
+ break;
+ case A_SYMBOLIC:
+ sym = eval_symbolic(mpl, out->code);
+ if (sym->str == NULL)
+ { dca->type[k] = 'N';
+ dca->num[k] = sym->num;
+ dca->str[k][0] = '\0';
+ }
+ else
+ { dca->type[k] = 'S';
+ dca->num[k] = 0.0;
+ fetch_string(mpl, sym->str, buf);
+ strcpy(dca->str[k], buf);
+ }
+ delete_symbol(mpl, sym);
+ break;
+ default:
+ xassert(out != out);
+ }
+ }
+ /* write record to output table */
+ mpl_tab_drv_write(mpl);
+ return 0;
+}
+
+void execute_table(MPL *mpl, TABLE *tab)
+{ /* execute table statement */
+ TABARG *arg;
+ TABFLD *fld;
+ TABIN *in;
+ TABOUT *out;
+ TABDCA *dca;
+ SET *set;
+ int k;
+ char buf[MAX_LENGTH+1];
+ /* allocate table driver communication area */
+ xassert(mpl->dca == NULL);
+ mpl->dca = dca = xmalloc(sizeof(TABDCA));
+ dca->id = 0;
+ dca->link = NULL;
+ dca->na = 0;
+ dca->arg = NULL;
+ dca->nf = 0;
+ dca->name = NULL;
+ dca->type = NULL;
+ dca->num = NULL;
+ dca->str = NULL;
+ /* allocate arguments */
+ xassert(dca->na == 0);
+ for (arg = tab->arg; arg != NULL; arg = arg->next)
+ dca->na++;
+ dca->arg = xcalloc(1+dca->na, sizeof(char *));
+#if 1 /* 28/IX-2008 */
+ for (k = 1; k <= dca->na; k++) dca->arg[k] = NULL;
+#endif
+ /* evaluate argument values */
+ k = 0;
+ for (arg = tab->arg; arg != NULL; arg = arg->next)
+ { SYMBOL *sym;
+ k++;
+ xassert(arg->code->type == A_SYMBOLIC);
+ sym = eval_symbolic(mpl, arg->code);
+ if (sym->str == NULL)
+ sprintf(buf, "%.*g", DBL_DIG, sym->num);
+ else
+ fetch_string(mpl, sym->str, buf);
+ delete_symbol(mpl, sym);
+ dca->arg[k] = xmalloc(strlen(buf)+1);
+ strcpy(dca->arg[k], buf);
+ }
+ /* perform table input/output */
+ switch (tab->type)
+ { case A_INPUT: goto read_table;
+ case A_OUTPUT: goto write_table;
+ default: xassert(tab != tab);
+ }
+read_table:
+ /* read data from input table */
+ /* add the only member to the control set and assign it empty
+ elemental set */
+ set = tab->u.in.set;
+ if (set != NULL)
+ { if (set->data)
+ error(mpl, "%s already provided with data", set->name);
+ xassert(set->array->head == NULL);
+ add_member(mpl, set->array, NULL)->value.set =
+ create_elemset(mpl, set->dimen);
+ set->data = 1;
+ }
+ /* check parameters specified in the input list */
+ for (in = tab->u.in.list; in != NULL; in = in->next)
+ { if (in->par->data)
+ error(mpl, "%s already provided with data", in->par->name);
+ in->par->data = 1;
+ }
+ /* allocate and initialize fields */
+ xassert(dca->nf == 0);
+ for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
+ dca->nf++;
+ for (in = tab->u.in.list; in != NULL; in = in->next)
+ dca->nf++;
+ dca->name = xcalloc(1+dca->nf, sizeof(char *));
+ dca->type = xcalloc(1+dca->nf, sizeof(int));
+ dca->num = xcalloc(1+dca->nf, sizeof(double));
+ dca->str = xcalloc(1+dca->nf, sizeof(char *));
+ k = 0;
+ for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
+ { k++;
+ dca->name[k] = fld->name;
+ dca->type[k] = '?';
+ dca->num[k] = 0.0;
+ dca->str[k] = xmalloc(MAX_LENGTH+1);
+ dca->str[k][0] = '\0';
+ }
+ for (in = tab->u.in.list; in != NULL; in = in->next)
+ { k++;
+ dca->name[k] = in->name;
+ dca->type[k] = '?';
+ dca->num[k] = 0.0;
+ dca->str[k] = xmalloc(MAX_LENGTH+1);
+ dca->str[k][0] = '\0';
+ }
+ /* open input table */
+ mpl_tab_drv_open(mpl, 'R');
+ /* read and process records */
+ for (;;)
+ { TUPLE *tup;
+ /* reset field types */
+ for (k = 1; k <= dca->nf; k++)
+ dca->type[k] = '?';
+ /* read next record */
+ if (mpl_tab_drv_read(mpl)) break;
+ /* all fields must be set by the driver */
+ for (k = 1; k <= dca->nf; k++)
+ { if (dca->type[k] == '?')
+ error(mpl, "field %s missing in input table",
+ dca->name[k]);
+ }
+ /* construct n-tuple */
+ tup = create_tuple(mpl);
+ k = 0;
+ for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
+ { k++;
+ xassert(k <= dca->nf);
+ switch (dca->type[k])
+ { case 'N':
+ tup = expand_tuple(mpl, tup, create_symbol_num(mpl,
+ dca->num[k]));
+ break;
+ case 'S':
+ xassert(strlen(dca->str[k]) <= MAX_LENGTH);
+ tup = expand_tuple(mpl, tup, create_symbol_str(mpl,
+ create_string(mpl, dca->str[k])));
+ break;
+ default:
+ xassert(dca != dca);
+ }
+ }
+ /* add n-tuple just read to the control set */
+ if (tab->u.in.set != NULL)
+ check_then_add(mpl, tab->u.in.set->array->head->value.set,
+ copy_tuple(mpl, tup));
+ /* assign values to the parameters in the input list */
+ for (in = tab->u.in.list; in != NULL; in = in->next)
+ { MEMBER *memb;
+ k++;
+ xassert(k <= dca->nf);
+ /* there must be no member with the same n-tuple */
+ if (find_member(mpl, in->par->array, tup) != NULL)
+ error(mpl, "%s%s already defined", in->par->name,
+ format_tuple(mpl, '[', tup));
+ /* create new parameter member with given n-tuple */
+ memb = add_member(mpl, in->par->array, copy_tuple(mpl, tup))
+ ;
+ /* assign value to the parameter member */
+ switch (in->par->type)
+ { case A_NUMERIC:
+ case A_INTEGER:
+ case A_BINARY:
+ if (dca->type[k] != 'N')
+ error(mpl, "%s requires numeric data",
+ in->par->name);
+ memb->value.num = dca->num[k];
+ break;
+ case A_SYMBOLIC:
+ switch (dca->type[k])
+ { case 'N':
+ memb->value.sym = create_symbol_num(mpl,
+ dca->num[k]);
+ break;
+ case 'S':
+ xassert(strlen(dca->str[k]) <= MAX_LENGTH);
+ memb->value.sym = create_symbol_str(mpl,
+ create_string(mpl,dca->str[k]));
+ break;
+ default:
+ xassert(dca != dca);
+ }
+ break;
+ default:
+ xassert(in != in);
+ }
+ }
+ /* n-tuple is no more needed */
+ delete_tuple(mpl, tup);
+ }
+ /* close input table */
+ mpl_tab_drv_close(mpl);
+ goto done;
+write_table:
+ /* write data to output table */
+ /* allocate and initialize fields */
+ xassert(dca->nf == 0);
+ for (out = tab->u.out.list; out != NULL; out = out->next)
+ dca->nf++;
+ dca->name = xcalloc(1+dca->nf, sizeof(char *));
+ dca->type = xcalloc(1+dca->nf, sizeof(int));
+ dca->num = xcalloc(1+dca->nf, sizeof(double));
+ dca->str = xcalloc(1+dca->nf, sizeof(char *));
+ k = 0;
+ for (out = tab->u.out.list; out != NULL; out = out->next)
+ { k++;
+ dca->name[k] = out->name;
+ dca->type[k] = '?';
+ dca->num[k] = 0.0;
+ dca->str[k] = xmalloc(MAX_LENGTH+1);
+ dca->str[k][0] = '\0';
+ }
+ /* open output table */
+ mpl_tab_drv_open(mpl, 'W');
+ /* evaluate fields and write records */
+ loop_within_domain(mpl, tab->u.out.domain, tab, write_func);
+ /* close output table */
+ mpl_tab_drv_close(mpl);
+done: /* free table driver communication area */
+ free_dca(mpl);
+ return;
+}
+
+void free_dca(MPL *mpl)
+{ /* free table driver communucation area */
+ TABDCA *dca = mpl->dca;
+ int k;
+ if (dca != NULL)
+ { if (dca->link != NULL)
+ mpl_tab_drv_close(mpl);
+ if (dca->arg != NULL)
+ { for (k = 1; k <= dca->na; k++)
+#if 1 /* 28/IX-2008 */
+ if (dca->arg[k] != NULL)
+#endif
+ xfree(dca->arg[k]);
+ xfree(dca->arg);
+ }
+ if (dca->name != NULL) xfree(dca->name);
+ if (dca->type != NULL) xfree(dca->type);
+ if (dca->num != NULL) xfree(dca->num);
+ if (dca->str != NULL)
+ { for (k = 1; k <= dca->nf; k++)
+ xfree(dca->str[k]);
+ xfree(dca->str);
+ }
+ xfree(dca), mpl->dca = NULL;
+ }
+ return;
+}
+
+void clean_table(MPL *mpl, TABLE *tab)
+{ /* clean table statement */
+ TABARG *arg;
+ TABOUT *out;
+ /* clean string list */
+ for (arg = tab->arg; arg != NULL; arg = arg->next)
+ clean_code(mpl, arg->code);
+ switch (tab->type)
+ { case A_INPUT:
+ break;
+ case A_OUTPUT:
+ /* clean subscript domain */
+ clean_domain(mpl, tab->u.out.domain);
+ /* clean output list */
+ for (out = tab->u.out.list; out != NULL; out = out->next)
+ clean_code(mpl, out->code);
+ break;
+ default:
+ xassert(tab != tab);
+ }
+ return;
+}
+#endif
+
+/**********************************************************************/
+/* * * MODEL STATEMENTS * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- execute_check - execute check statement.
+--
+-- This routine executes specified check statement. */
+
+static int check_func(MPL *mpl, void *info)
+{ /* this is auxiliary routine to work within domain scope */
+ CHECK *chk = (CHECK *)info;
+ if (!eval_logical(mpl, chk->code))
+ error(mpl, "check%s failed", format_tuple(mpl, '[',
+ get_domain_tuple(mpl, chk->domain)));
+ return 0;
+}
+
+void execute_check(MPL *mpl, CHECK *chk)
+{ loop_within_domain(mpl, chk->domain, chk, check_func);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_check - clean check statement.
+--
+-- This routine cleans specified check statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_check(MPL *mpl, CHECK *chk)
+{ /* clean subscript domain */
+ clean_domain(mpl, chk->domain);
+ /* clean pseudo-code for computing predicate */
+ clean_code(mpl, chk->code);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_display - execute display statement.
+--
+-- This routine executes specified display statement. */
+
+static void display_set(MPL *mpl, SET *set, MEMBER *memb)
+{ /* display member of model set */
+ ELEMSET *s = memb->value.set;
+ MEMBER *m;
+ write_text(mpl, "%s%s%s\n", set->name,
+ format_tuple(mpl, '[', memb->tuple),
+ s->head == NULL ? " is empty" : ":");
+ for (m = s->head; m != NULL; m = m->next)
+ write_text(mpl, " %s\n", format_tuple(mpl, '(', m->tuple));
+ return;
+}
+
+static void display_par(MPL *mpl, PARAMETER *par, MEMBER *memb)
+{ /* display member of model parameter */
+ switch (par->type)
+ { case A_NUMERIC:
+ case A_INTEGER:
+ case A_BINARY:
+ write_text(mpl, "%s%s = %.*g\n", par->name,
+ format_tuple(mpl, '[', memb->tuple),
+ DBL_DIG, memb->value.num);
+ break;
+ case A_SYMBOLIC:
+ write_text(mpl, "%s%s = %s\n", par->name,
+ format_tuple(mpl, '[', memb->tuple),
+ format_symbol(mpl, memb->value.sym));
+ break;
+ default:
+ xassert(par != par);
+ }
+ return;
+}
+
+#if 1 /* 15/V-2010 */
+static void display_var(MPL *mpl, VARIABLE *var, MEMBER *memb,
+ int suff)
+{ /* display member of model variable */
+ if (suff == DOT_NONE || suff == DOT_VAL)
+ write_text(mpl, "%s%s.val = %.*g\n", var->name,
+ format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+ memb->value.var->prim);
+ else if (suff == DOT_LB)
+ write_text(mpl, "%s%s.lb = %.*g\n", var->name,
+ format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+ memb->value.var->var->lbnd == NULL ? -DBL_MAX :
+ memb->value.var->lbnd);
+ else if (suff == DOT_UB)
+ write_text(mpl, "%s%s.ub = %.*g\n", var->name,
+ format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+ memb->value.var->var->ubnd == NULL ? +DBL_MAX :
+ memb->value.var->ubnd);
+ else if (suff == DOT_STATUS)
+ write_text(mpl, "%s%s.status = %d\n", var->name, format_tuple
+ (mpl, '[', memb->tuple), memb->value.var->stat);
+ else if (suff == DOT_DUAL)
+ write_text(mpl, "%s%s.dual = %.*g\n", var->name,
+ format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+ memb->value.var->dual);
+ else
+ xassert(suff != suff);
+ return;
+}
+#endif
+
+#if 1 /* 15/V-2010 */
+static void display_con(MPL *mpl, CONSTRAINT *con, MEMBER *memb,
+ int suff)
+{ /* display member of model constraint */
+ if (suff == DOT_NONE || suff == DOT_VAL)
+ write_text(mpl, "%s%s.val = %.*g\n", con->name,
+ format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+ memb->value.con->prim);
+ else if (suff == DOT_LB)
+ write_text(mpl, "%s%s.lb = %.*g\n", con->name,
+ format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+ memb->value.con->con->lbnd == NULL ? -DBL_MAX :
+ memb->value.con->lbnd);
+ else if (suff == DOT_UB)
+ write_text(mpl, "%s%s.ub = %.*g\n", con->name,
+ format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+ memb->value.con->con->ubnd == NULL ? +DBL_MAX :
+ memb->value.con->ubnd);
+ else if (suff == DOT_STATUS)
+ write_text(mpl, "%s%s.status = %d\n", con->name, format_tuple
+ (mpl, '[', memb->tuple), memb->value.con->stat);
+ else if (suff == DOT_DUAL)
+ write_text(mpl, "%s%s.dual = %.*g\n", con->name,
+ format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+ memb->value.con->dual);
+ else
+ xassert(suff != suff);
+ return;
+}
+#endif
+
+static void display_memb(MPL *mpl, CODE *code)
+{ /* display member specified by pseudo-code */
+ MEMBER memb;
+ ARG_LIST *e;
+ xassert(code->op == O_MEMNUM || code->op == O_MEMSYM
+ || code->op == O_MEMSET || code->op == O_MEMVAR
+ || code->op == O_MEMCON);
+ memb.tuple = create_tuple(mpl);
+ for (e = code->arg.par.list; e != NULL; e = e->next)
+ memb.tuple = expand_tuple(mpl, memb.tuple, eval_symbolic(mpl,
+ e->x));
+ switch (code->op)
+ { case O_MEMNUM:
+ memb.value.num = eval_member_num(mpl, code->arg.par.par,
+ memb.tuple);
+ display_par(mpl, code->arg.par.par, &memb);
+ break;
+ case O_MEMSYM:
+ memb.value.sym = eval_member_sym(mpl, code->arg.par.par,
+ memb.tuple);
+ display_par(mpl, code->arg.par.par, &memb);
+ delete_symbol(mpl, memb.value.sym);
+ break;
+ case O_MEMSET:
+ memb.value.set = eval_member_set(mpl, code->arg.set.set,
+ memb.tuple);
+ display_set(mpl, code->arg.set.set, &memb);
+ break;
+ case O_MEMVAR:
+ memb.value.var = eval_member_var(mpl, code->arg.var.var,
+ memb.tuple);
+ display_var
+ (mpl, code->arg.var.var, &memb, code->arg.var.suff);
+ break;
+ case O_MEMCON:
+ memb.value.con = eval_member_con(mpl, code->arg.con.con,
+ memb.tuple);
+ display_con
+ (mpl, code->arg.con.con, &memb, code->arg.con.suff);
+ break;
+ default:
+ xassert(code != code);
+ }
+ delete_tuple(mpl, memb.tuple);
+ return;
+}
+
+static void display_code(MPL *mpl, CODE *code)
+{ /* display value of expression */
+ switch (code->type)
+ { case A_NUMERIC:
+ /* numeric value */
+ { double num;
+ num = eval_numeric(mpl, code);
+ write_text(mpl, "%.*g\n", DBL_DIG, num);
+ }
+ break;
+ case A_SYMBOLIC:
+ /* symbolic value */
+ { SYMBOL *sym;
+ sym = eval_symbolic(mpl, code);
+ write_text(mpl, "%s\n", format_symbol(mpl, sym));
+ delete_symbol(mpl, sym);
+ }
+ break;
+ case A_LOGICAL:
+ /* logical value */
+ { int bit;
+ bit = eval_logical(mpl, code);
+ write_text(mpl, "%s\n", bit ? "true" : "false");
+ }
+ break;
+ case A_TUPLE:
+ /* n-tuple */
+ { TUPLE *tuple;
+ tuple = eval_tuple(mpl, code);
+ write_text(mpl, "%s\n", format_tuple(mpl, '(', tuple));
+ delete_tuple(mpl, tuple);
+ }
+ break;
+ case A_ELEMSET:
+ /* elemental set */
+ { ELEMSET *set;
+ MEMBER *memb;
+ set = eval_elemset(mpl, code);
+ if (set->head == 0)
+ write_text(mpl, "set is empty\n");
+ for (memb = set->head; memb != NULL; memb = memb->next)
+ write_text(mpl, " %s\n", format_tuple(mpl, '(',
+ memb->tuple));
+ delete_elemset(mpl, set);
+ }
+ break;
+ case A_FORMULA:
+ /* linear form */
+ { FORMULA *form, *term;
+ form = eval_formula(mpl, code);
+ if (form == NULL)
+ write_text(mpl, "linear form is empty\n");
+ for (term = form; term != NULL; term = term->next)
+ { if (term->var == NULL)
+ write_text(mpl, " %.*g\n", term->coef);
+ else
+ write_text(mpl, " %.*g %s%s\n", DBL_DIG,
+ term->coef, term->var->var->name,
+ format_tuple(mpl, '[', term->var->memb->tuple));
+ }
+ delete_formula(mpl, form);
+ }
+ break;
+ default:
+ xassert(code != code);
+ }
+ return;
+}
+
+static int display_func(MPL *mpl, void *info)
+{ /* this is auxiliary routine to work within domain scope */
+ DISPLAY *dpy = (DISPLAY *)info;
+ DISPLAY1 *entry;
+ for (entry = dpy->list; entry != NULL; entry = entry->next)
+ { if (entry->type == A_INDEX)
+ { /* dummy index */
+ DOMAIN_SLOT *slot = entry->u.slot;
+ write_text(mpl, "%s = %s\n", slot->name,
+ format_symbol(mpl, slot->value));
+ }
+ else if (entry->type == A_SET)
+ { /* model set */
+ SET *set = entry->u.set;
+ MEMBER *memb;
+ if (set->assign != NULL)
+ { /* the set has assignment expression; evaluate all its
+ members over entire domain */
+ eval_whole_set(mpl, set);
+ }
+ else
+ { /* the set has no assignment expression; refer to its
+ any existing member ignoring resultant value to check
+ the data provided the data section */
+#if 1 /* 12/XII-2008 */
+ if (set->gadget != NULL && set->data == 0)
+ { /* initialize the set with data from a plain set */
+ saturate_set(mpl, set);
+ }
+#endif
+ if (set->array->head != NULL)
+ eval_member_set(mpl, set, set->array->head->tuple);
+ }
+ /* display all members of the set array */
+ if (set->array->head == NULL)
+ write_text(mpl, "%s has empty content\n", set->name);
+ for (memb = set->array->head; memb != NULL; memb =
+ memb->next) display_set(mpl, set, memb);
+ }
+ else if (entry->type == A_PARAMETER)
+ { /* model parameter */
+ PARAMETER *par = entry->u.par;
+ MEMBER *memb;
+ if (par->assign != NULL)
+ { /* the parameter has an assignment expression; evaluate
+ all its member over entire domain */
+ eval_whole_par(mpl, par);
+ }
+ else
+ { /* the parameter has no assignment expression; refer to
+ its any existing member ignoring resultant value to
+ check the data provided in the data section */
+ if (par->array->head != NULL)
+ { if (par->type != A_SYMBOLIC)
+ eval_member_num(mpl, par, par->array->head->tuple);
+ else
+ delete_symbol(mpl, eval_member_sym(mpl, par,
+ par->array->head->tuple));
+ }
+ }
+ /* display all members of the parameter array */
+ if (par->array->head == NULL)
+ write_text(mpl, "%s has empty content\n", par->name);
+ for (memb = par->array->head; memb != NULL; memb =
+ memb->next) display_par(mpl, par, memb);
+ }
+ else if (entry->type == A_VARIABLE)
+ { /* model variable */
+ VARIABLE *var = entry->u.var;
+ MEMBER *memb;
+ xassert(mpl->flag_p);
+ /* display all members of the variable array */
+ if (var->array->head == NULL)
+ write_text(mpl, "%s has empty content\n", var->name);
+ for (memb = var->array->head; memb != NULL; memb =
+ memb->next) display_var(mpl, var, memb, DOT_NONE);
+ }
+ else if (entry->type == A_CONSTRAINT)
+ { /* model constraint */
+ CONSTRAINT *con = entry->u.con;
+ MEMBER *memb;
+ xassert(mpl->flag_p);
+ /* display all members of the constraint array */
+ if (con->array->head == NULL)
+ write_text(mpl, "%s has empty content\n", con->name);
+ for (memb = con->array->head; memb != NULL; memb =
+ memb->next) display_con(mpl, con, memb, DOT_NONE);
+ }
+ else if (entry->type == A_EXPRESSION)
+ { /* expression */
+ CODE *code = entry->u.code;
+ if (code->op == O_MEMNUM || code->op == O_MEMSYM ||
+ code->op == O_MEMSET || code->op == O_MEMVAR ||
+ code->op == O_MEMCON)
+ display_memb(mpl, code);
+ else
+ display_code(mpl, code);
+ }
+ else
+ xassert(entry != entry);
+ }
+ return 0;
+}
+
+void execute_display(MPL *mpl, DISPLAY *dpy)
+{ loop_within_domain(mpl, dpy->domain, dpy, display_func);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_display - clean display statement.
+--
+-- This routine cleans specified display statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_display(MPL *mpl, DISPLAY *dpy)
+{ DISPLAY1 *d;
+#if 0 /* 15/V-2010 */
+ ARG_LIST *e;
+#endif
+ /* clean subscript domain */
+ clean_domain(mpl, dpy->domain);
+ /* clean display list */
+ for (d = dpy->list; d != NULL; d = d->next)
+ { /* clean pseudo-code for computing expression */
+ if (d->type == A_EXPRESSION)
+ clean_code(mpl, d->u.code);
+#if 0 /* 15/V-2010 */
+ /* clean pseudo-code for computing subscripts */
+ for (e = d->list; e != NULL; e = e->next)
+ clean_code(mpl, e->x);
+#endif
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_printf - execute printf statement.
+--
+-- This routine executes specified printf statement. */
+
+#if 1 /* 14/VII-2006 */
+static void print_char(MPL *mpl, int c)
+{ if (mpl->prt_fp == NULL)
+ write_char(mpl, c);
+ else
+#if 0 /* 04/VIII-2013 */
+ xfputc(c, mpl->prt_fp);
+#else
+ { unsigned char buf[1];
+ buf[0] = (unsigned char)c;
+ glp_write(mpl->prt_fp, buf, 1);
+ }
+#endif
+ return;
+}
+
+static void print_text(MPL *mpl, char *fmt, ...)
+{ va_list arg;
+ char buf[OUTBUF_SIZE], *c;
+ va_start(arg, fmt);
+ vsprintf(buf, fmt, arg);
+ xassert(strlen(buf) < sizeof(buf));
+ va_end(arg);
+ for (c = buf; *c != '\0'; c++) print_char(mpl, *c);
+ return;
+}
+#endif
+
+static int printf_func(MPL *mpl, void *info)
+{ /* this is auxiliary routine to work within domain scope */
+ PRINTF *prt = (PRINTF *)info;
+ PRINTF1 *entry;
+ SYMBOL *sym;
+ char fmt[MAX_LENGTH+1], *c, *from, save;
+ /* evaluate format control string */
+ sym = eval_symbolic(mpl, prt->fmt);
+ if (sym->str == NULL)
+ sprintf(fmt, "%.*g", DBL_DIG, sym->num);
+ else
+ fetch_string(mpl, sym->str, fmt);
+ delete_symbol(mpl, sym);
+ /* scan format control string and perform formatting output */
+ entry = prt->list;
+ for (c = fmt; *c != '\0'; c++)
+ { if (*c == '%')
+ { /* scan format specifier */
+ from = c++;
+ if (*c == '%')
+ { print_char(mpl, '%');
+ continue;
+ }
+ if (entry == NULL) break;
+ /* scan optional flags */
+ while (*c == '-' || *c == '+' || *c == ' ' || *c == '#' ||
+ *c == '0') c++;
+ /* scan optional minimum field width */
+ while (isdigit((unsigned char)*c)) c++;
+ /* scan optional precision */
+ if (*c == '.')
+ { c++;
+ while (isdigit((unsigned char)*c)) c++;
+ }
+ /* scan conversion specifier and perform formatting */
+ save = *(c+1), *(c+1) = '\0';
+ if (*c == 'd' || *c == 'i' || *c == 'e' || *c == 'E' ||
+ *c == 'f' || *c == 'F' || *c == 'g' || *c == 'G')
+ { /* the specifier requires numeric value */
+ double value;
+ xassert(entry != NULL);
+ switch (entry->code->type)
+ { case A_NUMERIC:
+ value = eval_numeric(mpl, entry->code);
+ break;
+ case A_SYMBOLIC:
+ sym = eval_symbolic(mpl, entry->code);
+ if (sym->str != NULL)
+ error(mpl, "cannot convert %s to floating-point"
+ " number", format_symbol(mpl, sym));
+ value = sym->num;
+ delete_symbol(mpl, sym);
+ break;
+ case A_LOGICAL:
+ if (eval_logical(mpl, entry->code))
+ value = 1.0;
+ else
+ value = 0.0;
+ break;
+ default:
+ xassert(entry != entry);
+ }
+ if (*c == 'd' || *c == 'i')
+ { double int_max = (double)INT_MAX;
+ if (!(-int_max <= value && value <= +int_max))
+ error(mpl, "cannot convert %.*g to integer",
+ DBL_DIG, value);
+ print_text(mpl, from, (int)floor(value + 0.5));
+ }
+ else
+ print_text(mpl, from, value);
+ }
+ else if (*c == 's')
+ { /* the specifier requires symbolic value */
+ char value[MAX_LENGTH+1];
+ switch (entry->code->type)
+ { case A_NUMERIC:
+ sprintf(value, "%.*g", DBL_DIG, eval_numeric(mpl,
+ entry->code));
+ break;
+ case A_LOGICAL:
+ if (eval_logical(mpl, entry->code))
+ strcpy(value, "T");
+ else
+ strcpy(value, "F");
+ break;
+ case A_SYMBOLIC:
+ sym = eval_symbolic(mpl, entry->code);
+ if (sym->str == NULL)
+ sprintf(value, "%.*g", DBL_DIG, sym->num);
+ else
+ fetch_string(mpl, sym->str, value);
+ delete_symbol(mpl, sym);
+ break;
+ default:
+ xassert(entry != entry);
+ }
+ print_text(mpl, from, value);
+ }
+ else
+ error(mpl, "format specifier missing or invalid");
+ *(c+1) = save;
+ entry = entry->next;
+ }
+ else if (*c == '\\')
+ { /* write some control character */
+ c++;
+ if (*c == 't')
+ print_char(mpl, '\t');
+ else if (*c == 'n')
+ print_char(mpl, '\n');
+#if 1 /* 28/X-2010 */
+ else if (*c == '\0')
+ { /* format string ends with backslash */
+ error(mpl, "invalid use of escape character \\ in format"
+ " control string");
+ }
+#endif
+ else
+ print_char(mpl, *c);
+ }
+ else
+ { /* write character without formatting */
+ print_char(mpl, *c);
+ }
+ }
+ return 0;
+}
+
+#if 0 /* 14/VII-2006 */
+void execute_printf(MPL *mpl, PRINTF *prt)
+{ loop_within_domain(mpl, prt->domain, prt, printf_func);
+ return;
+}
+#else
+void execute_printf(MPL *mpl, PRINTF *prt)
+{ if (prt->fname == NULL)
+ { /* switch to the standard output */
+ if (mpl->prt_fp != NULL)
+ { glp_close(mpl->prt_fp), mpl->prt_fp = NULL;
+ xfree(mpl->prt_file), mpl->prt_file = NULL;
+ }
+ }
+ else
+ { /* evaluate file name string */
+ SYMBOL *sym;
+ char fname[MAX_LENGTH+1];
+ sym = eval_symbolic(mpl, prt->fname);
+ if (sym->str == NULL)
+ sprintf(fname, "%.*g", DBL_DIG, sym->num);
+ else
+ fetch_string(mpl, sym->str, fname);
+ delete_symbol(mpl, sym);
+ /* close the current print file, if necessary */
+ if (mpl->prt_fp != NULL &&
+ (!prt->app || strcmp(mpl->prt_file, fname) != 0))
+ { glp_close(mpl->prt_fp), mpl->prt_fp = NULL;
+ xfree(mpl->prt_file), mpl->prt_file = NULL;
+ }
+ /* open the specified print file, if necessary */
+ if (mpl->prt_fp == NULL)
+ { mpl->prt_fp = glp_open(fname, prt->app ? "a" : "w");
+ if (mpl->prt_fp == NULL)
+ error(mpl, "unable to open '%s' for writing - %s",
+ fname, get_err_msg());
+ mpl->prt_file = xmalloc(strlen(fname)+1);
+ strcpy(mpl->prt_file, fname);
+ }
+ }
+ loop_within_domain(mpl, prt->domain, prt, printf_func);
+ if (mpl->prt_fp != NULL)
+ {
+#if 0 /* FIXME */
+ xfflush(mpl->prt_fp);
+#endif
+ if (glp_ioerr(mpl->prt_fp))
+ error(mpl, "writing error to '%s' - %s", mpl->prt_file,
+ get_err_msg());
+ }
+ return;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- clean_printf - clean printf statement.
+--
+-- This routine cleans specified printf statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_printf(MPL *mpl, PRINTF *prt)
+{ PRINTF1 *p;
+ /* clean subscript domain */
+ clean_domain(mpl, prt->domain);
+ /* clean pseudo-code for computing format string */
+ clean_code(mpl, prt->fmt);
+ /* clean printf list */
+ for (p = prt->list; p != NULL; p = p->next)
+ { /* clean pseudo-code for computing value to be printed */
+ clean_code(mpl, p->code);
+ }
+#if 1 /* 14/VII-2006 */
+ /* clean pseudo-code for computing file name string */
+ clean_code(mpl, prt->fname);
+#endif
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_for - execute for statement.
+--
+-- This routine executes specified for statement. */
+
+static int for_func(MPL *mpl, void *info)
+{ /* this is auxiliary routine to work within domain scope */
+ FOR *fur = (FOR *)info;
+ STATEMENT *stmt, *save;
+ save = mpl->stmt;
+ for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
+ execute_statement(mpl, stmt);
+ mpl->stmt = save;
+ return 0;
+}
+
+void execute_for(MPL *mpl, FOR *fur)
+{ loop_within_domain(mpl, fur->domain, fur, for_func);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_for - clean for statement.
+--
+-- This routine cleans specified for statement that assumes deleting all
+-- stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_for(MPL *mpl, FOR *fur)
+{ STATEMENT *stmt;
+ /* clean subscript domain */
+ clean_domain(mpl, fur->domain);
+ /* clean all sub-statements */
+ for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
+ clean_statement(mpl, stmt);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_statement - execute specified model statement.
+--
+-- This routine executes specified model statement. */
+
+void execute_statement(MPL *mpl, STATEMENT *stmt)
+{ mpl->stmt = stmt;
+ switch (stmt->type)
+ { case A_SET:
+ case A_PARAMETER:
+ case A_VARIABLE:
+ break;
+ case A_CONSTRAINT:
+ xprintf("Generating %s...\n", stmt->u.con->name);
+ eval_whole_con(mpl, stmt->u.con);
+ break;
+ case A_TABLE:
+ switch (stmt->u.tab->type)
+ { case A_INPUT:
+ xprintf("Reading %s...\n", stmt->u.tab->name);
+ break;
+ case A_OUTPUT:
+ xprintf("Writing %s...\n", stmt->u.tab->name);
+ break;
+ default:
+ xassert(stmt != stmt);
+ }
+ execute_table(mpl, stmt->u.tab);
+ break;
+ case A_SOLVE:
+ break;
+ case A_CHECK:
+ xprintf("Checking (line %d)...\n", stmt->line);
+ execute_check(mpl, stmt->u.chk);
+ break;
+ case A_DISPLAY:
+ write_text(mpl, "Display statement at line %d\n",
+ stmt->line);
+ execute_display(mpl, stmt->u.dpy);
+ break;
+ case A_PRINTF:
+ execute_printf(mpl, stmt->u.prt);
+ break;
+ case A_FOR:
+ execute_for(mpl, stmt->u.fur);
+ break;
+ default:
+ xassert(stmt != stmt);
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_statement - clean specified model statement.
+--
+-- This routine cleans specified model statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_statement(MPL *mpl, STATEMENT *stmt)
+{ switch(stmt->type)
+ { case A_SET:
+ clean_set(mpl, stmt->u.set); break;
+ case A_PARAMETER:
+ clean_parameter(mpl, stmt->u.par); break;
+ case A_VARIABLE:
+ clean_variable(mpl, stmt->u.var); break;
+ case A_CONSTRAINT:
+ clean_constraint(mpl, stmt->u.con); break;
+#if 1 /* 11/II-2008 */
+ case A_TABLE:
+ clean_table(mpl, stmt->u.tab); break;
+#endif
+ case A_SOLVE:
+ break;
+ case A_CHECK:
+ clean_check(mpl, stmt->u.chk); break;
+ case A_DISPLAY:
+ clean_display(mpl, stmt->u.dpy); break;
+ case A_PRINTF:
+ clean_printf(mpl, stmt->u.prt); break;
+ case A_FOR:
+ clean_for(mpl, stmt->u.fur); break;
+ default:
+ xassert(stmt != stmt);
+ }
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/mpl/mpl4.c b/test/monniaux/glpk-4.65/src/mpl/mpl4.c
new file mode 100644
index 00000000..6e80499c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/mpl/mpl4.c
@@ -0,0 +1,1426 @@
+/* mpl4.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2003-2016 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/>.
+***********************************************************************/
+
+#include "mpl.h"
+
+#define xfault xerror
+#define xfprintf glp_format
+#define dmp_create_poolx(size) dmp_create_pool()
+
+/**********************************************************************/
+/* * * GENERATING AND POSTSOLVING MODEL * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- alloc_content - allocate content arrays for all model objects.
+--
+-- This routine allocates content arrays for all existing model objects
+-- and thereby finalizes creating model.
+--
+-- This routine must be called immediately after reading model section,
+-- i.e. before reading data section or generating model. */
+
+void alloc_content(MPL *mpl)
+{ STATEMENT *stmt;
+ /* walk through all model statements */
+ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+ { switch (stmt->type)
+ { case A_SET:
+ /* model set */
+ xassert(stmt->u.set->array == NULL);
+ stmt->u.set->array = create_array(mpl, A_ELEMSET,
+ stmt->u.set->dim);
+ break;
+ case A_PARAMETER:
+ /* model parameter */
+ xassert(stmt->u.par->array == NULL);
+ switch (stmt->u.par->type)
+ { case A_NUMERIC:
+ case A_INTEGER:
+ case A_BINARY:
+ stmt->u.par->array = create_array(mpl, A_NUMERIC,
+ stmt->u.par->dim);
+ break;
+ case A_SYMBOLIC:
+ stmt->u.par->array = create_array(mpl, A_SYMBOLIC,
+ stmt->u.par->dim);
+ break;
+ default:
+ xassert(stmt != stmt);
+ }
+ break;
+ case A_VARIABLE:
+ /* model variable */
+ xassert(stmt->u.var->array == NULL);
+ stmt->u.var->array = create_array(mpl, A_ELEMVAR,
+ stmt->u.var->dim);
+ break;
+ case A_CONSTRAINT:
+ /* model constraint/objective */
+ xassert(stmt->u.con->array == NULL);
+ stmt->u.con->array = create_array(mpl, A_ELEMCON,
+ stmt->u.con->dim);
+ break;
+#if 1 /* 11/II-2008 */
+ case A_TABLE:
+#endif
+ case A_SOLVE:
+ case A_CHECK:
+ case A_DISPLAY:
+ case A_PRINTF:
+ case A_FOR:
+ /* functional statements have no content array */
+ break;
+ default:
+ xassert(stmt != stmt);
+ }
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- generate_model - generate model.
+--
+-- This routine executes the model statements which precede the solve
+-- statement. */
+
+void generate_model(MPL *mpl)
+{ STATEMENT *stmt;
+ xassert(!mpl->flag_p);
+ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+ { execute_statement(mpl, stmt);
+ if (mpl->stmt->type == A_SOLVE) break;
+ }
+ mpl->stmt = stmt;
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- build_problem - build problem instance.
+--
+-- This routine builds lists of rows and columns for problem instance,
+-- which corresponds to the generated model. */
+
+void build_problem(MPL *mpl)
+{ STATEMENT *stmt;
+ MEMBER *memb;
+ VARIABLE *v;
+ CONSTRAINT *c;
+ FORMULA *t;
+ int i, j;
+ xassert(mpl->m == 0);
+ xassert(mpl->n == 0);
+ xassert(mpl->row == NULL);
+ xassert(mpl->col == NULL);
+ /* check that all elemental variables has zero column numbers */
+ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+ { if (stmt->type == A_VARIABLE)
+ { v = stmt->u.var;
+ for (memb = v->array->head; memb != NULL; memb = memb->next)
+ xassert(memb->value.var->j == 0);
+ }
+ }
+ /* assign row numbers to elemental constraints and objectives */
+ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+ { if (stmt->type == A_CONSTRAINT)
+ { c = stmt->u.con;
+ for (memb = c->array->head; memb != NULL; memb = memb->next)
+ { xassert(memb->value.con->i == 0);
+ memb->value.con->i = ++mpl->m;
+ /* walk through linear form and mark elemental variables,
+ which are referenced at least once */
+ for (t = memb->value.con->form; t != NULL; t = t->next)
+ { xassert(t->var != NULL);
+ t->var->memb->value.var->j = -1;
+ }
+ }
+ }
+ }
+ /* assign column numbers to marked elemental variables */
+ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+ { if (stmt->type == A_VARIABLE)
+ { v = stmt->u.var;
+ for (memb = v->array->head; memb != NULL; memb = memb->next)
+ if (memb->value.var->j != 0) memb->value.var->j =
+ ++mpl->n;
+ }
+ }
+ /* build list of rows */
+ mpl->row = xcalloc(1+mpl->m, sizeof(ELEMCON *));
+ for (i = 1; i <= mpl->m; i++) mpl->row[i] = NULL;
+ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+ { if (stmt->type == A_CONSTRAINT)
+ { c = stmt->u.con;
+ for (memb = c->array->head; memb != NULL; memb = memb->next)
+ { i = memb->value.con->i;
+ xassert(1 <= i && i <= mpl->m);
+ xassert(mpl->row[i] == NULL);
+ mpl->row[i] = memb->value.con;
+ }
+ }
+ }
+ for (i = 1; i <= mpl->m; i++) xassert(mpl->row[i] != NULL);
+ /* build list of columns */
+ mpl->col = xcalloc(1+mpl->n, sizeof(ELEMVAR *));
+ for (j = 1; j <= mpl->n; j++) mpl->col[j] = NULL;
+ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+ { if (stmt->type == A_VARIABLE)
+ { v = stmt->u.var;
+ for (memb = v->array->head; memb != NULL; memb = memb->next)
+ { j = memb->value.var->j;
+ if (j == 0) continue;
+ xassert(1 <= j && j <= mpl->n);
+ xassert(mpl->col[j] == NULL);
+ mpl->col[j] = memb->value.var;
+ }
+ }
+ }
+ for (j = 1; j <= mpl->n; j++) xassert(mpl->col[j] != NULL);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- postsolve_model - postsolve model.
+--
+-- This routine executes the model statements which follow the solve
+-- statement. */
+
+void postsolve_model(MPL *mpl)
+{ STATEMENT *stmt;
+ xassert(!mpl->flag_p);
+ mpl->flag_p = 1;
+ for (stmt = mpl->stmt; stmt != NULL; stmt = stmt->next)
+ execute_statement(mpl, stmt);
+ mpl->stmt = NULL;
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_model - clean model content.
+--
+-- This routine cleans the model content that assumes deleting all stuff
+-- dynamically allocated on generating/postsolving phase.
+--
+-- Actually cleaning model content is not needed. This function is used
+-- mainly to be sure that there were no logical errors on using dynamic
+-- memory pools during the generation phase.
+--
+-- NOTE: This routine must not be called if any errors were detected on
+-- the generation phase. */
+
+void clean_model(MPL *mpl)
+{ STATEMENT *stmt;
+ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+ clean_statement(mpl, stmt);
+ /* check that all atoms have been returned to their pools */
+ if (dmp_in_use(mpl->strings) != 0)
+ error(mpl, "internal logic error: %d string segment(s) were lo"
+ "st", dmp_in_use(mpl->strings));
+ if (dmp_in_use(mpl->symbols) != 0)
+ error(mpl, "internal logic error: %d symbol(s) were lost",
+ dmp_in_use(mpl->symbols));
+ if (dmp_in_use(mpl->tuples) != 0)
+ error(mpl, "internal logic error: %d n-tuple component(s) were"
+ " lost", dmp_in_use(mpl->tuples));
+ if (dmp_in_use(mpl->arrays) != 0)
+ error(mpl, "internal logic error: %d array(s) were lost",
+ dmp_in_use(mpl->arrays));
+ if (dmp_in_use(mpl->members) != 0)
+ error(mpl, "internal logic error: %d array member(s) were lost"
+ , dmp_in_use(mpl->members));
+ if (dmp_in_use(mpl->elemvars) != 0)
+ error(mpl, "internal logic error: %d elemental variable(s) wer"
+ "e lost", dmp_in_use(mpl->elemvars));
+ if (dmp_in_use(mpl->formulae) != 0)
+ error(mpl, "internal logic error: %d linear term(s) were lost",
+ dmp_in_use(mpl->formulae));
+ if (dmp_in_use(mpl->elemcons) != 0)
+ error(mpl, "internal logic error: %d elemental constraint(s) w"
+ "ere lost", dmp_in_use(mpl->elemcons));
+ return;
+}
+
+/**********************************************************************/
+/* * * INPUT/OUTPUT * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- open_input - open input text file.
+--
+-- This routine opens the input text file for scanning. */
+
+void open_input(MPL *mpl, char *file)
+{ mpl->line = 0;
+ mpl->c = '\n';
+ mpl->token = 0;
+ mpl->imlen = 0;
+ mpl->image[0] = '\0';
+ mpl->value = 0.0;
+ mpl->b_token = T_EOF;
+ mpl->b_imlen = 0;
+ mpl->b_image[0] = '\0';
+ mpl->b_value = 0.0;
+ mpl->f_dots = 0;
+ mpl->f_scan = 0;
+ mpl->f_token = 0;
+ mpl->f_imlen = 0;
+ mpl->f_image[0] = '\0';
+ mpl->f_value = 0.0;
+ memset(mpl->context, ' ', CONTEXT_SIZE);
+ mpl->c_ptr = 0;
+ xassert(mpl->in_fp == NULL);
+ mpl->in_fp = glp_open(file, "r");
+ if (mpl->in_fp == NULL)
+ error(mpl, "unable to open %s - %s", file, get_err_msg());
+ mpl->in_file = file;
+ /* scan the very first character */
+ get_char(mpl);
+ /* scan the very first token */
+ get_token(mpl);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- read_char - read next character from input text file.
+--
+-- This routine returns a next ASCII character read from the input text
+-- file. If the end of file has been reached, EOF is returned. */
+
+int read_char(MPL *mpl)
+{ int c;
+ xassert(mpl->in_fp != NULL);
+ c = glp_getc(mpl->in_fp);
+ if (c < 0)
+ { if (glp_ioerr(mpl->in_fp))
+ error(mpl, "read error on %s - %s", mpl->in_file,
+ get_err_msg());
+ c = EOF;
+ }
+ return c;
+}
+
+/*----------------------------------------------------------------------
+-- close_input - close input text file.
+--
+-- This routine closes the input text file. */
+
+void close_input(MPL *mpl)
+{ xassert(mpl->in_fp != NULL);
+ glp_close(mpl->in_fp);
+ mpl->in_fp = NULL;
+ mpl->in_file = NULL;
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- open_output - open output text file.
+--
+-- This routine opens the output text file for writing data produced by
+-- display and printf statements. */
+
+void open_output(MPL *mpl, char *file)
+{ xassert(mpl->out_fp == NULL);
+ if (file == NULL)
+ { file = "<stdout>";
+ mpl->out_fp = (void *)stdout;
+ }
+ else
+ { mpl->out_fp = glp_open(file, "w");
+ if (mpl->out_fp == NULL)
+ error(mpl, "unable to create %s - %s", file, get_err_msg());
+ }
+ mpl->out_file = xmalloc(strlen(file)+1);
+ strcpy(mpl->out_file, file);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- write_char - write next character to output text file.
+--
+-- This routine writes an ASCII character to the output text file. */
+
+void write_char(MPL *mpl, int c)
+{ xassert(mpl->out_fp != NULL);
+ if (mpl->out_fp == (void *)stdout)
+ xprintf("%c", c);
+ else
+ xfprintf(mpl->out_fp, "%c", c);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- write_text - format and write text to output text file.
+--
+-- This routine formats a text using the format control string and then
+-- writes this text to the output text file. */
+
+void write_text(MPL *mpl, char *fmt, ...)
+{ va_list arg;
+ char buf[OUTBUF_SIZE], *c;
+ va_start(arg, fmt);
+ vsprintf(buf, fmt, arg);
+ xassert(strlen(buf) < sizeof(buf));
+ va_end(arg);
+ for (c = buf; *c != '\0'; c++) write_char(mpl, *c);
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- flush_output - finalize writing data to output text file.
+--
+-- This routine finalizes writing data to the output text file. */
+
+void flush_output(MPL *mpl)
+{ xassert(mpl->out_fp != NULL);
+ if (mpl->out_fp != (void *)stdout)
+ {
+#if 0 /* FIXME */
+ xfflush(mpl->out_fp);
+#endif
+ if (glp_ioerr(mpl->out_fp))
+ error(mpl, "write error on %s - %s", mpl->out_file,
+ get_err_msg());
+ }
+ return;
+}
+
+/**********************************************************************/
+/* * * SOLVER INTERFACE * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- error - print error message and terminate model processing.
+--
+-- This routine formats and prints an error message and then terminates
+-- model processing. */
+
+void error(MPL *mpl, char *fmt, ...)
+{ va_list arg;
+ char msg[4095+1];
+ va_start(arg, fmt);
+ vsprintf(msg, fmt, arg);
+ xassert(strlen(msg) < sizeof(msg));
+ va_end(arg);
+ switch (mpl->phase)
+ { case 1:
+ case 2:
+ /* translation phase */
+ xprintf("%s:%d: %s\n",
+ mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
+ mpl->line, msg);
+ print_context(mpl);
+ break;
+ case 3:
+ /* generation/postsolve phase */
+ xprintf("%s:%d: %s\n",
+ mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
+ mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
+ break;
+ default:
+ xassert(mpl != mpl);
+ }
+ mpl->phase = 4;
+ longjmp(mpl->jump, 1);
+ /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- warning - print warning message and continue model processing.
+--
+-- This routine formats and prints a warning message and returns to the
+-- calling program. */
+
+void warning(MPL *mpl, char *fmt, ...)
+{ va_list arg;
+ char msg[4095+1];
+ va_start(arg, fmt);
+ vsprintf(msg, fmt, arg);
+ xassert(strlen(msg) < sizeof(msg));
+ va_end(arg);
+ switch (mpl->phase)
+ { case 1:
+ case 2:
+ /* translation phase */
+ xprintf("%s:%d: warning: %s\n",
+ mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
+ mpl->line, msg);
+ break;
+ case 3:
+ /* generation/postsolve phase */
+ xprintf("%s:%d: warning: %s\n",
+ mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
+ mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
+ break;
+ default:
+ xassert(mpl != mpl);
+ }
+ return;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_initialize - create and initialize translator database.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- MPL *mpl_initialize(void);
+--
+-- *Description*
+--
+-- The routine mpl_initialize creates and initializes the database used
+-- by the GNU MathProg translator.
+--
+-- *Returns*
+--
+-- The routine returns a pointer to the database created. */
+
+MPL *mpl_initialize(void)
+{ MPL *mpl;
+ mpl = xmalloc(sizeof(MPL));
+ /* scanning segment */
+ mpl->line = 0;
+ mpl->c = 0;
+ mpl->token = 0;
+ mpl->imlen = 0;
+ mpl->image = xcalloc(MAX_LENGTH+1, sizeof(char));
+ mpl->image[0] = '\0';
+ mpl->value = 0.0;
+ mpl->b_token = 0;
+ mpl->b_imlen = 0;
+ mpl->b_image = xcalloc(MAX_LENGTH+1, sizeof(char));
+ mpl->b_image[0] = '\0';
+ mpl->b_value = 0.0;
+ mpl->f_dots = 0;
+ mpl->f_scan = 0;
+ mpl->f_token = 0;
+ mpl->f_imlen = 0;
+ mpl->f_image = xcalloc(MAX_LENGTH+1, sizeof(char));
+ mpl->f_image[0] = '\0';
+ mpl->f_value = 0.0;
+ mpl->context = xcalloc(CONTEXT_SIZE, sizeof(char));
+ memset(mpl->context, ' ', CONTEXT_SIZE);
+ mpl->c_ptr = 0;
+ mpl->flag_d = 0;
+ /* translating segment */
+ mpl->pool = dmp_create_poolx(0);
+ mpl->tree = avl_create_tree(avl_strcmp, NULL);
+ mpl->model = NULL;
+ mpl->flag_x = 0;
+ mpl->as_within = 0;
+ mpl->as_in = 0;
+ mpl->as_binary = 0;
+ mpl->flag_s = 0;
+ /* common segment */
+ mpl->strings = dmp_create_poolx(sizeof(STRING));
+ mpl->symbols = dmp_create_poolx(sizeof(SYMBOL));
+ mpl->tuples = dmp_create_poolx(sizeof(TUPLE));
+ mpl->arrays = dmp_create_poolx(sizeof(ARRAY));
+ mpl->members = dmp_create_poolx(sizeof(MEMBER));
+ mpl->elemvars = dmp_create_poolx(sizeof(ELEMVAR));
+ mpl->formulae = dmp_create_poolx(sizeof(FORMULA));
+ mpl->elemcons = dmp_create_poolx(sizeof(ELEMCON));
+ mpl->a_list = NULL;
+ mpl->sym_buf = xcalloc(255+1, sizeof(char));
+ mpl->sym_buf[0] = '\0';
+ mpl->tup_buf = xcalloc(255+1, sizeof(char));
+ mpl->tup_buf[0] = '\0';
+ /* generating/postsolving segment */
+ mpl->rand = rng_create_rand();
+ mpl->flag_p = 0;
+ mpl->stmt = NULL;
+#if 1 /* 11/II-2008 */
+ mpl->dca = NULL;
+#endif
+ mpl->m = 0;
+ mpl->n = 0;
+ mpl->row = NULL;
+ mpl->col = NULL;
+ /* input/output segment */
+ mpl->in_fp = NULL;
+ mpl->in_file = NULL;
+ mpl->out_fp = NULL;
+ mpl->out_file = NULL;
+ mpl->prt_fp = NULL;
+ mpl->prt_file = NULL;
+ /* solver interface segment */
+ if (setjmp(mpl->jump)) xassert(mpl != mpl);
+ mpl->phase = 0;
+ mpl->mod_file = NULL;
+ mpl->mpl_buf = xcalloc(255+1, sizeof(char));
+ mpl->mpl_buf[0] = '\0';
+ return mpl;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_read_model - read model section and optional data section.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_read_model(MPL *mpl, char *file, int skip_data);
+--
+-- *Description*
+--
+-- The routine mpl_read_model reads model section and optionally data
+-- section, which may follow the model section, from the text file,
+-- whose name is the character string file, performs translating model
+-- statements and data blocks, and stores all the information in the
+-- translator database.
+--
+-- The parameter skip_data is a flag. If the input file contains the
+-- data section and this flag is set, the data section is not read as
+-- if there were no data section and a warning message is issued. This
+-- allows reading the data section from another input file.
+--
+-- This routine should be called once after the routine mpl_initialize
+-- and before other API routines.
+--
+-- *Returns*
+--
+-- The routine mpl_read_model returns one the following codes:
+--
+-- 1 - translation successful. The input text file contains only model
+-- section. In this case the calling program may call the routine
+-- mpl_read_data to read data section from another file.
+-- 2 - translation successful. The input text file contains both model
+-- and data section.
+-- 4 - processing failed due to some errors. In this case the calling
+-- program should call the routine mpl_terminate to terminate model
+-- processing. */
+
+int mpl_read_model(MPL *mpl, char *file, int skip_data)
+{ if (mpl->phase != 0)
+ xfault("mpl_read_model: invalid call sequence\n");
+ if (file == NULL)
+ xfault("mpl_read_model: no input filename specified\n");
+ /* set up error handler */
+ if (setjmp(mpl->jump)) goto done;
+ /* translate model section */
+ mpl->phase = 1;
+ xprintf("Reading model section from %s...\n", file);
+ open_input(mpl, file);
+ model_section(mpl);
+ if (mpl->model == NULL)
+ error(mpl, "empty model section not allowed");
+ /* save name of the input text file containing model section for
+ error diagnostics during the generation phase */
+ mpl->mod_file = xcalloc(strlen(file)+1, sizeof(char));
+ strcpy(mpl->mod_file, mpl->in_file);
+ /* allocate content arrays for all model objects */
+ alloc_content(mpl);
+ /* optional data section may begin with the keyword 'data' */
+ if (is_keyword(mpl, "data"))
+ { if (skip_data)
+ { warning(mpl, "data section ignored");
+ goto skip;
+ }
+ mpl->flag_d = 1;
+ get_token(mpl /* data */);
+ if (mpl->token != T_SEMICOLON)
+ error(mpl, "semicolon missing where expected");
+ get_token(mpl /* ; */);
+ /* translate data section */
+ mpl->phase = 2;
+ xprintf("Reading data section from %s...\n", file);
+ data_section(mpl);
+ }
+ /* process end statement */
+ end_statement(mpl);
+skip: xprintf("%d line%s were read\n",
+ mpl->line, mpl->line == 1 ? "" : "s");
+ close_input(mpl);
+done: /* return to the calling program */
+ return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_read_data - read data section.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_read_data(MPL *mpl, char *file);
+--
+-- *Description*
+--
+-- The routine mpl_read_data reads data section from the text file,
+-- whose name is the character string file, performs translating data
+-- blocks, and stores the data read in the translator database.
+--
+-- If this routine is used, it should be called once after the routine
+-- mpl_read_model and if the latter returned the code 1.
+--
+-- *Returns*
+--
+-- The routine mpl_read_data returns one of the following codes:
+--
+-- 2 - data section has been successfully processed.
+-- 4 - processing failed due to some errors. In this case the calling
+-- program should call the routine mpl_terminate to terminate model
+-- processing. */
+
+int mpl_read_data(MPL *mpl, char *file)
+#if 0 /* 02/X-2008 */
+{ if (mpl->phase != 1)
+#else
+{ if (!(mpl->phase == 1 || mpl->phase == 2))
+#endif
+ xfault("mpl_read_data: invalid call sequence\n");
+ if (file == NULL)
+ xfault("mpl_read_data: no input filename specified\n");
+ /* set up error handler */
+ if (setjmp(mpl->jump)) goto done;
+ /* process data section */
+ mpl->phase = 2;
+ xprintf("Reading data section from %s...\n", file);
+ mpl->flag_d = 1;
+ open_input(mpl, file);
+ /* in this case the keyword 'data' is optional */
+ if (is_literal(mpl, "data"))
+ { get_token(mpl /* data */);
+ if (mpl->token != T_SEMICOLON)
+ error(mpl, "semicolon missing where expected");
+ get_token(mpl /* ; */);
+ }
+ data_section(mpl);
+ /* process end statement */
+ end_statement(mpl);
+ xprintf("%d line%s were read\n",
+ mpl->line, mpl->line == 1 ? "" : "s");
+ close_input(mpl);
+done: /* return to the calling program */
+ return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_generate - generate model.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_generate(MPL *mpl, char *file);
+--
+-- *Description*
+--
+-- The routine mpl_generate generates the model using its description
+-- stored in the translator database. This phase means generating all
+-- variables, constraints, and objectives, executing check and display
+-- statements, which precede the solve statement (if it is presented),
+-- and building the problem instance.
+--
+-- The character string file specifies the name of output text file, to
+-- which output produced by display statements should be written. It is
+-- allowed to specify NULL, in which case the output goes to stdout via
+-- the routine print.
+--
+-- This routine should be called once after the routine mpl_read_model
+-- or mpl_read_data and if one of the latters returned the code 2.
+--
+-- *Returns*
+--
+-- The routine mpl_generate returns one of the following codes:
+--
+-- 3 - model has been successfully generated. In this case the calling
+-- program may call other api routines to obtain components of the
+-- problem instance from the translator database.
+-- 4 - processing failed due to some errors. In this case the calling
+-- program should call the routine mpl_terminate to terminate model
+-- processing. */
+
+int mpl_generate(MPL *mpl, char *file)
+{ if (!(mpl->phase == 1 || mpl->phase == 2))
+ xfault("mpl_generate: invalid call sequence\n");
+ /* set up error handler */
+ if (setjmp(mpl->jump)) goto done;
+ /* generate model */
+ mpl->phase = 3;
+ open_output(mpl, file);
+ generate_model(mpl);
+ flush_output(mpl);
+ /* build problem instance */
+ build_problem(mpl);
+ /* generation phase has been finished */
+ xprintf("Model has been successfully generated\n");
+done: /* return to the calling program */
+ return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_prob_name - obtain problem (model) name.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- char *mpl_get_prob_name(MPL *mpl);
+--
+-- *Returns*
+--
+-- The routine mpl_get_prob_name returns a pointer to internal buffer,
+-- which contains symbolic name of the problem (model).
+--
+-- *Note*
+--
+-- Currently MathProg has no feature to assign a symbolic name to the
+-- model. Therefore the routine mpl_get_prob_name tries to construct
+-- such name using the name of input text file containing model section,
+-- although this is not a good idea (due to portability problems). */
+
+char *mpl_get_prob_name(MPL *mpl)
+{ char *name = mpl->mpl_buf;
+ char *file = mpl->mod_file;
+ int k;
+ if (mpl->phase != 3)
+ xfault("mpl_get_prob_name: invalid call sequence\n");
+ for (;;)
+ { if (strchr(file, '/') != NULL)
+ file = strchr(file, '/') + 1;
+ else if (strchr(file, '\\') != NULL)
+ file = strchr(file, '\\') + 1;
+ else if (strchr(file, ':') != NULL)
+ file = strchr(file, ':') + 1;
+ else
+ break;
+ }
+ for (k = 0; ; k++)
+ { if (k == 255) break;
+ if (!(isalnum((unsigned char)*file) || *file == '_')) break;
+ name[k] = *file++;
+ }
+ if (k == 0)
+ strcpy(name, "Unknown");
+ else
+ name[k] = '\0';
+ xassert(strlen(name) <= 255);
+ return name;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_num_rows - determine number of rows.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_num_rows(MPL *mpl);
+--
+-- *Returns*
+--
+-- The routine mpl_get_num_rows returns total number of rows in the
+-- problem, where each row is an individual constraint or objective. */
+
+int mpl_get_num_rows(MPL *mpl)
+{ if (mpl->phase != 3)
+ xfault("mpl_get_num_rows: invalid call sequence\n");
+ return mpl->m;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_num_cols - determine number of columns.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_num_cols(MPL *mpl);
+--
+-- *Returns*
+--
+-- The routine mpl_get_num_cols returns total number of columns in the
+-- problem, where each column is an individual variable. */
+
+int mpl_get_num_cols(MPL *mpl)
+{ if (mpl->phase != 3)
+ xfault("mpl_get_num_cols: invalid call sequence\n");
+ return mpl->n;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_name - obtain row name.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- char *mpl_get_row_name(MPL *mpl, int i);
+--
+-- *Returns*
+--
+-- The routine mpl_get_row_name returns a pointer to internal buffer,
+-- which contains symbolic name of i-th row of the problem. */
+
+char *mpl_get_row_name(MPL *mpl, int i)
+{ char *name = mpl->mpl_buf, *t;
+ int len;
+ if (mpl->phase != 3)
+ xfault("mpl_get_row_name: invalid call sequence\n");
+ if (!(1 <= i && i <= mpl->m))
+ xfault("mpl_get_row_name: i = %d; row number out of range\n",
+ i);
+ strcpy(name, mpl->row[i]->con->name);
+ len = strlen(name);
+ xassert(len <= 255);
+ t = format_tuple(mpl, '[', mpl->row[i]->memb->tuple);
+ while (*t)
+ { if (len == 255) break;
+ name[len++] = *t++;
+ }
+ name[len] = '\0';
+ if (len == 255) strcpy(name+252, "...");
+ xassert(strlen(name) <= 255);
+ return name;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_kind - determine row kind.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_row_kind(MPL *mpl, int i);
+--
+-- *Returns*
+--
+-- The routine mpl_get_row_kind returns the kind of i-th row, which can
+-- be one of the following:
+--
+-- MPL_ST - non-free (constraint) row;
+-- MPL_MIN - free (objective) row to be minimized;
+-- MPL_MAX - free (objective) row to be maximized. */
+
+int mpl_get_row_kind(MPL *mpl, int i)
+{ int kind;
+ if (mpl->phase != 3)
+ xfault("mpl_get_row_kind: invalid call sequence\n");
+ if (!(1 <= i && i <= mpl->m))
+ xfault("mpl_get_row_kind: i = %d; row number out of range\n",
+ i);
+ switch (mpl->row[i]->con->type)
+ { case A_CONSTRAINT:
+ kind = MPL_ST; break;
+ case A_MINIMIZE:
+ kind = MPL_MIN; break;
+ case A_MAXIMIZE:
+ kind = MPL_MAX; break;
+ default:
+ xassert(mpl != mpl);
+ }
+ return kind;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_bnds - obtain row bounds.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
+--
+-- *Description*
+--
+-- The routine mpl_get_row_bnds stores lower and upper bounds of i-th
+-- row of the problem to the locations, which the parameters lb and ub
+-- point to, respectively. Besides the routine returns the type of the
+-- i-th row.
+--
+-- If some of the parameters lb and ub is NULL, the corresponding bound
+-- value is not stored.
+--
+-- Types and bounds have the following meaning:
+--
+-- Type Bounds Note
+-- -----------------------------------------------------------
+-- MPL_FR -inf < f(x) < +inf Free linear form
+-- MPL_LO lb <= f(x) < +inf Inequality f(x) >= lb
+-- MPL_UP -inf < f(x) <= ub Inequality f(x) <= ub
+-- MPL_DB lb <= f(x) <= ub Inequality lb <= f(x) <= ub
+-- MPL_FX f(x) = lb Equality f(x) = lb
+--
+-- where f(x) is the corresponding linear form of the i-th row.
+--
+-- If the row has no lower bound, *lb is set to zero; if the row has
+-- no upper bound, *ub is set to zero; and if the row is of fixed type,
+-- both *lb and *ub are set to the same value.
+--
+-- *Returns*
+--
+-- The routine returns the type of the i-th row as it is stated in the
+-- table above. */
+
+int mpl_get_row_bnds(MPL *mpl, int i, double *_lb, double *_ub)
+{ ELEMCON *con;
+ int type;
+ double lb, ub;
+ if (mpl->phase != 3)
+ xfault("mpl_get_row_bnds: invalid call sequence\n");
+ if (!(1 <= i && i <= mpl->m))
+ xfault("mpl_get_row_bnds: i = %d; row number out of range\n",
+ i);
+ con = mpl->row[i];
+#if 0 /* 21/VII-2006 */
+ if (con->con->lbnd == NULL && con->con->ubnd == NULL)
+ type = MPL_FR, lb = ub = 0.0;
+ else if (con->con->ubnd == NULL)
+ type = MPL_LO, lb = con->lbnd, ub = 0.0;
+ else if (con->con->lbnd == NULL)
+ type = MPL_UP, lb = 0.0, ub = con->ubnd;
+ else if (con->con->lbnd != con->con->ubnd)
+ type = MPL_DB, lb = con->lbnd, ub = con->ubnd;
+ else
+ type = MPL_FX, lb = ub = con->lbnd;
+#else
+ lb = (con->con->lbnd == NULL ? -DBL_MAX : con->lbnd);
+ ub = (con->con->ubnd == NULL ? +DBL_MAX : con->ubnd);
+ if (lb == -DBL_MAX && ub == +DBL_MAX)
+ type = MPL_FR, lb = ub = 0.0;
+ else if (ub == +DBL_MAX)
+ type = MPL_LO, ub = 0.0;
+ else if (lb == -DBL_MAX)
+ type = MPL_UP, lb = 0.0;
+ else if (con->con->lbnd != con->con->ubnd)
+ type = MPL_DB;
+ else
+ type = MPL_FX;
+#endif
+ if (_lb != NULL) *_lb = lb;
+ if (_ub != NULL) *_ub = ub;
+ return type;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_mat_row - obtain row of the constraint matrix.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
+--
+-- *Description*
+--
+-- The routine mpl_get_mat_row stores column indices and numeric values
+-- of constraint coefficients for the i-th row to locations ndx[1], ...,
+-- ndx[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
+-- is number of (structural) non-zero constraint coefficients, and n is
+-- number of columns in the problem.
+--
+-- If the parameter ndx is NULL, column indices are not stored. If the
+-- parameter val is NULL, numeric values are not stored.
+--
+-- Note that free rows may have constant terms, which are not part of
+-- the constraint matrix and therefore not reported by this routine. The
+-- constant term of a particular row can be obtained, if necessary, via
+-- the routine mpl_get_row_c0.
+--
+-- *Returns*
+--
+-- The routine mpl_get_mat_row returns len, which is length of i-th row
+-- of the constraint matrix (i.e. number of non-zero coefficients). */
+
+int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[])
+{ FORMULA *term;
+ int len = 0;
+ if (mpl->phase != 3)
+ xfault("mpl_get_mat_row: invalid call sequence\n");
+ if (!(1 <= i && i <= mpl->m))
+ xfault("mpl_get_mat_row: i = %d; row number out of range\n",
+ i);
+ for (term = mpl->row[i]->form; term != NULL; term = term->next)
+ { xassert(term->var != NULL);
+ len++;
+ xassert(len <= mpl->n);
+ if (ndx != NULL) ndx[len] = term->var->j;
+ if (val != NULL) val[len] = term->coef;
+ }
+ return len;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_c0 - obtain constant term of free row.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- double mpl_get_row_c0(MPL *mpl, int i);
+--
+-- *Returns*
+--
+-- The routine mpl_get_row_c0 returns numeric value of constant term of
+-- i-th row.
+--
+-- Note that only free rows may have non-zero constant terms. Therefore
+-- if i-th row is not free, the routine returns zero. */
+
+double mpl_get_row_c0(MPL *mpl, int i)
+{ ELEMCON *con;
+ double c0;
+ if (mpl->phase != 3)
+ xfault("mpl_get_row_c0: invalid call sequence\n");
+ if (!(1 <= i && i <= mpl->m))
+ xfault("mpl_get_row_c0: i = %d; row number out of range\n",
+ i);
+ con = mpl->row[i];
+ if (con->con->lbnd == NULL && con->con->ubnd == NULL)
+ c0 = - con->lbnd;
+ else
+ c0 = 0.0;
+ return c0;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_col_name - obtain column name.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- char *mpl_get_col_name(MPL *mpl, int j);
+--
+-- *Returns*
+--
+-- The routine mpl_get_col_name returns a pointer to internal buffer,
+-- which contains symbolic name of j-th column of the problem. */
+
+char *mpl_get_col_name(MPL *mpl, int j)
+{ char *name = mpl->mpl_buf, *t;
+ int len;
+ if (mpl->phase != 3)
+ xfault("mpl_get_col_name: invalid call sequence\n");
+ if (!(1 <= j && j <= mpl->n))
+ xfault("mpl_get_col_name: j = %d; column number out of range\n"
+ , j);
+ strcpy(name, mpl->col[j]->var->name);
+ len = strlen(name);
+ xassert(len <= 255);
+ t = format_tuple(mpl, '[', mpl->col[j]->memb->tuple);
+ while (*t)
+ { if (len == 255) break;
+ name[len++] = *t++;
+ }
+ name[len] = '\0';
+ if (len == 255) strcpy(name+252, "...");
+ xassert(strlen(name) <= 255);
+ return name;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_col_kind - determine column kind.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_col_kind(MPL *mpl, int j);
+--
+-- *Returns*
+--
+-- The routine mpl_get_col_kind returns the kind of j-th column, which
+-- can be one of the following:
+--
+-- MPL_NUM - continuous variable;
+-- MPL_INT - integer variable;
+-- MPL_BIN - binary variable.
+--
+-- Note that column kinds are defined independently on type and bounds
+-- (reported by the routine mpl_get_col_bnds) of corresponding columns.
+-- This means, in particular, that bounds of an integer column may be
+-- fractional, or a binary column may have lower and upper bounds that
+-- are not 0 and 1 (or it may have no lower/upper bound at all). */
+
+int mpl_get_col_kind(MPL *mpl, int j)
+{ int kind;
+ if (mpl->phase != 3)
+ xfault("mpl_get_col_kind: invalid call sequence\n");
+ if (!(1 <= j && j <= mpl->n))
+ xfault("mpl_get_col_kind: j = %d; column number out of range\n"
+ , j);
+ switch (mpl->col[j]->var->type)
+ { case A_NUMERIC:
+ kind = MPL_NUM; break;
+ case A_INTEGER:
+ kind = MPL_INT; break;
+ case A_BINARY:
+ kind = MPL_BIN; break;
+ default:
+ xassert(mpl != mpl);
+ }
+ return kind;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_col_bnds - obtain column bounds.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
+--
+-- *Description*
+--
+-- The routine mpl_get_col_bnds stores lower and upper bound of j-th
+-- column of the problem to the locations, which the parameters lb and
+-- ub point to, respectively. Besides the routine returns the type of
+-- the j-th column.
+--
+-- If some of the parameters lb and ub is NULL, the corresponding bound
+-- value is not stored.
+--
+-- Types and bounds have the following meaning:
+--
+-- Type Bounds Note
+-- ------------------------------------------------------
+-- MPL_FR -inf < x < +inf Free (unbounded) variable
+-- MPL_LO lb <= x < +inf Variable with lower bound
+-- MPL_UP -inf < x <= ub Variable with upper bound
+-- MPL_DB lb <= x <= ub Double-bounded variable
+-- MPL_FX x = lb Fixed variable
+--
+-- where x is individual variable corresponding to the j-th column.
+--
+-- If the column has no lower bound, *lb is set to zero; if the column
+-- has no upper bound, *ub is set to zero; and if the column is of fixed
+-- type, both *lb and *ub are set to the same value.
+--
+-- *Returns*
+--
+-- The routine returns the type of the j-th column as it is stated in
+-- the table above. */
+
+int mpl_get_col_bnds(MPL *mpl, int j, double *_lb, double *_ub)
+{ ELEMVAR *var;
+ int type;
+ double lb, ub;
+ if (mpl->phase != 3)
+ xfault("mpl_get_col_bnds: invalid call sequence\n");
+ if (!(1 <= j && j <= mpl->n))
+ xfault("mpl_get_col_bnds: j = %d; column number out of range\n"
+ , j);
+ var = mpl->col[j];
+#if 0 /* 21/VII-2006 */
+ if (var->var->lbnd == NULL && var->var->ubnd == NULL)
+ type = MPL_FR, lb = ub = 0.0;
+ else if (var->var->ubnd == NULL)
+ type = MPL_LO, lb = var->lbnd, ub = 0.0;
+ else if (var->var->lbnd == NULL)
+ type = MPL_UP, lb = 0.0, ub = var->ubnd;
+ else if (var->var->lbnd != var->var->ubnd)
+ type = MPL_DB, lb = var->lbnd, ub = var->ubnd;
+ else
+ type = MPL_FX, lb = ub = var->lbnd;
+#else
+ lb = (var->var->lbnd == NULL ? -DBL_MAX : var->lbnd);
+ ub = (var->var->ubnd == NULL ? +DBL_MAX : var->ubnd);
+ if (lb == -DBL_MAX && ub == +DBL_MAX)
+ type = MPL_FR, lb = ub = 0.0;
+ else if (ub == +DBL_MAX)
+ type = MPL_LO, ub = 0.0;
+ else if (lb == -DBL_MAX)
+ type = MPL_UP, lb = 0.0;
+ else if (var->var->lbnd != var->var->ubnd)
+ type = MPL_DB;
+ else
+ type = MPL_FX;
+#endif
+ if (_lb != NULL) *_lb = lb;
+ if (_ub != NULL) *_ub = ub;
+ return type;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_has_solve_stmt - check if model has solve statement.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_has_solve_stmt(MPL *mpl);
+--
+-- *Returns*
+--
+-- If the model has the solve statement, the routine returns non-zero,
+-- otherwise zero is returned. */
+
+int mpl_has_solve_stmt(MPL *mpl)
+{ if (mpl->phase != 3)
+ xfault("mpl_has_solve_stmt: invalid call sequence\n");
+ return mpl->flag_s;
+}
+
+#if 1 /* 15/V-2010 */
+void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
+ double dual)
+{ /* store row (constraint/objective) solution components */
+ xassert(mpl->phase == 3);
+ xassert(1 <= i && i <= mpl->m);
+ mpl->row[i]->stat = stat;
+ mpl->row[i]->prim = prim;
+ mpl->row[i]->dual = dual;
+ return;
+}
+#endif
+
+#if 1 /* 15/V-2010 */
+void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
+ double dual)
+{ /* store column (variable) solution components */
+ xassert(mpl->phase == 3);
+ xassert(1 <= j && j <= mpl->n);
+ mpl->col[j]->stat = stat;
+ mpl->col[j]->prim = prim;
+ mpl->col[j]->dual = dual;
+ return;
+}
+#endif
+
+#if 0 /* 15/V-2010 */
+/*----------------------------------------------------------------------
+-- mpl_put_col_value - store column value.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- void mpl_put_col_value(MPL *mpl, int j, double val);
+--
+-- *Description*
+--
+-- The routine mpl_put_col_value stores numeric value of j-th column
+-- into the translator database. It is assumed that the column value is
+-- provided by the solver. */
+
+void mpl_put_col_value(MPL *mpl, int j, double val)
+{ if (mpl->phase != 3)
+ xfault("mpl_put_col_value: invalid call sequence\n");
+ if (!(1 <= j && j <= mpl->n))
+ xfault(
+ "mpl_put_col_value: j = %d; column number out of range\n", j);
+ mpl->col[j]->prim = val;
+ return;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- mpl_postsolve - postsolve model.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_postsolve(MPL *mpl);
+--
+-- *Description*
+--
+-- The routine mpl_postsolve performs postsolving of the model using
+-- its description stored in the translator database. This phase means
+-- executing statements, which follow the solve statement.
+--
+-- If this routine is used, it should be called once after the routine
+-- mpl_generate and if the latter returned the code 3.
+--
+-- *Returns*
+--
+-- The routine mpl_postsolve returns one of the following codes:
+--
+-- 3 - model has been successfully postsolved.
+-- 4 - processing failed due to some errors. In this case the calling
+-- program should call the routine mpl_terminate to terminate model
+-- processing. */
+
+int mpl_postsolve(MPL *mpl)
+{ if (!(mpl->phase == 3 && !mpl->flag_p))
+ xfault("mpl_postsolve: invalid call sequence\n");
+ /* set up error handler */
+ if (setjmp(mpl->jump)) goto done;
+ /* perform postsolving */
+ postsolve_model(mpl);
+ flush_output(mpl);
+ /* postsolving phase has been finished */
+ xprintf("Model has been successfully processed\n");
+done: /* return to the calling program */
+ return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_terminate - free all resources used by translator.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- void mpl_terminate(MPL *mpl);
+--
+-- *Description*
+--
+-- The routine mpl_terminate frees all the resources used by the GNU
+-- MathProg translator. */
+
+void mpl_terminate(MPL *mpl)
+{ if (setjmp(mpl->jump)) xassert(mpl != mpl);
+ switch (mpl->phase)
+ { case 0:
+ case 1:
+ case 2:
+ case 3:
+ /* there were no errors; clean the model content */
+ clean_model(mpl);
+ xassert(mpl->a_list == NULL);
+#if 1 /* 11/II-2008 */
+ xassert(mpl->dca == NULL);
+#endif
+ break;
+ case 4:
+ /* model processing has been finished due to error; delete
+ search trees, which may be created for some arrays */
+ { ARRAY *a;
+ for (a = mpl->a_list; a != NULL; a = a->next)
+ if (a->tree != NULL) avl_delete_tree(a->tree);
+ }
+#if 1 /* 11/II-2008 */
+ free_dca(mpl);
+#endif
+ break;
+ default:
+ xassert(mpl != mpl);
+ }
+ /* delete the translator database */
+ xfree(mpl->image);
+ xfree(mpl->b_image);
+ xfree(mpl->f_image);
+ xfree(mpl->context);
+ dmp_delete_pool(mpl->pool);
+ avl_delete_tree(mpl->tree);
+ dmp_delete_pool(mpl->strings);
+ dmp_delete_pool(mpl->symbols);
+ dmp_delete_pool(mpl->tuples);
+ dmp_delete_pool(mpl->arrays);
+ dmp_delete_pool(mpl->members);
+ dmp_delete_pool(mpl->elemvars);
+ dmp_delete_pool(mpl->formulae);
+ dmp_delete_pool(mpl->elemcons);
+ xfree(mpl->sym_buf);
+ xfree(mpl->tup_buf);
+ rng_delete_rand(mpl->rand);
+ if (mpl->row != NULL) xfree(mpl->row);
+ if (mpl->col != NULL) xfree(mpl->col);
+ if (mpl->in_fp != NULL) glp_close(mpl->in_fp);
+ if (mpl->out_fp != NULL && mpl->out_fp != (void *)stdout)
+ glp_close(mpl->out_fp);
+ if (mpl->out_file != NULL) xfree(mpl->out_file);
+ if (mpl->prt_fp != NULL) glp_close(mpl->prt_fp);
+ if (mpl->prt_file != NULL) xfree(mpl->prt_file);
+ if (mpl->mod_file != NULL) xfree(mpl->mod_file);
+ xfree(mpl->mpl_buf);
+ xfree(mpl);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/mpl/mpl5.c b/test/monniaux/glpk-4.65/src/mpl/mpl5.c
new file mode 100644
index 00000000..c5374c9c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/mpl/mpl5.c
@@ -0,0 +1,566 @@
+/* mpl5.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Authors: Andrew Makhorin <mao@gnu.org>
+* Heinrich Schuchardt <xypron.glpk@gmx.de>
+*
+* Copyright (C) 2003-2017 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/>.
+***********************************************************************/
+
+#if 1 /* 11/VI-2013 */
+#include "jd.h"
+#endif
+#include "mpl.h"
+
+double fn_gmtime(MPL *mpl)
+{ /* obtain the current calendar time (UTC) */
+ time_t timer;
+ struct tm *tm;
+ int j;
+ time(&timer);
+ if (timer == (time_t)(-1))
+err: error(mpl, "gmtime(); unable to obtain current calendar time");
+#if 0 /* 29/I-2017 */
+ tm = gmtime(&timer);
+#else
+ tm = xgmtime(&timer);
+#endif
+ if (tm == NULL) goto err;
+ j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+ if (j < 0) goto err;
+ return (((double)(j - jday(1, 1, 1970)) * 24.0 +
+ (double)tm->tm_hour) * 60.0 + (double)tm->tm_min) * 60.0 +
+ (double)tm->tm_sec;
+}
+
+static char *week[] = { "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday", "Sunday" };
+
+static char *moon[] = { "January", "February", "March", "April", "May",
+ "June", "July", "August", "September", "October", "November",
+ "December" };
+
+static void error1(MPL *mpl, const char *str, const char *s,
+ const char *fmt, const char *f, const char *msg)
+{ xprintf("Input string passed to str2time:\n");
+ xprintf("%s\n", str);
+ xprintf("%*s\n", (s - str) + 1, "^");
+ xprintf("Format string passed to str2time:\n");
+ xprintf("%s\n", fmt);
+ xprintf("%*s\n", (f - fmt) + 1, "^");
+ error(mpl, "%s", msg);
+ /* no return */
+}
+
+double fn_str2time(MPL *mpl, const char *str, const char *fmt)
+{ /* convert character string to the calendar time */
+ int j, year, month, day, hh, mm, ss, zone;
+ const char *s, *f;
+ year = month = day = hh = mm = ss = -1, zone = INT_MAX;
+ s = str;
+ for (f = fmt; *f != '\0'; f++)
+ { if (*f == '%')
+ { f++;
+ if (*f == 'b' || *f == 'h')
+ { /* the abbreviated month name */
+ int k;
+ char *name;
+ if (month >= 0)
+ error1(mpl, str, s, fmt, f, "month multiply specified"
+ );
+ while (*s == ' ') s++;
+ for (month = 1; month <= 12; month++)
+ { name = moon[month-1];
+ for (k = 0; k <= 2; k++)
+ { if (toupper((unsigned char)s[k]) !=
+ toupper((unsigned char)name[k])) goto next;
+ }
+ s += 3;
+ for (k = 3; name[k] != '\0'; k++)
+ { if (toupper((unsigned char)*s) !=
+ toupper((unsigned char)name[k])) break;
+ s++;
+ }
+ break;
+next: ;
+ }
+ if (month > 12)
+ error1(mpl, str, s, fmt, f, "abbreviated month name m"
+ "issing or invalid");
+ }
+ else if (*f == 'd')
+ { /* the day of the month as a decimal number (01..31) */
+ if (day >= 0)
+ error1(mpl, str, s, fmt, f, "day multiply specified");
+ while (*s == ' ') s++;
+ if (!('0' <= *s && *s <= '9'))
+ error1(mpl, str, s, fmt, f, "day missing or invalid");
+ day = (*s++) - '0';
+ if ('0' <= *s && *s <= '9')
+ day = 10 * day + ((*s++) - '0');
+ if (!(1 <= day && day <= 31))
+ error1(mpl, str, s, fmt, f, "day out of range");
+ }
+ else if (*f == 'H')
+ { /* the hour as a decimal number, using a 24-hour clock
+ (00..23) */
+ if (hh >= 0)
+ error1(mpl, str, s, fmt, f, "hour multiply specified")
+ ;
+ while (*s == ' ') s++;
+ if (!('0' <= *s && *s <= '9'))
+ error1(mpl, str, s, fmt, f, "hour missing or invalid")
+ ;
+ hh = (*s++) - '0';
+ if ('0' <= *s && *s <= '9')
+ hh = 10 * hh + ((*s++) - '0');
+ if (!(0 <= hh && hh <= 23))
+ error1(mpl, str, s, fmt, f, "hour out of range");
+ }
+ else if (*f == 'm')
+ { /* the month as a decimal number (01..12) */
+ if (month >= 0)
+ error1(mpl, str, s, fmt, f, "month multiply specified"
+ );
+ while (*s == ' ') s++;
+ if (!('0' <= *s && *s <= '9'))
+ error1(mpl, str, s, fmt, f, "month missing or invalid"
+ );
+ month = (*s++) - '0';
+ if ('0' <= *s && *s <= '9')
+ month = 10 * month + ((*s++) - '0');
+ if (!(1 <= month && month <= 12))
+ error1(mpl, str, s, fmt, f, "month out of range");
+ }
+ else if (*f == 'M')
+ { /* the minute as a decimal number (00..59) */
+ if (mm >= 0)
+ error1(mpl, str, s, fmt, f, "minute multiply specifie"
+ "d");
+ while (*s == ' ') s++;
+ if (!('0' <= *s && *s <= '9'))
+ error1(mpl, str, s, fmt, f, "minute missing or invali"
+ "d");
+ mm = (*s++) - '0';
+ if ('0' <= *s && *s <= '9')
+ mm = 10 * mm + ((*s++) - '0');
+ if (!(0 <= mm && mm <= 59))
+ error1(mpl, str, s, fmt, f, "minute out of range");
+ }
+ else if (*f == 'S')
+ { /* the second as a decimal number (00..60) */
+ if (ss >= 0)
+ error1(mpl, str, s, fmt, f, "second multiply specifie"
+ "d");
+ while (*s == ' ') s++;
+ if (!('0' <= *s && *s <= '9'))
+ error1(mpl, str, s, fmt, f, "second missing or invali"
+ "d");
+ ss = (*s++) - '0';
+ if ('0' <= *s && *s <= '9')
+ ss = 10 * ss + ((*s++) - '0');
+ if (!(0 <= ss && ss <= 60))
+ error1(mpl, str, s, fmt, f, "second out of range");
+ }
+ else if (*f == 'y')
+ { /* the year without a century as a decimal number
+ (00..99); the values 00 to 68 mean the years 2000 to
+ 2068 while the values 69 to 99 mean the years 1969 to
+ 1999 */
+ if (year >= 0)
+ error1(mpl, str, s, fmt, f, "year multiply specified")
+ ;
+ while (*s == ' ') s++;
+ if (!('0' <= *s && *s <= '9'))
+ error1(mpl, str, s, fmt, f, "year missing or invalid")
+ ;
+ year = (*s++) - '0';
+ if ('0' <= *s && *s <= '9')
+ year = 10 * year + ((*s++) - '0');
+ year += (year >= 69 ? 1900 : 2000);
+ }
+ else if (*f == 'Y')
+ { /* the year as a decimal number, using the Gregorian
+ calendar */
+ if (year >= 0)
+ error1(mpl, str, s, fmt, f, "year multiply specified")
+ ;
+ while (*s == ' ') s++;
+ if (!('0' <= *s && *s <= '9'))
+ error1(mpl, str, s, fmt, f, "year missing or invalid")
+ ;
+ year = 0;
+ for (j = 1; j <= 4; j++)
+ { if (!('0' <= *s && *s <= '9')) break;
+ year = 10 * year + ((*s++) - '0');
+ }
+ if (!(1 <= year && year <= 4000))
+ error1(mpl, str, s, fmt, f, "year out of range");
+ }
+ else if (*f == 'z')
+ { /* time zone offset in the form zhhmm */
+ int z, hh, mm;
+ if (zone != INT_MAX)
+ error1(mpl, str, s, fmt, f, "time zone offset multipl"
+ "y specified");
+ while (*s == ' ') s++;
+ if (*s == 'Z')
+ { z = hh = mm = 0, s++;
+ goto skip;
+ }
+ if (*s == '+')
+ z = +1, s++;
+ else if (*s == '-')
+ z = -1, s++;
+ else
+ error1(mpl, str, s, fmt, f, "time zone offset sign mi"
+ "ssing");
+ hh = 0;
+ for (j = 1; j <= 2; j++)
+ { if (!('0' <= *s && *s <= '9'))
+err1: error1(mpl, str, s, fmt, f, "time zone offset valu"
+ "e incomplete or invalid");
+ hh = 10 * hh + ((*s++) - '0');
+ }
+ if (hh > 23)
+err2: error1(mpl, str, s, fmt, f, "time zone offset value o"
+ "ut of range");
+ if (*s == ':')
+ { s++;
+ if (!('0' <= *s && *s <= '9')) goto err1;
+ }
+ mm = 0;
+ if (!('0' <= *s && *s <= '9')) goto skip;
+ for (j = 1; j <= 2; j++)
+ { if (!('0' <= *s && *s <= '9')) goto err1;
+ mm = 10 * mm + ((*s++) - '0');
+ }
+ if (mm > 59) goto err2;
+skip: zone = z * (60 * hh + mm);
+ }
+ else if (*f == '%')
+ { /* literal % character */
+ goto test;
+ }
+ else
+ error1(mpl, str, s, fmt, f, "invalid conversion specifie"
+ "r");
+ }
+ else if (*f == ' ')
+ ;
+ else
+test: { /* check a matching character in the input string */
+ if (*s != *f)
+ error1(mpl, str, s, fmt, f, "character mismatch");
+ s++;
+ }
+ }
+ if (year < 0) year = 1970;
+ if (month < 0) month = 1;
+ if (day < 0) day = 1;
+ if (hh < 0) hh = 0;
+ if (mm < 0) mm = 0;
+ if (ss < 0) ss = 0;
+ if (zone == INT_MAX) zone = 0;
+ j = jday(day, month, year);
+ xassert(j >= 0);
+ return (((double)(j - jday(1, 1, 1970)) * 24.0 + (double)hh) *
+ 60.0 + (double)mm) * 60.0 + (double)ss - 60.0 * (double)zone;
+}
+
+static void error2(MPL *mpl, const char *fmt, const char *f,
+ const char *msg)
+{ xprintf("Format string passed to time2str:\n");
+ xprintf("%s\n", fmt);
+ xprintf("%*s\n", (f - fmt) + 1, "^");
+ error(mpl, "%s", msg);
+ /* no return */
+}
+
+static int weekday(int j)
+{ /* determine weekday number (1 = Mon, ..., 7 = Sun) */
+ return (j + jday(1, 1, 1970)) % 7 + 1;
+}
+
+static int firstday(int year)
+{ /* determine the first day of the first week for a specified year
+ according to ISO 8601 */
+ int j;
+ /* if 1 January is Monday, Tuesday, Wednesday or Thursday, it is
+ in week 01; if 1 January is Friday, Saturday or Sunday, it is
+ in week 52 or 53 of the previous year */
+ j = jday(1, 1, year) - jday(1, 1, 1970);
+ switch (weekday(j))
+ { case 1: /* 1 Jan is Mon */ j += 0; break;
+ case 2: /* 1 Jan is Tue */ j -= 1; break;
+ case 3: /* 1 Jan is Wed */ j -= 2; break;
+ case 4: /* 1 Jan is Thu */ j -= 3; break;
+ case 5: /* 1 Jan is Fri */ j += 3; break;
+ case 6: /* 1 Jan is Sat */ j += 2; break;
+ case 7: /* 1 Jan is Sun */ j += 1; break;
+ default: xassert(j != j);
+ }
+ /* the first day of the week must be Monday */
+ xassert(weekday(j) == 1);
+ return j;
+}
+
+void fn_time2str(MPL *mpl, char *str, double t, const char *fmt)
+{ /* convert the calendar time to character string */
+ int j, year, month, day, hh, mm, ss, len;
+ double temp;
+ const char *f;
+ char buf[MAX_LENGTH+1];
+ if (!(-62135596800.0 <= t && t <= 64092211199.0))
+ error(mpl, "time2str(%.*g,...); argument out of range",
+ DBL_DIG, t);
+ t = floor(t + 0.5);
+ temp = fabs(t) / 86400.0;
+ j = (int)floor(temp);
+ if (t < 0.0)
+ { if (temp == floor(temp))
+ j = - j;
+ else
+ j = - (j + 1);
+ }
+ xassert(jdate(j + jday(1, 1, 1970), &day, &month, &year) == 0);
+ ss = (int)(t - 86400.0 * (double)j);
+ xassert(0 <= ss && ss < 86400);
+ mm = ss / 60, ss %= 60;
+ hh = mm / 60, mm %= 60;
+ len = 0;
+ for (f = fmt; *f != '\0'; f++)
+ { if (*f == '%')
+ { f++;
+ if (*f == 'a')
+ { /* the abbreviated weekday name */
+ memcpy(buf, week[weekday(j)-1], 3), buf[3] = '\0';
+ }
+ else if (*f == 'A')
+ { /* the full weekday name */
+ strcpy(buf, week[weekday(j)-1]);
+ }
+ else if (*f == 'b' || *f == 'h')
+ { /* the abbreviated month name */
+ memcpy(buf, moon[month-1], 3), buf[3] = '\0';
+ }
+ else if (*f == 'B')
+ { /* the full month name */
+ strcpy(buf, moon[month-1]);
+ }
+ else if (*f == 'C')
+ { /* the century of the year */
+ sprintf(buf, "%02d", year / 100);
+ }
+ else if (*f == 'd')
+ { /* the day of the month as a decimal number (01..31) */
+ sprintf(buf, "%02d", day);
+ }
+ else if (*f == 'D')
+ { /* the date using the format %m/%d/%y */
+ sprintf(buf, "%02d/%02d/%02d", month, day, year % 100);
+ }
+ else if (*f == 'e')
+ { /* the day of the month like with %d, but padded with
+ blank (1..31) */
+ sprintf(buf, "%2d", day);
+ }
+ else if (*f == 'F')
+ { /* the date using the format %Y-%m-%d */
+ sprintf(buf, "%04d-%02d-%02d", year, month, day);
+ }
+ else if (*f == 'g')
+ { /* the year corresponding to the ISO week number, but
+ without the century (range 00 through 99); this has
+ the same format and value as %y, except that if the
+ ISO week number (see %V) belongs to the previous or
+ next year, that year is used instead */
+ int iso;
+ if (j < firstday(year))
+ iso = year - 1;
+ else if (j < firstday(year + 1))
+ iso = year;
+ else
+ iso = year + 1;
+ sprintf(buf, "%02d", iso % 100);
+ }
+ else if (*f == 'G')
+ { /* the year corresponding to the ISO week number; this
+ has the same format and value as %Y, excepth that if
+ the ISO week number (see %V) belongs to the previous
+ or next year, that year is used instead */
+ int iso;
+ if (j < firstday(year))
+ iso = year - 1;
+ else if (j < firstday(year + 1))
+ iso = year;
+ else
+ iso = year + 1;
+ sprintf(buf, "%04d", iso);
+ }
+ else if (*f == 'H')
+ { /* the hour as a decimal number, using a 24-hour clock
+ (00..23) */
+ sprintf(buf, "%02d", hh);
+ }
+ else if (*f == 'I')
+ { /* the hour as a decimal number, using a 12-hour clock
+ (01..12) */
+ sprintf(buf, "%02d",
+ hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
+ }
+ else if (*f == 'j')
+ { /* the day of the year as a decimal number (001..366) */
+ sprintf(buf, "%03d",
+ jday(day, month, year) - jday(1, 1, year) + 1);
+ }
+ else if (*f == 'k')
+ { /* the hour as a decimal number, using a 24-hour clock
+ like %H, but padded with blank (0..23) */
+ sprintf(buf, "%2d", hh);
+ }
+ else if (*f == 'l')
+ { /* the hour as a decimal number, using a 12-hour clock
+ like %I, but padded with blank (1..12) */
+ sprintf(buf, "%2d",
+ hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
+ }
+ else if (*f == 'm')
+ { /* the month as a decimal number (01..12) */
+ sprintf(buf, "%02d", month);
+ }
+ else if (*f == 'M')
+ { /* the minute as a decimal number (00..59) */
+ sprintf(buf, "%02d", mm);
+ }
+ else if (*f == 'p')
+ { /* either AM or PM, according to the given time value;
+ noon is treated as PM and midnight as AM */
+ strcpy(buf, hh <= 11 ? "AM" : "PM");
+ }
+ else if (*f == 'P')
+ { /* either am or pm, according to the given time value;
+ noon is treated as pm and midnight as am */
+ strcpy(buf, hh <= 11 ? "am" : "pm");
+ }
+ else if (*f == 'r')
+ { /* the calendar time using the format %I:%M:%S %p */
+ sprintf(buf, "%02d:%02d:%02d %s",
+ hh == 0 ? 12 : hh <= 12 ? hh : hh - 12,
+ mm, ss, hh <= 11 ? "AM" : "PM");
+ }
+ else if (*f == 'R')
+ { /* the hour and minute using the format %H:%M */
+ sprintf(buf, "%02d:%02d", hh, mm);
+ }
+ else if (*f == 'S')
+ { /* the second as a decimal number (00..59) */
+ sprintf(buf, "%02d", ss);
+ }
+ else if (*f == 'T')
+ { /* the time of day using the format %H:%M:%S */
+ sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
+ }
+ else if (*f == 'u')
+ { /* the day of the week as a decimal number (1..7),
+ Monday being 1 */
+ sprintf(buf, "%d", weekday(j));
+ }
+ else if (*f == 'U')
+ { /* the week number of the current year as a decimal
+ number (range 00 through 53), starting with the first
+ Sunday as the first day of the first week; days
+ preceding the first Sunday in the year are considered
+ to be in week 00 */
+#if 1 /* 09/I-2009 */
+#undef sun
+/* causes compilation error in SunOS */
+#endif
+ int sun;
+ /* sun = the first Sunday of the year */
+ sun = jday(1, 1, year) - jday(1, 1, 1970);
+ sun += (7 - weekday(sun));
+ sprintf(buf, "%02d", (j + 7 - sun) / 7);
+ }
+ else if (*f == 'V')
+ { /* the ISO week number as a decimal number (range 01
+ through 53); ISO weeks start with Monday and end with
+ Sunday; week 01 of a year is the first week which has
+ the majority of its days in that year; week 01 of
+ a year can contain days from the previous year; the
+ week before week 01 of a year is the last week (52 or
+ 53) of the previous year even if it contains days
+ from the new year */
+ int iso;
+ if (j < firstday(year))
+ iso = j - firstday(year - 1);
+ else if (j < firstday(year + 1))
+ iso = j - firstday(year);
+ else
+ iso = j - firstday(year + 1);
+ sprintf(buf, "%02d", iso / 7 + 1);
+ }
+ else if (*f == 'w')
+ { /* the day of the week as a decimal number (0..6),
+ Sunday being 0 */
+ sprintf(buf, "%d", weekday(j) % 7);
+ }
+ else if (*f == 'W')
+ { /* the week number of the current year as a decimal
+ number (range 00 through 53), starting with the first
+ Monday as the first day of the first week; days
+ preceding the first Monday in the year are considered
+ to be in week 00 */
+ int mon;
+ /* mon = the first Monday of the year */
+ mon = jday(1, 1, year) - jday(1, 1, 1970);
+ mon += (8 - weekday(mon)) % 7;
+ sprintf(buf, "%02d", (j + 7 - mon) / 7);
+ }
+ else if (*f == 'y')
+ { /* the year without a century as a decimal number
+ (00..99) */
+ sprintf(buf, "%02d", year % 100);
+ }
+ else if (*f == 'Y')
+ { /* the year as a decimal number, using the Gregorian
+ calendar */
+ sprintf(buf, "%04d", year);
+ }
+ else if (*f == '%')
+ { /* a literal % character */
+ buf[0] = '%', buf[1] = '\0';
+ }
+ else
+ error2(mpl, fmt, f, "invalid conversion specifier");
+ }
+ else
+ buf[0] = *f, buf[1] = '\0';
+ if (len + strlen(buf) > MAX_LENGTH)
+ error(mpl, "time2str; output string length exceeds %d chara"
+ "cters", MAX_LENGTH);
+ memcpy(str+len, buf, strlen(buf));
+ len += strlen(buf);
+ }
+ str[len] = '\0';
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/mpl/mpl6.c b/test/monniaux/glpk-4.65/src/mpl/mpl6.c
new file mode 100644
index 00000000..ac2a0393
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/mpl/mpl6.c
@@ -0,0 +1,1039 @@
+/* mpl6.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2003-2017 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/>.
+***********************************************************************/
+
+#include "mpl.h"
+#include "mplsql.h"
+
+/**********************************************************************/
+
+#define CSV_FIELD_MAX 50
+/* maximal number of fields in record */
+
+#define CSV_FDLEN_MAX 100
+/* maximal field length */
+
+struct csv
+{ /* comma-separated values file */
+ int mode;
+ /* 'R' = reading; 'W' = writing */
+ char *fname;
+ /* name of csv file */
+ FILE *fp;
+ /* stream assigned to csv file */
+ jmp_buf jump;
+ /* address for non-local go to in case of error */
+ int count;
+ /* record count */
+ /*--------------------------------------------------------------*/
+ /* used only for input csv file */
+ int c;
+ /* current character or EOF */
+ int what;
+ /* current marker: */
+#define CSV_EOF 0 /* end-of-file */
+#define CSV_EOR 1 /* end-of-record */
+#define CSV_NUM 2 /* floating-point number */
+#define CSV_STR 3 /* character string */
+ char field[CSV_FDLEN_MAX+1];
+ /* current field just read */
+ int nf;
+ /* number of fields in the csv file */
+ int ref[1+CSV_FIELD_MAX];
+ /* ref[k] = k', if k-th field of the csv file corresponds to
+ k'-th field in the table statement; if ref[k] = 0, k-th field
+ of the csv file is ignored */
+#if 1 /* 01/VI-2010 */
+ int nskip;
+ /* number of comment records preceding the header record */
+#endif
+};
+
+#undef read_char
+
+static void read_char(struct csv *csv)
+{ /* read character from csv data file */
+ int c;
+ xassert(csv->c != EOF);
+ if (csv->c == '\n') csv->count++;
+loop: c = fgetc(csv->fp);
+ if (ferror(csv->fp))
+ { xprintf("%s:%d: read error - %s\n", csv->fname, csv->count,
+#if 0 /* 29/I-2017 */
+ strerror(errno));
+#else
+ xstrerr(errno));
+#endif
+ longjmp(csv->jump, 0);
+ }
+ if (feof(csv->fp))
+ { if (csv->c == '\n')
+ { csv->count--;
+ c = EOF;
+ }
+ else
+ { xprintf("%s:%d: warning: missing final end-of-line\n",
+ csv->fname, csv->count);
+ c = '\n';
+ }
+ }
+ else if (c == '\r')
+ goto loop;
+ else if (c == '\n')
+ ;
+ else if (iscntrl(c))
+ { xprintf("%s:%d: invalid control character 0x%02X\n",
+ csv->fname, csv->count, c);
+ longjmp(csv->jump, 0);
+ }
+ csv->c = c;
+ return;
+}
+
+static void read_field(struct csv *csv)
+{ /* read field from csv data file */
+ /* check for end of file */
+ if (csv->c == EOF)
+ { csv->what = CSV_EOF;
+ strcpy(csv->field, "EOF");
+ goto done;
+ }
+ /* check for end of record */
+ if (csv->c == '\n')
+ { csv->what = CSV_EOR;
+ strcpy(csv->field, "EOR");
+ read_char(csv);
+ if (csv->c == ',')
+err1: { xprintf("%s:%d: empty field not allowed\n", csv->fname,
+ csv->count);
+ longjmp(csv->jump, 0);
+ }
+ if (csv->c == '\n')
+ { xprintf("%s:%d: empty record not allowed\n", csv->fname,
+ csv->count);
+ longjmp(csv->jump, 0);
+ }
+#if 1 /* 01/VI-2010 */
+ /* skip comment records; may appear only before the very first
+ record containing field names */
+ if (csv->c == '#' && csv->count == 1)
+ { while (csv->c == '#')
+ { while (csv->c != '\n')
+ read_char(csv);
+ read_char(csv);
+ csv->nskip++;
+ }
+ }
+#endif
+ goto done;
+ }
+ /* skip comma before next field */
+ if (csv->c == ',')
+ read_char(csv);
+ /* read field */
+ if (csv->c == '\'' || csv->c == '"')
+ { /* read a field enclosed in quotes */
+ int quote = csv->c, len = 0;
+ csv->what = CSV_STR;
+ /* skip opening quote */
+ read_char(csv);
+ /* read field characters within quotes */
+ for (;;)
+ { /* check for closing quote and read it */
+ if (csv->c == quote)
+ { read_char(csv);
+ if (csv->c == quote)
+ ;
+ else if (csv->c == ',' || csv->c == '\n')
+ break;
+ else
+ { xprintf("%s:%d: invalid field\n", csv->fname,
+ csv->count);
+ longjmp(csv->jump, 0);
+ }
+ }
+ /* check the current field length */
+ if (len == CSV_FDLEN_MAX)
+err2: { xprintf("%s:%d: field too long\n", csv->fname,
+ csv->count);
+ longjmp(csv->jump, 0);
+ }
+ /* add the current character to the field */
+ csv->field[len++] = (char)csv->c;
+ /* read the next character */
+ read_char(csv);
+ }
+ /* the field has been read */
+ if (len == 0) goto err1;
+ csv->field[len] = '\0';
+ }
+ else
+ { /* read a field not enclosed in quotes */
+ int len = 0;
+ double temp;
+ csv->what = CSV_NUM;
+ while (!(csv->c == ',' || csv->c == '\n'))
+ { /* quotes within the field are not allowed */
+ if (csv->c == '\'' || csv->c == '"')
+ { xprintf("%s:%d: invalid use of single or double quote wi"
+ "thin field\n", csv->fname, csv->count);
+ longjmp(csv->jump, 0);
+ }
+ /* check the current field length */
+ if (len == CSV_FDLEN_MAX) goto err2;
+ /* add the current character to the field */
+ csv->field[len++] = (char)csv->c;
+ /* read the next character */
+ read_char(csv);
+ }
+ /* the field has been read */
+ if (len == 0) goto err1;
+ csv->field[len] = '\0';
+ /* check the field type */
+ if (str2num(csv->field, &temp)) csv->what = CSV_STR;
+ }
+done: return;
+}
+
+static struct csv *csv_open_file(TABDCA *dca, int mode)
+{ /* open csv data file */
+ struct csv *csv;
+ /* create control structure */
+ csv = xmalloc(sizeof(struct csv));
+ csv->mode = mode;
+ csv->fname = NULL;
+ csv->fp = NULL;
+ if (setjmp(csv->jump)) goto fail;
+ csv->count = 0;
+ csv->c = '\n';
+ csv->what = 0;
+ csv->field[0] = '\0';
+ csv->nf = 0;
+ /* try to open the csv data file */
+ if (mpl_tab_num_args(dca) < 2)
+ { xprintf("csv_driver: file name not specified\n");
+ longjmp(csv->jump, 0);
+ }
+ csv->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
+ strcpy(csv->fname, mpl_tab_get_arg(dca, 2));
+ if (mode == 'R')
+ { /* open the file for reading */
+ int k;
+ csv->fp = fopen(csv->fname, "r");
+ if (csv->fp == NULL)
+ { xprintf("csv_driver: unable to open %s - %s\n",
+#if 0 /* 29/I-2017 */
+ csv->fname, strerror(errno));
+#else
+ csv->fname, xstrerr(errno));
+#endif
+ longjmp(csv->jump, 0);
+ }
+#if 1 /* 01/VI-2010 */
+ csv->nskip = 0;
+#endif
+ /* skip fake new-line */
+ read_field(csv);
+ xassert(csv->what == CSV_EOR);
+ /* read field names */
+ xassert(csv->nf == 0);
+ for (;;)
+ { read_field(csv);
+ if (csv->what == CSV_EOR)
+ break;
+ if (csv->what != CSV_STR)
+ { xprintf("%s:%d: invalid field name\n", csv->fname,
+ csv->count);
+ longjmp(csv->jump, 0);
+ }
+ if (csv->nf == CSV_FIELD_MAX)
+ { xprintf("%s:%d: too many fields\n", csv->fname,
+ csv->count);
+ longjmp(csv->jump, 0);
+ }
+ csv->nf++;
+ /* find corresponding field in the table statement */
+ for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+ { if (strcmp(mpl_tab_get_name(dca, k), csv->field) == 0)
+ break;
+ }
+ csv->ref[csv->nf] = k;
+ }
+ /* find dummy RECNO field in the table statement */
+ for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+ if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
+ csv->ref[0] = k;
+ }
+ else if (mode == 'W')
+ { /* open the file for writing */
+ int k, nf;
+ csv->fp = fopen(csv->fname, "w");
+ if (csv->fp == NULL)
+ { xprintf("csv_driver: unable to create %s - %s\n",
+#if 0 /* 29/I-2017 */
+ csv->fname, strerror(errno));
+#else
+ csv->fname, xstrerr(errno));
+#endif
+ longjmp(csv->jump, 0);
+ }
+ /* write field names */
+ nf = mpl_tab_num_flds(dca);
+ for (k = 1; k <= nf; k++)
+ fprintf(csv->fp, "%s%c", mpl_tab_get_name(dca, k),
+ k < nf ? ',' : '\n');
+ csv->count++;
+ }
+ else
+ xassert(mode != mode);
+ /* the file has been open */
+ return csv;
+fail: /* the file cannot be open */
+ if (csv->fname != NULL) xfree(csv->fname);
+ if (csv->fp != NULL) fclose(csv->fp);
+ xfree(csv);
+ return NULL;
+}
+
+static int csv_read_record(TABDCA *dca, struct csv *csv)
+{ /* read next record from csv data file */
+ int k, ret = 0;
+ xassert(csv->mode == 'R');
+ if (setjmp(csv->jump))
+ { ret = 1;
+ goto done;
+ }
+ /* read dummy RECNO field */
+ if (csv->ref[0] > 0)
+#if 0 /* 01/VI-2010 */
+ mpl_tab_set_num(dca, csv->ref[0], csv->count-1);
+#else
+ mpl_tab_set_num(dca, csv->ref[0], csv->count-csv->nskip-1);
+#endif
+ /* read fields */
+ for (k = 1; k <= csv->nf; k++)
+ { read_field(csv);
+ if (csv->what == CSV_EOF)
+ { /* end-of-file reached */
+ xassert(k == 1);
+ ret = -1;
+ goto done;
+ }
+ else if (csv->what == CSV_EOR)
+ { /* end-of-record reached */
+ int lack = csv->nf - k + 1;
+ if (lack == 1)
+ xprintf("%s:%d: one field missing\n", csv->fname,
+ csv->count);
+ else
+ xprintf("%s:%d: %d fields missing\n", csv->fname,
+ csv->count, lack);
+ longjmp(csv->jump, 0);
+ }
+ else if (csv->what == CSV_NUM)
+ { /* floating-point number */
+ if (csv->ref[k] > 0)
+ { double num;
+ xassert(str2num(csv->field, &num) == 0);
+ mpl_tab_set_num(dca, csv->ref[k], num);
+ }
+ }
+ else if (csv->what == CSV_STR)
+ { /* character string */
+ if (csv->ref[k] > 0)
+ mpl_tab_set_str(dca, csv->ref[k], csv->field);
+ }
+ else
+ xassert(csv != csv);
+ }
+ /* now there must be NL */
+ read_field(csv);
+ xassert(csv->what != CSV_EOF);
+ if (csv->what != CSV_EOR)
+ { xprintf("%s:%d: too many fields\n", csv->fname, csv->count);
+ longjmp(csv->jump, 0);
+ }
+done: return ret;
+}
+
+static int csv_write_record(TABDCA *dca, struct csv *csv)
+{ /* write next record to csv data file */
+ int k, nf, ret = 0;
+ const char *c;
+ xassert(csv->mode == 'W');
+ nf = mpl_tab_num_flds(dca);
+ for (k = 1; k <= nf; k++)
+ { switch (mpl_tab_get_type(dca, k))
+ { case 'N':
+ fprintf(csv->fp, "%.*g", DBL_DIG,
+ mpl_tab_get_num(dca, k));
+ break;
+ case 'S':
+ fputc('"', csv->fp);
+ for (c = mpl_tab_get_str(dca, k); *c != '\0'; c++)
+ { if (*c == '"')
+ fputc('"', csv->fp), fputc('"', csv->fp);
+ else
+ fputc(*c, csv->fp);
+ }
+ fputc('"', csv->fp);
+ break;
+ default:
+ xassert(dca != dca);
+ }
+ fputc(k < nf ? ',' : '\n', csv->fp);
+ }
+ csv->count++;
+ if (ferror(csv->fp))
+ { xprintf("%s:%d: write error - %s\n", csv->fname, csv->count,
+#if 0 /* 29/I-2017 */
+ strerror(errno));
+#else
+ xstrerr(errno));
+#endif
+ ret = 1;
+ }
+ return ret;
+}
+
+static int csv_close_file(TABDCA *dca, struct csv *csv)
+{ /* close csv data file */
+ int ret = 0;
+ xassert(dca == dca);
+ if (csv->mode == 'W')
+ { fflush(csv->fp);
+ if (ferror(csv->fp))
+ { xprintf("%s:%d: write error - %s\n", csv->fname,
+#if 0 /* 29/I-2017 */
+ csv->count, strerror(errno));
+#else
+ csv->count, xstrerr(errno));
+#endif
+ ret = 1;
+ }
+ }
+ xfree(csv->fname);
+ fclose(csv->fp);
+ xfree(csv);
+ return ret;
+}
+
+/**********************************************************************/
+
+#define DBF_FIELD_MAX 50
+/* maximal number of fields in record */
+
+#define DBF_FDLEN_MAX 100
+/* maximal field length */
+
+struct dbf
+{ /* xBASE data file */
+ int mode;
+ /* 'R' = reading; 'W' = writing */
+ char *fname;
+ /* name of xBASE file */
+ FILE *fp;
+ /* stream assigned to xBASE file */
+ jmp_buf jump;
+ /* address for non-local go to in case of error */
+ int offset;
+ /* offset of a byte to be read next */
+ int count;
+ /* record count */
+ int nf;
+ /* number of fields */
+ int ref[1+DBF_FIELD_MAX];
+ /* ref[k] = k', if k-th field of the csv file corresponds to
+ k'-th field in the table statement; if ref[k] = 0, k-th field
+ of the csv file is ignored */
+ int type[1+DBF_FIELD_MAX];
+ /* type[k] is type of k-th field */
+ int len[1+DBF_FIELD_MAX];
+ /* len[k] is length of k-th field */
+ int prec[1+DBF_FIELD_MAX];
+ /* prec[k] is precision of k-th field */
+};
+
+static int read_byte(struct dbf *dbf)
+{ /* read byte from xBASE data file */
+ int b;
+ b = fgetc(dbf->fp);
+ if (ferror(dbf->fp))
+ { xprintf("%s:0x%X: read error - %s\n", dbf->fname,
+#if 0 /* 29/I-2017 */
+ dbf->offset, strerror(errno));
+#else
+ dbf->offset, xstrerr(errno));
+#endif
+ longjmp(dbf->jump, 0);
+ }
+ if (feof(dbf->fp))
+ { xprintf("%s:0x%X: unexpected end of file\n", dbf->fname,
+ dbf->offset);
+ longjmp(dbf->jump, 0);
+ }
+ xassert(0x00 <= b && b <= 0xFF);
+ dbf->offset++;
+ return b;
+}
+
+static void read_header(TABDCA *dca, struct dbf *dbf)
+{ /* read xBASE data file header */
+ int b, j, k, recl;
+ char name[10+1];
+ /* (ignored) */
+ for (j = 1; j <= 10; j++)
+ read_byte(dbf);
+ /* length of each record, in bytes */
+ recl = read_byte(dbf);
+ recl += read_byte(dbf) << 8;
+ /* (ignored) */
+ for (j = 1; j <= 20; j++)
+ read_byte(dbf);
+ /* field descriptor array */
+ xassert(dbf->nf == 0);
+ for (;;)
+ { /* check for end of array */
+ b = read_byte(dbf);
+ if (b == 0x0D) break;
+ if (dbf->nf == DBF_FIELD_MAX)
+ { xprintf("%s:0x%X: too many fields\n", dbf->fname,
+ dbf->offset);
+ longjmp(dbf->jump, 0);
+ }
+ dbf->nf++;
+ /* field name */
+ name[0] = (char)b;
+ for (j = 1; j < 10; j++)
+ { b = read_byte(dbf);
+ name[j] = (char)b;
+ }
+ name[10] = '\0';
+ b = read_byte(dbf);
+ if (b != 0x00)
+ { xprintf("%s:0x%X: invalid field name\n", dbf->fname,
+ dbf->offset);
+ longjmp(dbf->jump, 0);
+ }
+ /* find corresponding field in the table statement */
+ for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+ if (strcmp(mpl_tab_get_name(dca, k), name) == 0) break;
+ dbf->ref[dbf->nf] = k;
+ /* field type */
+ b = read_byte(dbf);
+ if (!(b == 'C' || b == 'N'))
+ { xprintf("%s:0x%X: invalid field type\n", dbf->fname,
+ dbf->offset);
+ longjmp(dbf->jump, 0);
+ }
+ dbf->type[dbf->nf] = b;
+ /* (ignored) */
+ for (j = 1; j <= 4; j++)
+ read_byte(dbf);
+ /* field length */
+ b = read_byte(dbf);
+ if (b == 0)
+ { xprintf("%s:0x%X: invalid field length\n", dbf->fname,
+ dbf->offset);
+ longjmp(dbf->jump, 0);
+ }
+ if (b > DBF_FDLEN_MAX)
+ { xprintf("%s:0x%X: field too long\n", dbf->fname,
+ dbf->offset);
+ longjmp(dbf->jump, 0);
+ }
+ dbf->len[dbf->nf] = b;
+ recl -= b;
+ /* (ignored) */
+ for (j = 1; j <= 15; j++)
+ read_byte(dbf);
+ }
+ if (recl != 1)
+ { xprintf("%s:0x%X: invalid file header\n", dbf->fname,
+ dbf->offset);
+ longjmp(dbf->jump, 0);
+ }
+ /* find dummy RECNO field in the table statement */
+ for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+ if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
+ dbf->ref[0] = k;
+ return;
+}
+
+static void parse_third_arg(TABDCA *dca, struct dbf *dbf)
+{ /* parse xBASE file format (third argument) */
+ int j, k, temp;
+ const char *arg;
+ dbf->nf = mpl_tab_num_flds(dca);
+ arg = mpl_tab_get_arg(dca, 3), j = 0;
+ for (k = 1; k <= dbf->nf; k++)
+ { /* parse specification of k-th field */
+ if (arg[j] == '\0')
+ { xprintf("xBASE driver: field %s: specification missing\n",
+ mpl_tab_get_name(dca, k));
+ longjmp(dbf->jump, 0);
+ }
+ /* parse field type */
+ if (arg[j] == 'C' || arg[j] == 'N')
+ dbf->type[k] = arg[j], j++;
+ else
+ { xprintf("xBASE driver: field %s: invalid field type\n",
+ mpl_tab_get_name(dca, k));
+ longjmp(dbf->jump, 0);
+ }
+ /* check for left parenthesis */
+ if (arg[j] == '(')
+ j++;
+ else
+err: { xprintf("xBASE driver: field %s: invalid field format\n",
+ mpl_tab_get_name(dca, k));
+ longjmp(dbf->jump, 0);
+ }
+ /* parse field length */
+ temp = 0;
+ while (isdigit(arg[j]))
+ { if (temp > DBF_FDLEN_MAX) break;
+ temp = 10 * temp + (arg[j] - '0'), j++;
+ }
+ if (!(1 <= temp && temp <= DBF_FDLEN_MAX))
+ { xprintf("xBASE driver: field %s: invalid field length\n",
+ mpl_tab_get_name(dca, k));
+ longjmp(dbf->jump, 0);
+ }
+ dbf->len[k] = temp;
+ /* parse optional field precision */
+ if (dbf->type[k] == 'N' && arg[j] == ',')
+ { j++;
+ temp = 0;
+ while (isdigit(arg[j]))
+ { if (temp > dbf->len[k]) break;
+ temp = 10 * temp + (arg[j] - '0'), j++;
+ }
+ if (temp > dbf->len[k])
+ { xprintf("xBASE driver: field %s: invalid field precision"
+ "\n", mpl_tab_get_name(dca, k));
+ longjmp(dbf->jump, 0);
+ }
+ dbf->prec[k] = temp;
+ }
+ else
+ dbf->prec[k] = 0;
+ /* check for right parenthesis */
+ if (arg[j] == ')')
+ j++;
+ else
+ goto err;
+ }
+ /* ignore other specifications */
+ return;
+}
+
+static void write_byte(struct dbf *dbf, int b)
+{ /* write byte to xBASE data file */
+ fputc(b, dbf->fp);
+ dbf->offset++;
+ return;
+}
+
+static void write_header(TABDCA *dca, struct dbf *dbf)
+{ /* write xBASE data file header */
+ int j, k, temp;
+ const char *name;
+ /* version number */
+ write_byte(dbf, 0x03 /* file without DBT */);
+ /* date of last update (YYMMDD) */
+ write_byte(dbf, 70 /* 1970 */);
+ write_byte(dbf, 1 /* January */);
+ write_byte(dbf, 1 /* 1st */);
+ /* number of records (unknown so far) */
+ for (j = 1; j <= 4; j++)
+ write_byte(dbf, 0xFF);
+ /* length of the header, in bytes */
+ temp = 32 + dbf->nf * 32 + 1;
+ write_byte(dbf, temp);
+ write_byte(dbf, temp >> 8);
+ /* length of each record, in bytes */
+ temp = 1;
+ for (k = 1; k <= dbf->nf; k++)
+ temp += dbf->len[k];
+ write_byte(dbf, temp);
+ write_byte(dbf, temp >> 8);
+ /* (reserved) */
+ for (j = 1; j <= 20; j++)
+ write_byte(dbf, 0x00);
+ /* field descriptor array */
+ for (k = 1; k <= dbf->nf; k++)
+ { /* field name (terminated by 0x00) */
+ name = mpl_tab_get_name(dca, k);
+ for (j = 0; j < 10 && name[j] != '\0'; j++)
+ write_byte(dbf, name[j]);
+ for (j = j; j < 11; j++)
+ write_byte(dbf, 0x00);
+ /* field type */
+ write_byte(dbf, dbf->type[k]);
+ /* (reserved) */
+ for (j = 1; j <= 4; j++)
+ write_byte(dbf, 0x00);
+ /* field length */
+ write_byte(dbf, dbf->len[k]);
+ /* field precision */
+ write_byte(dbf, dbf->prec[k]);
+ /* (reserved) */
+ for (j = 1; j <= 14; j++)
+ write_byte(dbf, 0x00);
+ }
+ /* end of header */
+ write_byte(dbf, 0x0D);
+ return;
+}
+
+static struct dbf *dbf_open_file(TABDCA *dca, int mode)
+{ /* open xBASE data file */
+ struct dbf *dbf;
+ /* create control structure */
+ dbf = xmalloc(sizeof(struct dbf));
+ dbf->mode = mode;
+ dbf->fname = NULL;
+ dbf->fp = NULL;
+ if (setjmp(dbf->jump)) goto fail;
+ dbf->offset = 0;
+ dbf->count = 0;
+ dbf->nf = 0;
+ /* try to open the xBASE data file */
+ if (mpl_tab_num_args(dca) < 2)
+ { xprintf("xBASE driver: file name not specified\n");
+ longjmp(dbf->jump, 0);
+ }
+ dbf->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
+ strcpy(dbf->fname, mpl_tab_get_arg(dca, 2));
+ if (mode == 'R')
+ { /* open the file for reading */
+ dbf->fp = fopen(dbf->fname, "rb");
+ if (dbf->fp == NULL)
+ { xprintf("xBASE driver: unable to open %s - %s\n",
+#if 0 /* 29/I-2017 */
+ dbf->fname, strerror(errno));
+#else
+ dbf->fname, xstrerr(errno));
+#endif
+ longjmp(dbf->jump, 0);
+ }
+ read_header(dca, dbf);
+ }
+ else if (mode == 'W')
+ { /* open the file for writing */
+ if (mpl_tab_num_args(dca) < 3)
+ { xprintf("xBASE driver: file format not specified\n");
+ longjmp(dbf->jump, 0);
+ }
+ parse_third_arg(dca, dbf);
+ dbf->fp = fopen(dbf->fname, "wb");
+ if (dbf->fp == NULL)
+ { xprintf("xBASE driver: unable to create %s - %s\n",
+#if 0 /* 29/I-2017 */
+ dbf->fname, strerror(errno));
+#else
+ dbf->fname, xstrerr(errno));
+#endif
+ longjmp(dbf->jump, 0);
+ }
+ write_header(dca, dbf);
+ }
+ else
+ xassert(mode != mode);
+ /* the file has been open */
+ return dbf;
+fail: /* the file cannot be open */
+ if (dbf->fname != NULL) xfree(dbf->fname);
+ if (dbf->fp != NULL) fclose(dbf->fp);
+ xfree(dbf);
+ return NULL;
+}
+
+static int dbf_read_record(TABDCA *dca, struct dbf *dbf)
+{ /* read next record from xBASE data file */
+ int b, j, k, ret = 0;
+ char buf[DBF_FDLEN_MAX+1];
+ xassert(dbf->mode == 'R');
+ if (setjmp(dbf->jump))
+ { ret = 1;
+ goto done;
+ }
+ /* check record flag */
+ b = read_byte(dbf);
+ if (b == 0x1A)
+ { /* end of data */
+ ret = -1;
+ goto done;
+ }
+ if (b != 0x20)
+ { xprintf("%s:0x%X: invalid record flag\n", dbf->fname,
+ dbf->offset);
+ longjmp(dbf->jump, 0);
+ }
+ /* read dummy RECNO field */
+ if (dbf->ref[0] > 0)
+ mpl_tab_set_num(dca, dbf->ref[0], dbf->count+1);
+ /* read fields */
+ for (k = 1; k <= dbf->nf; k++)
+ { /* read k-th field */
+ for (j = 0; j < dbf->len[k]; j++)
+ buf[j] = (char)read_byte(dbf);
+ buf[dbf->len[k]] = '\0';
+ /* set field value */
+ if (dbf->type[k] == 'C')
+ { /* character field */
+ if (dbf->ref[k] > 0)
+ mpl_tab_set_str(dca, dbf->ref[k], strtrim(buf));
+ }
+ else if (dbf->type[k] == 'N')
+ { /* numeric field */
+ if (dbf->ref[k] > 0)
+ { double num;
+ strspx(buf);
+ xassert(str2num(buf, &num) == 0);
+ mpl_tab_set_num(dca, dbf->ref[k], num);
+ }
+ }
+ else
+ xassert(dbf != dbf);
+ }
+ /* increase record count */
+ dbf->count++;
+done: return ret;
+}
+
+static int dbf_write_record(TABDCA *dca, struct dbf *dbf)
+{ /* write next record to xBASE data file */
+ int j, k, ret = 0;
+ char buf[255+1];
+ xassert(dbf->mode == 'W');
+ if (setjmp(dbf->jump))
+ { ret = 1;
+ goto done;
+ }
+ /* record flag */
+ write_byte(dbf, 0x20);
+ xassert(dbf->nf == mpl_tab_num_flds(dca));
+ for (k = 1; k <= dbf->nf; k++)
+ { if (dbf->type[k] == 'C')
+ { /* character field */
+ const char *str;
+ if (mpl_tab_get_type(dca, k) == 'N')
+ { sprintf(buf, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
+ str = buf;
+ }
+ else if (mpl_tab_get_type(dca, k) == 'S')
+ str = mpl_tab_get_str(dca, k);
+ else
+ xassert(dca != dca);
+ if ((int)strlen(str) > dbf->len[k])
+ { xprintf("xBASE driver: field %s: cannot convert %.15s..."
+ " to field format\n", mpl_tab_get_name(dca, k), str);
+ longjmp(dbf->jump, 0);
+ }
+ for (j = 0; j < dbf->len[k] && str[j] != '\0'; j++)
+ write_byte(dbf, str[j]);
+ for (j = j; j < dbf->len[k]; j++)
+ write_byte(dbf, ' ');
+ }
+ else if (dbf->type[k] == 'N')
+ { /* numeric field */
+ double num = mpl_tab_get_num(dca, k);
+ if (fabs(num) > 1e20)
+err: { xprintf("xBASE driver: field %s: cannot convert %g to fi"
+ "eld format\n", mpl_tab_get_name(dca, k), num);
+ longjmp(dbf->jump, 0);
+ }
+ sprintf(buf, "%*.*f", dbf->len[k], dbf->prec[k], num);
+ xassert(strlen(buf) < sizeof(buf));
+ if ((int)strlen(buf) != dbf->len[k]) goto err;
+ for (j = 0; j < dbf->len[k]; j++)
+ write_byte(dbf, buf[j]);
+ }
+ else
+ xassert(dbf != dbf);
+ }
+ /* increase record count */
+ dbf->count++;
+done: return ret;
+}
+
+static int dbf_close_file(TABDCA *dca, struct dbf *dbf)
+{ /* close xBASE data file */
+ int ret = 0;
+ xassert(dca == dca);
+ if (dbf->mode == 'W')
+ { if (setjmp(dbf->jump))
+ { ret = 1;
+ goto skip;
+ }
+ /* end-of-file flag */
+ write_byte(dbf, 0x1A);
+ /* number of records */
+ dbf->offset = 4;
+ if (fseek(dbf->fp, dbf->offset, SEEK_SET))
+ { xprintf("%s:0x%X: seek error - %s\n", dbf->fname,
+#if 0 /* 29/I-2017 */
+ dbf->offset, strerror(errno));
+#else
+ dbf->offset, xstrerr(errno));
+#endif
+ longjmp(dbf->jump, 0);
+ }
+ write_byte(dbf, dbf->count);
+ write_byte(dbf, dbf->count >> 8);
+ write_byte(dbf, dbf->count >> 16);
+ write_byte(dbf, dbf->count >> 24);
+ fflush(dbf->fp);
+ if (ferror(dbf->fp))
+ { xprintf("%s:0x%X: write error - %s\n", dbf->fname,
+#if 0 /* 29/I-2017 */
+ dbf->offset, strerror(errno));
+#else
+ dbf->offset, xstrerr(errno));
+#endif
+ longjmp(dbf->jump, 0);
+ }
+skip: ;
+ }
+ xfree(dbf->fname);
+ fclose(dbf->fp);
+ xfree(dbf);
+ return ret;
+}
+
+/**********************************************************************/
+
+#define TAB_CSV 1
+#define TAB_XBASE 2
+#define TAB_ODBC 3
+#define TAB_MYSQL 4
+
+void mpl_tab_drv_open(MPL *mpl, int mode)
+{ TABDCA *dca = mpl->dca;
+ xassert(dca->id == 0);
+ xassert(dca->link == NULL);
+ xassert(dca->na >= 1);
+ if (strcmp(dca->arg[1], "CSV") == 0)
+ { dca->id = TAB_CSV;
+ dca->link = csv_open_file(dca, mode);
+ }
+ else if (strcmp(dca->arg[1], "xBASE") == 0)
+ { dca->id = TAB_XBASE;
+ dca->link = dbf_open_file(dca, mode);
+ }
+ else if (strcmp(dca->arg[1], "ODBC") == 0 ||
+ strcmp(dca->arg[1], "iODBC") == 0)
+ { dca->id = TAB_ODBC;
+ dca->link = db_iodbc_open(dca, mode);
+ }
+ else if (strcmp(dca->arg[1], "MySQL") == 0)
+ { dca->id = TAB_MYSQL;
+ dca->link = db_mysql_open(dca, mode);
+ }
+ else
+ xprintf("Invalid table driver '%s'\n", dca->arg[1]);
+ if (dca->link == NULL)
+ error(mpl, "error on opening table %s",
+ mpl->stmt->u.tab->name);
+ return;
+}
+
+int mpl_tab_drv_read(MPL *mpl)
+{ TABDCA *dca = mpl->dca;
+ int ret;
+ switch (dca->id)
+ { case TAB_CSV:
+ ret = csv_read_record(dca, dca->link);
+ break;
+ case TAB_XBASE:
+ ret = dbf_read_record(dca, dca->link);
+ break;
+ case TAB_ODBC:
+ ret = db_iodbc_read(dca, dca->link);
+ break;
+ case TAB_MYSQL:
+ ret = db_mysql_read(dca, dca->link);
+ break;
+ default:
+ xassert(dca != dca);
+ }
+ if (ret > 0)
+ error(mpl, "error on reading data from table %s",
+ mpl->stmt->u.tab->name);
+ return ret;
+}
+
+void mpl_tab_drv_write(MPL *mpl)
+{ TABDCA *dca = mpl->dca;
+ int ret;
+ switch (dca->id)
+ { case TAB_CSV:
+ ret = csv_write_record(dca, dca->link);
+ break;
+ case TAB_XBASE:
+ ret = dbf_write_record(dca, dca->link);
+ break;
+ case TAB_ODBC:
+ ret = db_iodbc_write(dca, dca->link);
+ break;
+ case TAB_MYSQL:
+ ret = db_mysql_write(dca, dca->link);
+ break;
+ default:
+ xassert(dca != dca);
+ }
+ if (ret)
+ error(mpl, "error on writing data to table %s",
+ mpl->stmt->u.tab->name);
+ return;
+}
+
+void mpl_tab_drv_close(MPL *mpl)
+{ TABDCA *dca = mpl->dca;
+ int ret;
+ switch (dca->id)
+ { case TAB_CSV:
+ ret = csv_close_file(dca, dca->link);
+ break;
+ case TAB_XBASE:
+ ret = dbf_close_file(dca, dca->link);
+ break;
+ case TAB_ODBC:
+ ret = db_iodbc_close(dca, dca->link);
+ break;
+ case TAB_MYSQL:
+ ret = db_mysql_close(dca, dca->link);
+ break;
+ default:
+ xassert(dca != dca);
+ }
+ dca->id = 0;
+ dca->link = NULL;
+ if (ret)
+ error(mpl, "error on closing table %s",
+ mpl->stmt->u.tab->name);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/mpl/mplsql.c b/test/monniaux/glpk-4.65/src/mpl/mplsql.c
new file mode 100644
index 00000000..fcd2afa6
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/mpl/mplsql.c
@@ -0,0 +1,1659 @@
+/* mplsql.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Author: Heinrich Schuchardt <xypron.glpk@gmx.de>.
+*
+* Copyright (C) 2003-2017 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/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "mpl.h"
+#include "mplsql.h"
+
+#ifdef ODBC_DLNAME
+#define HAVE_ODBC
+#define libodbc ODBC_DLNAME
+#define h_odbc (get_env_ptr()->h_odbc)
+#endif
+
+#ifdef MYSQL_DLNAME
+#define HAVE_MYSQL
+#define libmysql MYSQL_DLNAME
+#define h_mysql (get_env_ptr()->h_mysql)
+#endif
+
+static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
+ **sqllines);
+static void *db_mysql_open_int(TABDCA *dca, int mode, const char
+ **sqllines);
+
+/**********************************************************************/
+
+#if defined(HAVE_ODBC) || defined(HAVE_MYSQL)
+
+#define SQL_FIELD_MAX 100
+/* maximal field count */
+
+#define SQL_FDLEN_MAX 255
+/* maximal field length */
+
+/***********************************************************************
+* NAME
+*
+* args_concat - concatenate arguments
+*
+* SYNOPSIS
+*
+* static char **args_concat(TABDCA *dca);
+*
+* DESCRIPTION
+*
+* The arguments passed in dca are SQL statements. A SQL statement may
+* be split over multiple arguments. The last argument of a SQL
+* statement will be terminated with a semilocon. Each SQL statement is
+* merged into a single zero terminated string. Boundaries between
+* arguments are replaced by space.
+*
+* RETURNS
+*
+* Buffer with SQL statements */
+
+static char **args_concat(TABDCA *dca)
+{
+ const char *arg;
+ int i;
+ int j;
+ int j0;
+ int j1;
+ size_t len;
+ int lentot;
+ int narg;
+ int nline = 0;
+ char **sqllines = NULL;
+
+ narg = mpl_tab_num_args(dca);
+ /* The SQL statements start with argument 3. */
+ if (narg < 3)
+ return NULL;
+ /* Count the SQL statements */
+ for (j = 3; j <= narg; j++)
+ {
+ arg = mpl_tab_get_arg(dca, j);
+ len = strlen(arg);
+ if (arg[len-1] == ';' || j == narg)
+ nline ++;
+ }
+ /* Allocate string buffer. */
+ sqllines = (char **) xmalloc((nline+1) * sizeof(char **));
+ /* Join arguments */
+ sqllines[0] = NULL;
+ j0 = 3;
+ i = 0;
+ lentot = 0;
+ for (j = 3; j <= narg; j++)
+ {
+ arg = mpl_tab_get_arg(dca, j);
+ len = strlen(arg);
+ /* add length of part */
+ lentot += len;
+ /* add length of space separating parts or 0x00 at end of SQL
+ statement */
+ lentot++;
+ if (arg[len-1] == ';' || j == narg)
+ { /* Join arguments for a single SQL statement */
+ sqllines[i] = xmalloc(lentot);
+ sqllines[i+1] = NULL;
+ sqllines[i][0] = 0x00;
+ for (j1 = j0; j1 <= j; j1++)
+ { if(j1>j0)
+ strcat(sqllines[i], " ");
+ strcat(sqllines[i], mpl_tab_get_arg(dca, j1));
+ }
+ len = strlen(sqllines[i]);
+ if (sqllines[i][len-1] == ';')
+ sqllines[i][len-1] = 0x00;
+ j0 = j+1;
+ i++;
+ lentot = 0;
+ }
+ }
+ return sqllines;
+}
+
+/***********************************************************************
+* NAME
+*
+* free_buffer - free multiline string buffer
+*
+* SYNOPSIS
+*
+* static void free_buffer(char **buf);
+*
+* DESCRIPTION
+*
+* buf is a list of strings terminated by NULL.
+* The memory for the strings and for the list is released. */
+
+static void free_buffer(char **buf)
+{ int i;
+
+ for(i = 0; buf[i] != NULL; i++)
+ xfree(buf[i]);
+ xfree(buf);
+}
+
+static int db_escaped_string_length(const char* from)
+/* length of escaped string */
+{
+ int count;
+ const char *pointer;
+
+ for (pointer = from, count = 0; *pointer != (char) '\0'; pointer++,
+ count++)
+ {
+ switch (*pointer)
+ {
+ case '\'':
+ count++;
+ break;
+ }
+ }
+
+ return count;
+}
+
+static void db_escape_string (char *to, const char *from)
+/* escape string*/
+{
+ const char *source = from;
+ char *target = to;
+ size_t remaining;
+
+ remaining = strlen(from);
+
+ if (to == NULL)
+ to = (char *) (from + remaining);
+
+ while (remaining > 0)
+ {
+ switch (*source)
+ {
+ case '\'':
+ *target = '\'';
+ target++;
+ *target = '\'';
+ break;
+
+ default:
+ *target = *source;
+ }
+ source++;
+ target++;
+ remaining--;
+ }
+
+ /* Write the terminating NUL character. */
+ *target = '\0';
+}
+
+static char *db_generate_select_stmt(TABDCA *dca)
+/* generate select statement */
+{
+ char *arg;
+ char const *field;
+ char *query;
+ int j;
+ int narg;
+ int nf;
+ int total;
+
+ total = 50;
+ nf = mpl_tab_num_flds(dca);
+ narg = mpl_tab_num_args(dca);
+ for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+ {
+ field = mpl_tab_get_name(dca, j);
+ total += strlen(field);
+ total += 2;
+ }
+ arg = (char *) mpl_tab_get_arg(dca, narg);
+ total += strlen(arg);
+ query = xmalloc( total * sizeof(char));
+ strcpy (query, "SELECT ");
+ for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+ {
+ field = mpl_tab_get_name(dca, j);
+ strcat(query, field);
+ if ( j < nf )
+ strcat(query, ", ");
+ }
+ strcat(query, " FROM ");
+ strcat(query, arg);
+ return query;
+}
+
+static char *db_generate_insert_stmt(TABDCA *dca)
+/* generate insert statement */
+{
+ char *arg;
+ char const *field;
+ char *query;
+ int j;
+ int narg;
+ int nf;
+ int total;
+
+ total = 50;
+ nf = mpl_tab_num_flds(dca);
+ narg = mpl_tab_num_args(dca);
+ for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+ {
+ field = mpl_tab_get_name(dca, j);
+ total += strlen(field);
+ total += 5;
+ }
+ arg = (char *) mpl_tab_get_arg(dca, narg);
+ total += strlen(arg);
+ query = xmalloc( (total+1) * sizeof(char));
+ strcpy (query, "INSERT INTO ");
+ strcat(query, arg);
+ strcat(query, " ( ");
+ for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+ {
+ field = mpl_tab_get_name(dca, j);
+ strcat(query, field);
+ if ( j < nf )
+ strcat(query, ", ");
+ }
+ strcat(query, " ) VALUES ( ");
+ for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+ {
+ strcat(query, "?");
+ if ( j < nf )
+ strcat(query, ", ");
+ }
+ strcat(query, " )");
+ return query;
+}
+
+#endif
+
+/**********************************************************************/
+
+#ifndef HAVE_ODBC
+
+void *db_iodbc_open(TABDCA *dca, int mode)
+{ xassert(dca == dca);
+ xassert(mode == mode);
+ xprintf("iODBC table driver not supported\n");
+ return NULL;
+}
+
+int db_iodbc_read(TABDCA *dca, void *link)
+{ xassert(dca != dca);
+ xassert(link != link);
+ return 0;
+}
+
+int db_iodbc_write(TABDCA *dca, void *link)
+{ xassert(dca != dca);
+ xassert(link != link);
+ return 0;
+}
+
+int db_iodbc_close(TABDCA *dca, void *link)
+{ xassert(dca != dca);
+ xassert(link != link);
+ return 0;
+}
+
+#else
+
+#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
+#include <windows.h>
+#endif
+
+#include <sql.h>
+#include <sqlext.h>
+
+struct db_odbc
+{
+ int mode; /*'R' = Read, 'W' = Write*/
+ SQLHDBC hdbc; /*connection handle*/
+ SQLHENV henv; /*environment handle*/
+ SQLHSTMT hstmt; /*statement handle*/
+ SQLSMALLINT nresultcols; /* columns in result*/
+ SQLULEN collen[SQL_FIELD_MAX+1];
+ SQLLEN outlen[SQL_FIELD_MAX+1];
+ SQLSMALLINT coltype[SQL_FIELD_MAX+1];
+ SQLCHAR data[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
+#if 1 /* 12/I-2014 */
+ SQLDOUBLE datanum[SQL_FIELD_MAX+1];
+#endif
+ SQLCHAR colname[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
+ int isnumeric[SQL_FIELD_MAX+1];
+ int nf;
+ /* number of fields in the csv file */
+ int ref[1+SQL_FIELD_MAX];
+ /* ref[k] = k', if k-th field of the csv file corresponds to
+ k'-th field in the table statement; if ref[k] = 0, k-th field
+ of the csv file is ignored */
+ SQLCHAR *query;
+ /* query generated by db_iodbc_open */
+};
+
+SQLRETURN SQL_API dl_SQLAllocHandle (
+ SQLSMALLINT HandleType,
+ SQLHANDLE InputHandle,
+ SQLHANDLE *OutputHandle)
+{
+ typedef SQLRETURN SQL_API ep_SQLAllocHandle(
+ SQLSMALLINT HandleType,
+ SQLHANDLE InputHandle,
+ SQLHANDLE *OutputHandle);
+
+ ep_SQLAllocHandle *fn;
+ fn = (ep_SQLAllocHandle *) xdlsym(h_odbc, "SQLAllocHandle");
+ xassert(fn != NULL);
+ return (*fn)(HandleType, InputHandle, OutputHandle);
+}
+
+SQLRETURN SQL_API dl_SQLBindCol (
+ SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLSMALLINT TargetType,
+ SQLPOINTER TargetValue,
+ SQLLEN BufferLength,
+ SQLLEN *StrLen_or_Ind)
+{
+ typedef SQLRETURN SQL_API ep_SQLBindCol(
+ SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLSMALLINT TargetType,
+ SQLPOINTER TargetValue,
+ SQLLEN BufferLength,
+ SQLLEN *StrLen_or_Ind);
+ ep_SQLBindCol *fn;
+ fn = (ep_SQLBindCol *) xdlsym(h_odbc, "SQLBindCol");
+ xassert(fn != NULL);
+ return (*fn)(StatementHandle, ColumnNumber, TargetType,
+ TargetValue, BufferLength, StrLen_or_Ind);
+}
+
+SQLRETURN SQL_API dl_SQLCloseCursor (
+ SQLHSTMT StatementHandle)
+{
+ typedef SQLRETURN SQL_API ep_SQLCloseCursor (
+ SQLHSTMT StatementHandle);
+
+ ep_SQLCloseCursor *fn;
+ fn = (ep_SQLCloseCursor *) xdlsym(h_odbc, "SQLCloseCursor");
+ xassert(fn != NULL);
+ return (*fn)(StatementHandle);
+}
+
+
+SQLRETURN SQL_API dl_SQLDisconnect (
+ SQLHDBC ConnectionHandle)
+{
+ typedef SQLRETURN SQL_API ep_SQLDisconnect(
+ SQLHDBC ConnectionHandle);
+
+ ep_SQLDisconnect *fn;
+ fn = (ep_SQLDisconnect *) xdlsym(h_odbc, "SQLDisconnect");
+ xassert(fn != NULL);
+ return (*fn)(ConnectionHandle);
+}
+
+SQLRETURN SQL_API dl_SQLDriverConnect (
+ SQLHDBC hdbc,
+ SQLHWND hwnd,
+ SQLCHAR *szConnStrIn,
+ SQLSMALLINT cbConnStrIn,
+ SQLCHAR *szConnStrOut,
+ SQLSMALLINT cbConnStrOutMax,
+ SQLSMALLINT *pcbConnStrOut,
+ SQLUSMALLINT fDriverCompletion)
+{
+ typedef SQLRETURN SQL_API ep_SQLDriverConnect(
+ SQLHDBC hdbc,
+ SQLHWND hwnd,
+ SQLCHAR * szConnStrIn,
+ SQLSMALLINT cbConnStrIn,
+ SQLCHAR * szConnStrOut,
+ SQLSMALLINT cbConnStrOutMax,
+ SQLSMALLINT * pcbConnStrOut,
+ SQLUSMALLINT fDriverCompletion);
+
+ ep_SQLDriverConnect *fn;
+ fn = (ep_SQLDriverConnect *) xdlsym(h_odbc, "SQLDriverConnect");
+ xassert(fn != NULL);
+ return (*fn)(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut,
+ cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
+}
+
+SQLRETURN SQL_API dl_SQLEndTran (
+ SQLSMALLINT HandleType,
+ SQLHANDLE Handle,
+ SQLSMALLINT CompletionType)
+{
+ typedef SQLRETURN SQL_API ep_SQLEndTran (
+ SQLSMALLINT HandleType,
+ SQLHANDLE Handle,
+ SQLSMALLINT CompletionType);
+
+ ep_SQLEndTran *fn;
+ fn = (ep_SQLEndTran *) xdlsym(h_odbc, "SQLEndTran");
+ xassert(fn != NULL);
+ return (*fn)(HandleType, Handle, CompletionType);
+}
+
+SQLRETURN SQL_API dl_SQLExecDirect (
+ SQLHSTMT StatementHandle,
+ SQLCHAR * StatementText,
+ SQLINTEGER TextLength)
+{
+ typedef SQLRETURN SQL_API ep_SQLExecDirect (
+ SQLHSTMT StatementHandle,
+ SQLCHAR * StatementText,
+ SQLINTEGER TextLength);
+
+ ep_SQLExecDirect *fn;
+ fn = (ep_SQLExecDirect *) xdlsym(h_odbc, "SQLExecDirect");
+ xassert(fn != NULL);
+ return (*fn)(StatementHandle, StatementText, TextLength);
+}
+
+SQLRETURN SQL_API dl_SQLFetch (
+ SQLHSTMT StatementHandle)
+{
+ typedef SQLRETURN SQL_API ep_SQLFetch (
+ SQLHSTMT StatementHandle);
+
+ ep_SQLFetch *fn;
+ fn = (ep_SQLFetch*) xdlsym(h_odbc, "SQLFetch");
+ xassert(fn != NULL);
+ return (*fn)(StatementHandle);
+}
+
+SQLRETURN SQL_API dl_SQLFreeHandle (
+ SQLSMALLINT HandleType,
+ SQLHANDLE Handle)
+{
+ typedef SQLRETURN SQL_API ep_SQLFreeHandle (
+ SQLSMALLINT HandleType,
+ SQLHANDLE Handle);
+
+ ep_SQLFreeHandle *fn;
+ fn = (ep_SQLFreeHandle *) xdlsym(h_odbc, "SQLFreeHandle");
+ xassert(fn != NULL);
+ return (*fn)(HandleType, Handle);
+}
+
+SQLRETURN SQL_API dl_SQLDescribeCol (
+ SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLCHAR * ColumnName,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT * NameLength,
+ SQLSMALLINT * DataType,
+ SQLULEN * ColumnSize,
+ SQLSMALLINT * DecimalDigits,
+ SQLSMALLINT * Nullable)
+{
+ typedef SQLRETURN SQL_API ep_SQLDescribeCol (
+ SQLHSTMT StatementHandle,
+ SQLUSMALLINT ColumnNumber,
+ SQLCHAR *ColumnName,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT *NameLength,
+ SQLSMALLINT *DataType,
+ SQLULEN *ColumnSize,
+ SQLSMALLINT *DecimalDigits,
+ SQLSMALLINT *Nullable);
+
+ ep_SQLDescribeCol *fn;
+ fn = (ep_SQLDescribeCol *) xdlsym(h_odbc, "SQLDescribeCol");
+ xassert(fn != NULL);
+ return (*fn)(StatementHandle, ColumnNumber, ColumnName,
+ BufferLength, NameLength,
+ DataType, ColumnSize, DecimalDigits, Nullable);
+}
+
+SQLRETURN SQL_API dl_SQLGetDiagRec (
+ SQLSMALLINT HandleType,
+ SQLHANDLE Handle,
+ SQLSMALLINT RecNumber,
+ SQLCHAR *Sqlstate,
+ SQLINTEGER *NativeError,
+ SQLCHAR *MessageText,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT *TextLength)
+{
+ typedef SQLRETURN SQL_API ep_SQLGetDiagRec (
+ SQLSMALLINT HandleType,
+ SQLHANDLE Handle,
+ SQLSMALLINT RecNumber,
+ SQLCHAR *Sqlstate,
+ SQLINTEGER *NativeError,
+ SQLCHAR *MessageText,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT *TextLength);
+
+ ep_SQLGetDiagRec *fn;
+ fn = (ep_SQLGetDiagRec *) xdlsym(h_odbc, "SQLGetDiagRec");
+ xassert(fn != NULL);
+ return (*fn)(HandleType, Handle, RecNumber, Sqlstate,
+ NativeError, MessageText, BufferLength, TextLength);
+}
+
+SQLRETURN SQL_API dl_SQLGetInfo (
+ SQLHDBC ConnectionHandle,
+ SQLUSMALLINT InfoType,
+ SQLPOINTER InfoValue,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT *StringLength)
+{
+ typedef SQLRETURN SQL_API ep_SQLGetInfo (
+ SQLHDBC ConnectionHandle,
+ SQLUSMALLINT InfoType,
+ SQLPOINTER InfoValue,
+ SQLSMALLINT BufferLength,
+ SQLSMALLINT *StringLength);
+
+ ep_SQLGetInfo *fn;
+ fn = (ep_SQLGetInfo *) xdlsym(h_odbc, "SQLGetInfo");
+ xassert(fn != NULL);
+ return (*fn)(ConnectionHandle, InfoType, InfoValue, BufferLength,
+ StringLength);
+}
+
+SQLRETURN SQL_API dl_SQLNumResultCols (
+ SQLHSTMT StatementHandle,
+ SQLSMALLINT *ColumnCount)
+{
+ typedef SQLRETURN SQL_API ep_SQLNumResultCols (
+ SQLHSTMT StatementHandle,
+ SQLSMALLINT *ColumnCount);
+
+ ep_SQLNumResultCols *fn;
+ fn = (ep_SQLNumResultCols *) xdlsym(h_odbc, "SQLNumResultCols");
+ xassert(fn != NULL);
+ return (*fn)(StatementHandle, ColumnCount);
+}
+
+SQLRETURN SQL_API dl_SQLSetConnectAttr (
+ SQLHDBC ConnectionHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER Value,
+ SQLINTEGER StringLength)
+{
+ typedef SQLRETURN SQL_API ep_SQLSetConnectAttr (
+ SQLHDBC ConnectionHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER Value,
+ SQLINTEGER StringLength);
+
+ ep_SQLSetConnectAttr *fn;
+ fn = (ep_SQLSetConnectAttr *) xdlsym(h_odbc, "SQLSetConnectAttr");
+ xassert(fn != NULL);
+ return (*fn)(ConnectionHandle, Attribute, Value, StringLength);
+}
+
+SQLRETURN SQL_API dl_SQLSetEnvAttr (
+ SQLHENV EnvironmentHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER Value,
+ SQLINTEGER StringLength)
+{
+ typedef SQLRETURN SQL_API ep_SQLSetEnvAttr (
+ SQLHENV EnvironmentHandle,
+ SQLINTEGER Attribute,
+ SQLPOINTER Value,
+ SQLINTEGER StringLength);
+
+ ep_SQLSetEnvAttr *fn;
+ fn = (ep_SQLSetEnvAttr *) xdlsym(h_odbc, "SQLSetEnvAttr");
+ xassert(fn != NULL);
+ return (*fn)(EnvironmentHandle, Attribute, Value, StringLength);
+}
+
+static void extract_error(
+ char *fn,
+ SQLHANDLE handle,
+ SQLSMALLINT type);
+
+static int is_numeric(
+ SQLSMALLINT coltype);
+
+/***********************************************************************
+* NAME
+*
+* db_iodbc_open - open connection to ODBC data base
+*
+* SYNOPSIS
+*
+* #include "mplsql.h"
+* void *db_iodbc_open(TABDCA *dca, int mode);
+*
+* DESCRIPTION
+*
+* The routine db_iodbc_open opens a connection to an ODBC data base.
+* It then executes the sql statements passed.
+*
+* In the case of table read the SELECT statement is executed.
+*
+* In the case of table write the INSERT statement is prepared.
+* RETURNS
+*
+* The routine returns a pointer to data storage area created. */
+void *db_iodbc_open(TABDCA *dca, int mode)
+{ void *ret;
+ char **sqllines;
+
+ sqllines = args_concat(dca);
+ if (sqllines == NULL)
+ { xprintf("Missing arguments in table statement.\n"
+ "Please, supply table driver, dsn, and query.\n");
+ return NULL;
+ }
+ ret = db_iodbc_open_int(dca, mode, (const char **) sqllines);
+ free_buffer(sqllines);
+ return ret;
+}
+
+static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
+ **sqllines)
+{
+ struct db_odbc *sql;
+ SQLRETURN ret;
+ SQLCHAR FAR *dsn;
+ SQLCHAR info[256];
+ SQLSMALLINT colnamelen;
+ SQLSMALLINT nullable;
+ SQLSMALLINT scale;
+ const char *arg;
+ int narg;
+ int i, j;
+ int total;
+
+ if (libodbc == NULL)
+ {
+ xprintf("No loader for shared ODBC library available\n");
+ return NULL;
+ }
+
+ if (h_odbc == NULL)
+ {
+ h_odbc = xdlopen(libodbc);
+ if (h_odbc == NULL)
+ { xprintf("unable to open library %s\n", libodbc);
+ xprintf("%s\n", get_err_msg());
+ return NULL;
+ }
+ }
+
+ sql = (struct db_odbc *) xmalloc(sizeof(struct db_odbc));
+ if (sql == NULL)
+ return NULL;
+
+ sql->mode = mode;
+ sql->hdbc = NULL;
+ sql->henv = NULL;
+ sql->hstmt = NULL;
+ sql->query = NULL;
+ narg = mpl_tab_num_args(dca);
+
+ dsn = (SQLCHAR FAR *) mpl_tab_get_arg(dca, 2);
+ /* allocate an environment handle */
+ ret = dl_SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
+ &(sql->henv));
+ /* set attribute to enable application to run as ODBC 3.0
+ application */
+ ret = dl_SQLSetEnvAttr(sql->henv, SQL_ATTR_ODBC_VERSION,
+ (void *) SQL_OV_ODBC3, 0);
+ /* allocate a connection handle */
+ ret = dl_SQLAllocHandle(SQL_HANDLE_DBC, sql->henv, &(sql->hdbc));
+ /* connect */
+ ret = dl_SQLDriverConnect(sql->hdbc, NULL, dsn, SQL_NTS, NULL, 0,
+ NULL, SQL_DRIVER_COMPLETE);
+ if (SQL_SUCCEEDED(ret))
+ { /* output information about data base connection */
+ xprintf("Connected to ");
+ dl_SQLGetInfo(sql->hdbc, SQL_DBMS_NAME, (SQLPOINTER)info,
+ sizeof(info), NULL);
+ xprintf("%s ", info);
+ dl_SQLGetInfo(sql->hdbc, SQL_DBMS_VER, (SQLPOINTER)info,
+ sizeof(info), NULL);
+ xprintf("%s - ", info);
+ dl_SQLGetInfo(sql->hdbc, SQL_DATABASE_NAME, (SQLPOINTER)info,
+ sizeof(info), NULL);
+ xprintf("%s\n", info);
+ }
+ else
+ { /* describe error */
+ xprintf("Failed to connect\n");
+ extract_error("SQLDriverConnect", sql->hdbc, SQL_HANDLE_DBC);
+ dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+ dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+ xfree(sql);
+ return NULL;
+ }
+ /* set AUTOCOMMIT on*/
+ ret = dl_SQLSetConnectAttr(sql->hdbc, SQL_ATTR_AUTOCOMMIT,
+ (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
+ /* allocate a statement handle */
+ ret = dl_SQLAllocHandle(SQL_HANDLE_STMT, sql->hdbc, &(sql->hstmt));
+
+ /* initialization queries */
+ for(j = 0; sqllines[j+1] != NULL; j++)
+ {
+ sql->query = (SQLCHAR *) sqllines[j];
+ xprintf("%s\n", sql->query);
+ ret = dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS);
+ switch (ret)
+ {
+ case SQL_SUCCESS:
+ case SQL_SUCCESS_WITH_INFO:
+ case SQL_NO_DATA_FOUND:
+ break;
+ default:
+ xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n",
+ sql->query);
+ extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
+ dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+ dl_SQLDisconnect(sql->hdbc);
+ dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+ dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+ xfree(sql);
+ return NULL;
+ }
+ /* commit statement */
+ dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
+ }
+
+ if ( sql->mode == 'R' )
+ { sql->nf = mpl_tab_num_flds(dca);
+ for(j = 0; sqllines[j] != NULL; j++)
+ arg = sqllines[j];
+ total = strlen(arg);
+ if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
+ {
+ total = strlen(arg);
+ sql->query = xmalloc( (total+1) * sizeof(char));
+ strcpy (sql->query, arg);
+ }
+ else
+ {
+ sql->query = db_generate_select_stmt(dca);
+ }
+ xprintf("%s\n", sql->query);
+ if (dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS) !=
+ SQL_SUCCESS)
+ {
+ xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", sql->query);
+ extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
+ dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+ dl_SQLDisconnect(sql->hdbc);
+ dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+ dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+ xfree(sql->query);
+ xfree(sql);
+ return NULL;
+ }
+ xfree(sql->query);
+ /* determine number of result columns */
+ ret = dl_SQLNumResultCols(sql->hstmt, &sql->nresultcols);
+ total = sql->nresultcols;
+ if (total > SQL_FIELD_MAX)
+ { xprintf("db_iodbc_open: Too many fields (> %d) in query.\n"
+ "\"%s\"\n", SQL_FIELD_MAX, sql->query);
+ dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+ dl_SQLDisconnect(sql->hdbc);
+ dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+ dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+ xfree(sql->query);
+ return NULL;
+ }
+ for (i = 1; i <= total; i++)
+ { /* return a set of attributes for a column */
+ ret = dl_SQLDescribeCol(sql->hstmt, (SQLSMALLINT) i,
+ sql->colname[i], SQL_FDLEN_MAX,
+ &colnamelen, &(sql->coltype[i]), &(sql->collen[i]), &scale,
+ &nullable);
+ sql->isnumeric[i] = is_numeric(sql->coltype[i]);
+ /* bind columns to program vars, converting all types to CHAR*/
+ if (sql->isnumeric[i])
+#if 0 /* 12/I-2014 */
+ { dl_SQLBindCol(sql->hstmt, i, SQL_DOUBLE, sql->data[i],
+#else
+ { dl_SQLBindCol(sql->hstmt, i, SQL_DOUBLE, &sql->datanum[i],
+#endif
+ SQL_FDLEN_MAX, &(sql->outlen[i]));
+ } else
+ { dl_SQLBindCol(sql->hstmt, i, SQL_CHAR, sql->data[i],
+ SQL_FDLEN_MAX, &(sql->outlen[i]));
+ }
+ for (j = sql->nf; j >= 1; j--)
+ { if (strcmp(mpl_tab_get_name(dca, j), sql->colname[i]) == 0)
+ break;
+ }
+ sql->ref[i] = j;
+ }
+ }
+ else if ( sql->mode == 'W' )
+ { for(j = 0; sqllines[j] != NULL; j++)
+ arg = sqllines[j];
+ if ( NULL != strchr(arg, '?') )
+ {
+ total = strlen(arg);
+ sql->query = xmalloc( (total+1) * sizeof(char));
+ strcpy (sql->query, arg);
+ }
+ else
+ {
+ sql->query = db_generate_insert_stmt(dca);
+ }
+ xprintf("%s\n", sql->query);
+ }
+ return sql;
+}
+
+int db_iodbc_read(TABDCA *dca, void *link)
+{
+ struct db_odbc *sql;
+ SQLRETURN ret;
+ char buf[SQL_FDLEN_MAX+1];
+ int i;
+ int len;
+ double num;
+
+ sql = (struct db_odbc *) link;
+
+ xassert(sql != NULL);
+ xassert(sql->mode == 'R');
+
+ ret=dl_SQLFetch(sql->hstmt);
+ if (ret== SQL_ERROR)
+ return -1;
+ if (ret== SQL_NO_DATA_FOUND)
+ return -1; /*EOF*/
+ for (i=1; i <= sql->nresultcols; i++)
+ {
+ if (sql->ref[i] > 0)
+ {
+ len = sql->outlen[i];
+ if (len != SQL_NULL_DATA)
+ {
+ if (sql->isnumeric[i])
+ { mpl_tab_set_num(dca, sql->ref[i],
+#if 0 /* 12/I-2014 */
+ *((const double *) sql->data[i]));
+#else
+ (const double) sql->datanum[i]);
+#endif
+ }
+ else
+ { if (len > SQL_FDLEN_MAX)
+ len = SQL_FDLEN_MAX;
+ else if (len < 0)
+ len = 0;
+ strncpy(buf, (const char *) sql->data[i], len);
+ buf[len] = 0x00;
+ mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int db_iodbc_write(TABDCA *dca, void *link)
+{
+ struct db_odbc *sql;
+ char *part;
+ char *query;
+ char *template;
+ char num[50];
+ int k;
+ int len;
+ int nf;
+
+ sql = (struct db_odbc *) link;
+ xassert(sql != NULL);
+ xassert(sql->mode == 'W');
+
+ len = strlen(sql->query);
+ template = (char *) xmalloc( (len + 1) * sizeof(char) );
+ strcpy(template, sql->query);
+
+ nf = mpl_tab_num_flds(dca);
+ for (k = 1; k <= nf; k++)
+ { switch (mpl_tab_get_type(dca, k))
+ { case 'N':
+ len += 20;
+ break;
+ case 'S':
+ len += db_escaped_string_length(mpl_tab_get_str(dca, k));
+ len += 2;
+ break;
+ default:
+ xassert(dca != dca);
+ }
+ }
+ query = xmalloc( (len + 1 ) * sizeof(char) );
+ query[0] = 0x00;
+#if 0 /* 29/I-2017 */
+ for (k = 1, part = strtok (template, "?"); (part != NULL);
+ part = strtok (NULL, "?"), k++)
+#else
+ for (k = 1, part = xstrtok (template, "?"); (part != NULL);
+ part = xstrtok (NULL, "?"), k++)
+#endif
+ {
+ if (k > nf) break;
+ strcat( query, part );
+ switch (mpl_tab_get_type(dca, k))
+ { case 'N':
+#if 0 /* 02/XI-2010 by xypron */
+ sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
+#else
+ sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
+#endif
+ strcat( query, num );
+ break;
+ case 'S':
+ strcat( query, "'");
+ db_escape_string( query + strlen(query),
+ mpl_tab_get_str(dca, k) );
+ strcat( query, "'");
+ break;
+ default:
+ xassert(dca != dca);
+ }
+ }
+ if (part != NULL)
+ strcat(query, part);
+ if (dl_SQLExecDirect(sql->hstmt, (SQLCHAR *) query, SQL_NTS)
+ != SQL_SUCCESS)
+ {
+ xprintf("db_iodbc_write: Query\n\"%s\"\nfailed.\n", query);
+ extract_error("SQLExecDirect", sql->hdbc, SQL_HANDLE_DBC);
+ xfree(query);
+ xfree(template);
+ return 1;
+ }
+
+ xfree(query);
+ xfree(template);
+ return 0;
+}
+
+int db_iodbc_close(TABDCA *dca, void *link)
+{
+ struct db_odbc *sql;
+
+ sql = (struct db_odbc *) link;
+ xassert(sql != NULL);
+ /* Commit */
+ if ( sql->mode == 'W' )
+ dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
+ if ( sql->mode == 'R' )
+ dl_SQLCloseCursor(sql->hstmt);
+
+ dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+ dl_SQLDisconnect(sql->hdbc);
+ dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+ dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+ if ( sql->mode == 'W' )
+ xfree(sql->query);
+ xfree(sql);
+ dca->link = NULL;
+ return 0;
+}
+
+static void extract_error(
+ char *fn,
+ SQLHANDLE handle,
+ SQLSMALLINT type)
+{
+ SQLINTEGER i = 0;
+ SQLINTEGER native;
+ SQLCHAR state[ 7 ];
+ SQLCHAR text[256];
+ SQLSMALLINT len;
+ SQLRETURN ret;
+
+ xprintf("\nThe driver reported the following diagnostics whilst "
+ "running %s\n", fn);
+
+ do
+ {
+ ret = dl_SQLGetDiagRec(type, handle, ++i, state, &native, text,
+ sizeof(text), &len );
+ if (SQL_SUCCEEDED(ret))
+ xprintf("%s:%ld:%ld:%s\n", state, i, native, text);
+ }
+ while( ret == SQL_SUCCESS );
+}
+
+static int is_numeric(SQLSMALLINT coltype)
+{
+ int ret = 0;
+ switch (coltype)
+ {
+ case SQL_DECIMAL:
+ case SQL_NUMERIC:
+ case SQL_SMALLINT:
+ case SQL_INTEGER:
+ case SQL_REAL:
+ case SQL_FLOAT:
+ case SQL_DOUBLE:
+ case SQL_TINYINT:
+ case SQL_BIGINT:
+ ret = 1;
+ break;
+ }
+ return ret;
+}
+
+#endif
+
+/**********************************************************************/
+
+#ifndef HAVE_MYSQL
+
+void *db_mysql_open(TABDCA *dca, int mode)
+{ xassert(dca == dca);
+ xassert(mode == mode);
+ xprintf("MySQL table driver not supported\n");
+ return NULL;
+}
+
+int db_mysql_read(TABDCA *dca, void *link)
+{ xassert(dca != dca);
+ xassert(link != link);
+ return 0;
+}
+
+int db_mysql_write(TABDCA *dca, void *link)
+{ xassert(dca != dca);
+ xassert(link != link);
+ return 0;
+}
+
+int db_mysql_close(TABDCA *dca, void *link)
+{ xassert(dca != dca);
+ xassert(link != link);
+ return 0;
+}
+
+#else
+
+#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
+#include <windows.h>
+#endif
+
+#ifdef __CYGWIN__
+#define byte_defined 1
+#endif
+
+#if 0 /* 12/II-2014; to fix namespace bug */
+#include <my_global.h>
+#include <my_sys.h>
+#endif
+#include <mysql.h>
+
+struct db_mysql
+{
+ int mode; /*'R' = Read, 'W' = Write*/
+ MYSQL *con; /*connection*/
+ MYSQL_RES *res; /*result*/
+ int nf;
+ /* number of fields in the csv file */
+ int ref[1+SQL_FIELD_MAX];
+ /* ref[k] = k', if k-th field of the csv file corresponds to
+ k'-th field in the table statement; if ref[k] = 0, k-th field
+ of the csv file is ignored */
+ char *query;
+ /* query generated by db_mysql_open */
+};
+
+void STDCALL dl_mysql_close(MYSQL *sock)
+{
+ typedef void STDCALL ep_mysql_close(MYSQL *sock);
+
+ ep_mysql_close *fn;
+ fn = (ep_mysql_close *) xdlsym(h_mysql, "mysql_close");
+ xassert(fn != NULL);
+ return (*fn)(sock);
+}
+
+const char * STDCALL dl_mysql_error(MYSQL *mysql)
+{
+ typedef const char * STDCALL ep_mysql_error(MYSQL *mysql);
+
+ ep_mysql_error *fn;
+ fn = (ep_mysql_error *) xdlsym(h_mysql, "mysql_error");
+ xassert(fn != NULL);
+ return (*fn)(mysql);
+}
+
+MYSQL_FIELD * STDCALL dl_mysql_fetch_fields(MYSQL_RES *res)
+{
+ typedef MYSQL_FIELD * STDCALL
+ ep_mysql_fetch_fields(MYSQL_RES *res);
+
+ ep_mysql_fetch_fields *fn;
+ fn = (ep_mysql_fetch_fields *) xdlsym(h_mysql, "mysql_fetch_fields");
+ xassert(fn != NULL);
+ return (*fn)(res);
+}
+
+unsigned long * STDCALL dl_mysql_fetch_lengths(MYSQL_RES *result)
+{
+ typedef unsigned long * STDCALL
+ ep_mysql_fetch_lengths(MYSQL_RES *result);
+
+ ep_mysql_fetch_lengths *fn;
+ fn = (ep_mysql_fetch_lengths *) xdlsym(h_mysql,
+ "mysql_fetch_lengths");
+ xassert(fn != NULL);
+ return (*fn)(result);
+}
+
+MYSQL_ROW STDCALL dl_mysql_fetch_row(MYSQL_RES *result)
+{
+ typedef MYSQL_ROW STDCALL ep_mysql_fetch_row(MYSQL_RES *result);
+
+ ep_mysql_fetch_row *fn;
+ fn = (ep_mysql_fetch_row *) xdlsym(h_mysql, "mysql_fetch_row");
+ xassert(fn != NULL);
+ return (*fn)(result);
+}
+
+unsigned int STDCALL dl_mysql_field_count(MYSQL *mysql)
+{
+ typedef unsigned int STDCALL ep_mysql_field_count(MYSQL *mysql);
+
+ ep_mysql_field_count *fn;
+ fn = (ep_mysql_field_count *) xdlsym(h_mysql, "mysql_field_count");
+ xassert(fn != NULL);
+ return (*fn)(mysql);
+}
+
+MYSQL * STDCALL dl_mysql_init(MYSQL *mysql)
+{
+ typedef MYSQL * STDCALL ep_mysql_init(MYSQL *mysql);
+
+ ep_mysql_init *fn;
+ fn = (ep_mysql_init *) xdlsym(h_mysql, "mysql_init");
+ xassert(fn != NULL);
+ return (*fn)(mysql);
+}
+
+unsigned int STDCALL dl_mysql_num_fields(MYSQL_RES *res)
+{
+ typedef unsigned int STDCALL ep_mysql_num_fields(MYSQL_RES *res);
+
+ ep_mysql_num_fields *fn;
+ fn = (ep_mysql_num_fields *) xdlsym(h_mysql, "mysql_num_fields");
+ xassert(fn != NULL);
+ return (*fn)(res);
+}
+
+int STDCALL dl_mysql_query(MYSQL *mysql, const char *q)
+{
+ typedef int STDCALL ep_mysql_query(MYSQL *mysql, const char *q);
+
+ ep_mysql_query *fn;
+ fn = (ep_mysql_query *) xdlsym(h_mysql, "mysql_query");
+ xassert(fn != NULL);
+ return (*fn)(mysql, q);
+}
+
+MYSQL * STDCALL dl_mysql_real_connect(MYSQL *mysql, const char *host,
+ const char *user,
+ const char *passwd,
+ const char *db,
+ unsigned int port,
+ const char *unix_socket,
+ unsigned long clientflag)
+{
+ typedef MYSQL * STDCALL ep_mysql_real_connect(MYSQL *mysql,
+ const char *host,
+ const char *user,
+ const char *passwd,
+ const char *db,
+ unsigned int port,
+ const char *unix_socket,
+ unsigned long clientflag);
+
+ ep_mysql_real_connect *fn;
+ fn = (ep_mysql_real_connect *) xdlsym(h_mysql,
+ "mysql_real_connect");
+ xassert(fn != NULL);
+ return (*fn)(mysql, host, user, passwd, db, port, unix_socket,
+ clientflag);
+}
+
+MYSQL_RES * STDCALL dl_mysql_use_result(MYSQL *mysql)
+{
+ typedef MYSQL_RES * STDCALL ep_mysql_use_result(MYSQL *mysql);
+ ep_mysql_use_result *fn;
+ fn = (ep_mysql_use_result *) xdlsym(h_mysql, "mysql_use_result");
+ xassert(fn != NULL);
+ return (*fn)(mysql);
+}
+
+/***********************************************************************
+* NAME
+*
+* db_mysql_open - open connection to ODBC data base
+*
+* SYNOPSIS
+*
+* #include "mplsql.h"
+* void *db_mysql_open(TABDCA *dca, int mode);
+*
+* DESCRIPTION
+*
+* The routine db_mysql_open opens a connection to a MySQL data base.
+* It then executes the sql statements passed.
+*
+* In the case of table read the SELECT statement is executed.
+*
+* In the case of table write the INSERT statement is prepared.
+* RETURNS
+*
+* The routine returns a pointer to data storage area created. */
+
+void *db_mysql_open(TABDCA *dca, int mode)
+{ void *ret;
+ char **sqllines;
+
+ sqllines = args_concat(dca);
+ if (sqllines == NULL)
+ { xprintf("Missing arguments in table statement.\n"
+ "Please, supply table driver, dsn, and query.\n");
+ return NULL;
+ }
+ ret = db_mysql_open_int(dca, mode, (const char **) sqllines);
+ free_buffer(sqllines);
+ return ret;
+}
+
+static void *db_mysql_open_int(TABDCA *dca, int mode, const char
+ **sqllines)
+{
+ struct db_mysql *sql = NULL;
+ char *arg = NULL;
+ const char *field;
+ MYSQL_FIELD *fields;
+ char *keyword;
+ char *value;
+ char *query;
+ char *dsn;
+/* "Server=[server_name];Database=[database_name];UID=[username];*/
+/* PWD=[password];Port=[port]"*/
+ char *server = NULL; /* Server */
+ char *user = NULL; /* UID */
+ char *password = NULL; /* PWD */
+ char *database = NULL; /* Database */
+ unsigned int port = 0; /* Port */
+ int narg;
+ int i, j, total;
+
+ if (libmysql == NULL)
+ {
+ xprintf("No loader for shared MySQL library available\n");
+ return NULL;
+ }
+
+ if (h_mysql == NULL)
+ {
+ h_mysql = xdlopen(libmysql);
+ if (h_mysql == NULL)
+ { xprintf("unable to open library %s\n", libmysql);
+ xprintf("%s\n", get_err_msg());
+ return NULL;
+ }
+ }
+
+ sql = (struct db_mysql *) xmalloc(sizeof(struct db_mysql));
+ if (sql == NULL)
+ return NULL;
+ sql->mode = mode;
+ sql->res = NULL;
+ sql->query = NULL;
+ sql->nf = mpl_tab_num_flds(dca);
+
+ narg = mpl_tab_num_args(dca);
+ if (narg < 3 )
+ xprintf("MySQL driver: string list too short \n");
+
+ /* get connection string*/
+ dsn = (char *) mpl_tab_get_arg(dca, 2);
+ /* copy connection string*/
+ i = strlen(dsn);
+ i++;
+ arg = xmalloc(i * sizeof(char));
+ strcpy(arg, dsn);
+ /*tokenize connection string*/
+#if 0 /* 29/I-2017 */
+ for (i = 1, keyword = strtok (arg, "="); (keyword != NULL);
+ keyword = strtok (NULL, "="), i++)
+#else
+ for (i = 1, keyword = xstrtok (arg, "="); (keyword != NULL);
+ keyword = xstrtok (NULL, "="), i++)
+#endif
+ {
+#if 0 /* 29/I-2017 */
+ value = strtok (NULL, ";");
+#else
+ value = xstrtok (NULL, ";");
+#endif
+ if (value==NULL)
+ {
+ xprintf("db_mysql_open: Missing value for keyword %s\n",
+ keyword);
+ xfree(arg);
+ xfree(sql);
+ return NULL;
+ }
+ if (0 == strcmp(keyword, "Server"))
+ server = value;
+ else if (0 == strcmp(keyword, "Database"))
+ database = value;
+ else if (0 == strcmp(keyword, "UID"))
+ user = value;
+ else if (0 == strcmp(keyword, "PWD"))
+ password = value;
+ else if (0 == strcmp(keyword, "Port"))
+ port = (unsigned int) atol(value);
+ }
+ /* Connect to database */
+ sql->con = dl_mysql_init(NULL);
+ if (!dl_mysql_real_connect(sql->con, server, user, password, database,
+ port, NULL, 0))
+ {
+ xprintf("db_mysql_open: Connect failed\n");
+ xprintf("%s\n", dl_mysql_error(sql->con));
+ xfree(arg);
+ xfree(sql);
+ return NULL;
+ }
+ xfree(arg);
+
+ for(j = 0; sqllines[j+1] != NULL; j++)
+ { query = (char *) sqllines[j];
+ xprintf("%s\n", query);
+ if (dl_mysql_query(sql->con, query))
+ {
+ xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
+ xprintf("%s\n",dl_mysql_error(sql->con));
+ dl_mysql_close(sql->con);
+ xfree(sql);
+ return NULL;
+ }
+ }
+
+ if ( sql->mode == 'R' )
+ { sql->nf = mpl_tab_num_flds(dca);
+ for(j = 0; sqllines[j] != NULL; j++)
+ arg = (char *) sqllines[j];
+ total = strlen(arg);
+ if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
+ {
+ total = strlen(arg);
+ query = xmalloc( (total+1) * sizeof(char));
+ strcpy (query, arg);
+ }
+ else
+ {
+ query = db_generate_select_stmt(dca);
+ }
+ xprintf("%s\n", query);
+ if (dl_mysql_query(sql->con, query))
+ {
+ xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
+ xprintf("%s\n",dl_mysql_error(sql->con));
+ dl_mysql_close(sql->con);
+ xfree(query);
+ xfree(sql);
+ return NULL;
+ }
+ xfree(query);
+ sql->res = dl_mysql_use_result(sql->con);
+ if (sql->res)
+ {
+ /* create references between query results and table fields*/
+ total = dl_mysql_num_fields(sql->res);
+ if (total > SQL_FIELD_MAX)
+ { xprintf("db_mysql_open: Too many fields (> %d) in query.\n"
+ "\"%s\"\n", SQL_FIELD_MAX, query);
+ xprintf("%s\n",dl_mysql_error(sql->con));
+ dl_mysql_close(sql->con);
+ xfree(query);
+ xfree(sql);
+ return NULL;
+ }
+ fields = dl_mysql_fetch_fields(sql->res);
+ for (i = 1; i <= total; i++)
+ {
+ for (j = sql->nf; j >= 1; j--)
+ {
+ if (strcmp(mpl_tab_get_name(dca, j), fields[i-1].name)
+ == 0)
+ break;
+ }
+ sql->ref[i] = j;
+ }
+ }
+ else
+ {
+ if(dl_mysql_field_count(sql->con) == 0)
+ {
+ xprintf("db_mysql_open: Query was not a SELECT\n\"%s\"\n",
+ query);
+ xprintf("%s\n",dl_mysql_error(sql->con));
+ xfree(query);
+ xfree(sql);
+ return NULL;
+ }
+ else
+ {
+ xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
+ xprintf("%s\n",dl_mysql_error(sql->con));
+ xfree(query);
+ xfree(sql);
+ return NULL;
+ }
+ }
+ }
+ else if ( sql->mode == 'W' )
+ { for(j = 0; sqllines[j] != NULL; j++)
+ arg = (char *) sqllines[j];
+ if ( NULL != strchr(arg, '?') )
+ {
+ total = strlen(arg);
+ query = xmalloc( (total+1) * sizeof(char));
+ strcpy (query, arg);
+ }
+ else
+ query = db_generate_insert_stmt(dca);
+ sql->query = query;
+ xprintf("%s\n", query);
+ }
+ return sql;
+}
+
+int db_mysql_read(TABDCA *dca, void *link)
+{ struct db_mysql *sql;
+ char buf[255+1];
+ char **row;
+ unsigned long *lengths;
+ MYSQL_FIELD *fields;
+ double num;
+ int len;
+ unsigned long num_fields;
+ int i;
+
+ sql = (struct db_mysql *) link;
+
+ xassert(sql != NULL);
+ xassert(sql->mode == 'R');
+ if (NULL == sql->res)
+ {
+ xprintf("db_mysql_read: no result set available");
+ return 1;
+ }
+ if (NULL==(row = (char **)dl_mysql_fetch_row(sql->res))) {
+ return -1; /*EOF*/
+ }
+ lengths = dl_mysql_fetch_lengths(sql->res);
+ fields = dl_mysql_fetch_fields(sql->res);
+ num_fields = dl_mysql_num_fields(sql->res);
+ for (i=1; i <= num_fields; i++)
+ {
+ if (row[i-1] != NULL)
+ { len = (size_t) lengths[i-1];
+ if (len > 255)
+ len = 255;
+ strncpy(buf, (const char *) row[i-1], len);
+ buf[len] = 0x00;
+ if (0 != (fields[i-1].flags & NUM_FLAG))
+ { strspx(buf); /* remove spaces*/
+ if (str2num(buf, &num) != 0)
+ { xprintf("'%s' cannot be converted to a number.\n", buf);
+ return 1;
+ }
+ if (sql->ref[i] > 0)
+ mpl_tab_set_num(dca, sql->ref[i], num);
+ }
+ else
+ { if (sql->ref[i] > 0)
+ mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
+ }
+ }
+ }
+ return 0;
+}
+
+int db_mysql_write(TABDCA *dca, void *link)
+{
+ struct db_mysql *sql;
+ char *part;
+ char *query;
+ char *template;
+ char num[50];
+ int k;
+ int len;
+ int nf;
+
+ sql = (struct db_mysql *) link;
+ xassert(sql != NULL);
+ xassert(sql->mode == 'W');
+
+ len = strlen(sql->query);
+ template = (char *) xmalloc( (len + 1) * sizeof(char) );
+ strcpy(template, sql->query);
+
+ nf = mpl_tab_num_flds(dca);
+ for (k = 1; k <= nf; k++)
+ { switch (mpl_tab_get_type(dca, k))
+ { case 'N':
+ len += 20;
+ break;
+ case 'S':
+ len += db_escaped_string_length(mpl_tab_get_str(dca, k));
+ len += 2;
+ break;
+ default:
+ xassert(dca != dca);
+ }
+ }
+ query = xmalloc( (len + 1 ) * sizeof(char) );
+ query[0] = 0x00;
+#if 0 /* 29/I-2017 */
+ for (k = 1, part = strtok (template, "?"); (part != NULL);
+ part = strtok (NULL, "?"), k++)
+#else
+ for (k = 1, part = xstrtok (template, "?"); (part != NULL);
+ part = xstrtok (NULL, "?"), k++)
+#endif
+ {
+ if (k > nf) break;
+ strcat( query, part );
+ switch (mpl_tab_get_type(dca, k))
+ { case 'N':
+#if 0 /* 02/XI-2010 by xypron */
+ sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
+#else
+ sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
+#endif
+ strcat( query, num );
+ break;
+ case 'S':
+ strcat( query, "'");
+ db_escape_string( query + strlen(query),
+ mpl_tab_get_str(dca, k) );
+ strcat( query, "'");
+ break;
+ default:
+ xassert(dca != dca);
+ }
+ }
+ if (part != NULL)
+ strcat(query, part);
+ if (dl_mysql_query(sql->con, query))
+ {
+ xprintf("db_mysql_write: Query\n\"%s\"\nfailed.\n", query);
+ xprintf("%s\n",dl_mysql_error(sql->con));
+ xfree(query);
+ xfree(template);
+ return 1;
+ }
+
+ xfree(query);
+ xfree(template);
+ return 0;
+ }
+
+int db_mysql_close(TABDCA *dca, void *link)
+{
+ struct db_mysql *sql;
+
+ sql = (struct db_mysql *) link;
+ xassert(sql != NULL);
+ dl_mysql_close(sql->con);
+ if ( sql->mode == 'W' )
+ xfree(sql->query);
+ xfree(sql);
+ dca->link = NULL;
+ return 0;
+}
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/mpl/mplsql.h b/test/monniaux/glpk-4.65/src/mpl/mplsql.h
new file mode 100644
index 00000000..11d438bb
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/mpl/mplsql.h
@@ -0,0 +1,63 @@
+/* mplsql.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Author: Heinrich Schuchardt <heinrich.schuchardt@gmx.de>.
+*
+* Copyright (C) 2003-2016 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/>.
+***********************************************************************/
+
+#ifndef MPLSQL_H
+#define MPLSQL_H
+
+#define db_iodbc_open _glp_db_iodbc_open
+void *db_iodbc_open(TABDCA *dca, int mode);
+/* open iODBC database connection */
+
+#define db_iodbc_read _glp_db_iodbc_read
+int db_iodbc_read(TABDCA *dca, void *link);
+/* read data from iODBC */
+
+#define db_iodbc_write _glp_db_iodbc_write
+int db_iodbc_write(TABDCA *dca, void *link);
+/* write data to iODBC */
+
+#define db_iodbc_close _glp_db_iodbc_close
+int db_iodbc_close(TABDCA *dca, void *link);
+/* close iODBC database connection */
+
+#define db_mysql_open _glp_db_mysql_open
+void *db_mysql_open(TABDCA *dca, int mode);
+/* open MySQL database connection */
+
+#define db_mysql_read _glp_db_mysql_read
+int db_mysql_read(TABDCA *dca, void *link);
+/* read data from MySQL */
+
+#define db_mysql_write _glp_db_mysql_write
+int db_mysql_write(TABDCA *dca, void *link);
+/* write data to MySQL */
+
+#define db_mysql_close _glp_db_mysql_close
+int db_mysql_close(TABDCA *dca, void *link);
+/* close MySQL database connection */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp.h b/test/monniaux/glpk-4.65/src/npp/npp.h
new file mode 100644
index 00000000..428cb23c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp.h
@@ -0,0 +1,645 @@
+/* npp.h (LP/MIP preprocessor) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 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/>.
+***********************************************************************/
+
+#ifndef NPP_H
+#define NPP_H
+
+#include "prob.h"
+
+#if 0 /* 20/XI-2017 */
+typedef struct NPP NPP;
+#else
+typedef struct glp_prep NPP;
+#endif
+typedef struct NPPROW NPPROW;
+typedef struct NPPCOL NPPCOL;
+typedef struct NPPAIJ NPPAIJ;
+typedef struct NPPTSE NPPTSE;
+typedef struct NPPLFE NPPLFE;
+
+#if 0 /* 20/XI-2017 */
+struct NPP
+#else
+struct glp_prep
+#endif
+{ /* LP/MIP preprocessor workspace */
+ /*--------------------------------------------------------------*/
+ /* original problem segment */
+ int orig_dir;
+ /* optimization direction flag:
+ GLP_MIN - minimization
+ GLP_MAX - maximization */
+ int orig_m;
+ /* number of rows */
+ int orig_n;
+ /* number of columns */
+ int orig_nnz;
+ /* number of non-zero constraint coefficients */
+ /*--------------------------------------------------------------*/
+ /* transformed problem segment (always minimization) */
+ DMP *pool;
+ /* memory pool to store problem components */
+ char *name;
+ /* problem name (1 to 255 chars); NULL means no name is assigned
+ to the problem */
+ char *obj;
+ /* objective function name (1 to 255 chars); NULL means no name
+ is assigned to the objective function */
+ double c0;
+ /* constant term of the objective function */
+ int nrows;
+ /* number of rows introduced into the problem; this count
+ increases by one every time a new row is added and never
+ decreases; thus, actual number of rows may be less than nrows
+ due to row deletions */
+ int ncols;
+ /* number of columns introduced into the problem; this count
+ increases by one every time a new column is added and never
+ decreases; thus, actual number of column may be less than
+ ncols due to column deletions */
+ NPPROW *r_head;
+ /* pointer to the beginning of the row list */
+ NPPROW *r_tail;
+ /* pointer to the end of the row list */
+ NPPCOL *c_head;
+ /* pointer to the beginning of the column list */
+ NPPCOL *c_tail;
+ /* pointer to the end of the column list */
+ /*--------------------------------------------------------------*/
+ /* transformation history */
+ DMP *stack;
+ /* memory pool to store transformation entries */
+ NPPTSE *top;
+ /* pointer to most recent transformation entry */
+#if 0 /* 16/XII-2009 */
+ int count[1+25];
+ /* transformation statistics */
+#endif
+ /*--------------------------------------------------------------*/
+ /* resultant (preprocessed) problem segment */
+ int m;
+ /* number of rows */
+ int n;
+ /* number of columns */
+ int nnz;
+ /* number of non-zero constraint coefficients */
+ int *row_ref; /* int row_ref[1+m]; */
+ /* row_ref[i], 1 <= i <= m, is the reference number assigned to
+ a row, which is i-th row of the resultant problem */
+ int *col_ref; /* int col_ref[1+n]; */
+ /* col_ref[j], 1 <= j <= n, is the reference number assigned to
+ a column, which is j-th column of the resultant problem */
+ /*--------------------------------------------------------------*/
+ /* recovered solution segment */
+ int sol;
+ /* solution indicator:
+ GLP_SOL - basic solution
+ GLP_IPT - interior-point solution
+ GLP_MIP - mixed integer solution */
+ int scaling;
+ /* scaling option:
+ GLP_OFF - scaling is disabled
+ GLP_ON - scaling is enabled */
+ int p_stat;
+ /* status of primal basic solution:
+ GLP_UNDEF - primal solution is undefined
+ GLP_FEAS - primal solution is feasible
+ GLP_INFEAS - primal solution is infeasible
+ GLP_NOFEAS - no primal feasible solution exists */
+ int d_stat;
+ /* status of dual basic solution:
+ GLP_UNDEF - dual solution is undefined
+ GLP_FEAS - dual solution is feasible
+ GLP_INFEAS - dual solution is infeasible
+ GLP_NOFEAS - no dual feasible solution exists */
+ int t_stat;
+ /* status of interior-point solution:
+ GLP_UNDEF - interior solution is undefined
+ GLP_OPT - interior solution is optimal */
+ int i_stat;
+ /* status of mixed integer solution:
+ GLP_UNDEF - integer solution is undefined
+ GLP_OPT - integer solution is optimal
+ GLP_FEAS - integer solution is feasible
+ GLP_NOFEAS - no integer solution exists */
+ char *r_stat; /* char r_stat[1+nrows]; */
+ /* r_stat[i], 1 <= i <= nrows, is status of i-th row:
+ GLP_BS - inactive constraint
+ GLP_NL - active constraint on lower bound
+ GLP_NU - active constraint on upper bound
+ GLP_NF - active free row
+ GLP_NS - active equality constraint */
+ char *c_stat; /* char c_stat[1+nrows]; */
+ /* c_stat[j], 1 <= j <= nrows, is status of j-th column:
+ GLP_BS - basic variable
+ GLP_NL - non-basic variable on lower bound
+ GLP_NU - non-basic variable on upper bound
+ GLP_NF - non-basic free variable
+ GLP_NS - non-basic fixed variable */
+ double *r_pi; /* double r_pi[1+nrows]; */
+ /* r_pi[i], 1 <= i <= nrows, is Lagrange multiplier (dual value)
+ for i-th row (constraint) */
+ double *c_value; /* double c_value[1+ncols]; */
+ /* c_value[j], 1 <= j <= ncols, is primal value of j-th column
+ (structural variable) */
+};
+
+struct NPPROW
+{ /* row (constraint) */
+ int i;
+ /* reference number assigned to the row, 1 <= i <= nrows */
+ char *name;
+ /* row name (1 to 255 chars); NULL means no name is assigned to
+ the row */
+ double lb;
+ /* lower bound; -DBL_MAX means the row has no lower bound */
+ double ub;
+ /* upper bound; +DBL_MAX means the row has no upper bound */
+ NPPAIJ *ptr;
+ /* pointer to the linked list of constraint coefficients */
+ int temp;
+ /* working field used by preprocessor routines */
+ NPPROW *prev;
+ /* pointer to previous row in the row list */
+ NPPROW *next;
+ /* pointer to next row in the row list */
+};
+
+struct NPPCOL
+{ /* column (variable) */
+ int j;
+ /* reference number assigned to the column, 1 <= j <= ncols */
+ char *name;
+ /* column name (1 to 255 chars); NULL means no name is assigned
+ to the column */
+ char is_int;
+ /* 0 means continuous variable; 1 means integer variable */
+ double lb;
+ /* lower bound; -DBL_MAX means the column has no lower bound */
+ double ub;
+ /* upper bound; +DBL_MAX means the column has no upper bound */
+ double coef;
+ /* objective coefficient */
+ NPPAIJ *ptr;
+ /* pointer to the linked list of constraint coefficients */
+ int temp;
+ /* working field used by preprocessor routines */
+#if 1 /* 28/XII-2009 */
+ union
+ { double ll;
+ /* implied column lower bound */
+ int pos;
+ /* vertex ordinal number corresponding to this binary column
+ in the conflict graph (0, if the vertex does not exist) */
+ } ll;
+ union
+ { double uu;
+ /* implied column upper bound */
+ int neg;
+ /* vertex ordinal number corresponding to complement of this
+ binary column in the conflict graph (0, if the vertex does
+ not exist) */
+ } uu;
+#endif
+ NPPCOL *prev;
+ /* pointer to previous column in the column list */
+ NPPCOL *next;
+ /* pointer to next column in the column list */
+};
+
+struct NPPAIJ
+{ /* constraint coefficient */
+ NPPROW *row;
+ /* pointer to corresponding row */
+ NPPCOL *col;
+ /* pointer to corresponding column */
+ double val;
+ /* (non-zero) coefficient value */
+ NPPAIJ *r_prev;
+ /* pointer to previous coefficient in the same row */
+ NPPAIJ *r_next;
+ /* pointer to next coefficient in the same row */
+ NPPAIJ *c_prev;
+ /* pointer to previous coefficient in the same column */
+ NPPAIJ *c_next;
+ /* pointer to next coefficient in the same column */
+};
+
+struct NPPTSE
+{ /* transformation stack entry */
+ int (*func)(NPP *npp, void *info);
+ /* pointer to routine performing back transformation */
+ void *info;
+ /* pointer to specific info (depends on the transformation) */
+ NPPTSE *link;
+ /* pointer to another entry created *before* this entry */
+};
+
+struct NPPLFE
+{ /* linear form element */
+ int ref;
+ /* row/column reference number */
+ double val;
+ /* (non-zero) coefficient value */
+ NPPLFE *next;
+ /* pointer to another element */
+};
+
+#define npp_create_wksp _glp_npp_create_wksp
+NPP *npp_create_wksp(void);
+/* create LP/MIP preprocessor workspace */
+
+#define npp_insert_row _glp_npp_insert_row
+void npp_insert_row(NPP *npp, NPPROW *row, int where);
+/* insert row to the row list */
+
+#define npp_remove_row _glp_npp_remove_row
+void npp_remove_row(NPP *npp, NPPROW *row);
+/* remove row from the row list */
+
+#define npp_activate_row _glp_npp_activate_row
+void npp_activate_row(NPP *npp, NPPROW *row);
+/* make row active */
+
+#define npp_deactivate_row _glp_npp_deactivate_row
+void npp_deactivate_row(NPP *npp, NPPROW *row);
+/* make row inactive */
+
+#define npp_insert_col _glp_npp_insert_col
+void npp_insert_col(NPP *npp, NPPCOL *col, int where);
+/* insert column to the column list */
+
+#define npp_remove_col _glp_npp_remove_col
+void npp_remove_col(NPP *npp, NPPCOL *col);
+/* remove column from the column list */
+
+#define npp_activate_col _glp_npp_activate_col
+void npp_activate_col(NPP *npp, NPPCOL *col);
+/* make column active */
+
+#define npp_deactivate_col _glp_npp_deactivate_col
+void npp_deactivate_col(NPP *npp, NPPCOL *col);
+/* make column inactive */
+
+#define npp_add_row _glp_npp_add_row
+NPPROW *npp_add_row(NPP *npp);
+/* add new row to the current problem */
+
+#define npp_add_col _glp_npp_add_col
+NPPCOL *npp_add_col(NPP *npp);
+/* add new column to the current problem */
+
+#define npp_add_aij _glp_npp_add_aij
+NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val);
+/* add new element to the constraint matrix */
+
+#define npp_row_nnz _glp_npp_row_nnz
+int npp_row_nnz(NPP *npp, NPPROW *row);
+/* count number of non-zero coefficients in row */
+
+#define npp_col_nnz _glp_npp_col_nnz
+int npp_col_nnz(NPP *npp, NPPCOL *col);
+/* count number of non-zero coefficients in column */
+
+#define npp_push_tse _glp_npp_push_tse
+void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
+ int size);
+/* push new entry to the transformation stack */
+
+#define npp_erase_row _glp_npp_erase_row
+void npp_erase_row(NPP *npp, NPPROW *row);
+/* erase row content to make it empty */
+
+#define npp_del_row _glp_npp_del_row
+void npp_del_row(NPP *npp, NPPROW *row);
+/* remove row from the current problem */
+
+#define npp_del_col _glp_npp_del_col
+void npp_del_col(NPP *npp, NPPCOL *col);
+/* remove column from the current problem */
+
+#define npp_del_aij _glp_npp_del_aij
+void npp_del_aij(NPP *npp, NPPAIJ *aij);
+/* remove element from the constraint matrix */
+
+#define npp_load_prob _glp_npp_load_prob
+void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
+ int scaling);
+/* load original problem into the preprocessor workspace */
+
+#define npp_build_prob _glp_npp_build_prob
+void npp_build_prob(NPP *npp, glp_prob *prob);
+/* build resultant (preprocessed) problem */
+
+#define npp_postprocess _glp_npp_postprocess
+void npp_postprocess(NPP *npp, glp_prob *prob);
+/* postprocess solution from the resultant problem */
+
+#define npp_unload_sol _glp_npp_unload_sol
+void npp_unload_sol(NPP *npp, glp_prob *orig);
+/* store solution to the original problem */
+
+#define npp_delete_wksp _glp_npp_delete_wksp
+void npp_delete_wksp(NPP *npp);
+/* delete LP/MIP preprocessor workspace */
+
+#define npp_error()
+
+#define npp_free_row _glp_npp_free_row
+void npp_free_row(NPP *npp, NPPROW *p);
+/* process free (unbounded) row */
+
+#define npp_geq_row _glp_npp_geq_row
+void npp_geq_row(NPP *npp, NPPROW *p);
+/* process row of 'not less than' type */
+
+#define npp_leq_row _glp_npp_leq_row
+void npp_leq_row(NPP *npp, NPPROW *p);
+/* process row of 'not greater than' type */
+
+#define npp_free_col _glp_npp_free_col
+void npp_free_col(NPP *npp, NPPCOL *q);
+/* process free (unbounded) column */
+
+#define npp_lbnd_col _glp_npp_lbnd_col
+void npp_lbnd_col(NPP *npp, NPPCOL *q);
+/* process column with (non-zero) lower bound */
+
+#define npp_ubnd_col _glp_npp_ubnd_col
+void npp_ubnd_col(NPP *npp, NPPCOL *q);
+/* process column with upper bound */
+
+#define npp_dbnd_col _glp_npp_dbnd_col
+void npp_dbnd_col(NPP *npp, NPPCOL *q);
+/* process non-negative column with upper bound */
+
+#define npp_fixed_col _glp_npp_fixed_col
+void npp_fixed_col(NPP *npp, NPPCOL *q);
+/* process fixed column */
+
+#define npp_make_equality _glp_npp_make_equality
+int npp_make_equality(NPP *npp, NPPROW *p);
+/* process row with almost identical bounds */
+
+#define npp_make_fixed _glp_npp_make_fixed
+int npp_make_fixed(NPP *npp, NPPCOL *q);
+/* process column with almost identical bounds */
+
+#define npp_empty_row _glp_npp_empty_row
+int npp_empty_row(NPP *npp, NPPROW *p);
+/* process empty row */
+
+#define npp_empty_col _glp_npp_empty_col
+int npp_empty_col(NPP *npp, NPPCOL *q);
+/* process empty column */
+
+#define npp_implied_value _glp_npp_implied_value
+int npp_implied_value(NPP *npp, NPPCOL *q, double s);
+/* process implied column value */
+
+#define npp_eq_singlet _glp_npp_eq_singlet
+int npp_eq_singlet(NPP *npp, NPPROW *p);
+/* process row singleton (equality constraint) */
+
+#define npp_implied_lower _glp_npp_implied_lower
+int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
+/* process implied column lower bound */
+
+#define npp_implied_upper _glp_npp_implied_upper
+int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
+/* process implied upper bound of column */
+
+#define npp_ineq_singlet _glp_npp_ineq_singlet
+int npp_ineq_singlet(NPP *npp, NPPROW *p);
+/* process row singleton (inequality constraint) */
+
+#define npp_implied_slack _glp_npp_implied_slack
+void npp_implied_slack(NPP *npp, NPPCOL *q);
+/* process column singleton (implied slack variable) */
+
+#define npp_implied_free _glp_npp_implied_free
+int npp_implied_free(NPP *npp, NPPCOL *q);
+/* process column singleton (implied free variable) */
+
+#define npp_eq_doublet _glp_npp_eq_doublet
+NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
+/* process row doubleton (equality constraint) */
+
+#define npp_forcing_row _glp_npp_forcing_row
+int npp_forcing_row(NPP *npp, NPPROW *p, int at);
+/* process forcing row */
+
+#define npp_analyze_row _glp_npp_analyze_row
+int npp_analyze_row(NPP *npp, NPPROW *p);
+/* perform general row analysis */
+
+#define npp_inactive_bound _glp_npp_inactive_bound
+void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
+/* remove row lower/upper inactive bound */
+
+#define npp_implied_bounds _glp_npp_implied_bounds
+void npp_implied_bounds(NPP *npp, NPPROW *p);
+/* determine implied column bounds */
+
+#define npp_binarize_prob _glp_npp_binarize_prob
+int npp_binarize_prob(NPP *npp);
+/* binarize MIP problem */
+
+#define npp_is_packing _glp_npp_is_packing
+int npp_is_packing(NPP *npp, NPPROW *row);
+/* test if constraint is packing inequality */
+
+#define npp_hidden_packing _glp_npp_hidden_packing
+int npp_hidden_packing(NPP *npp, NPPROW *row);
+/* identify hidden packing inequality */
+
+#define npp_implied_packing _glp_npp_implied_packing
+int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+ NPPCOL *var[], char set[]);
+/* identify implied packing inequality */
+
+#define npp_is_covering _glp_npp_is_covering
+int npp_is_covering(NPP *npp, NPPROW *row);
+/* test if constraint is covering inequality */
+
+#define npp_hidden_covering _glp_npp_hidden_covering
+int npp_hidden_covering(NPP *npp, NPPROW *row);
+/* identify hidden covering inequality */
+
+#define npp_is_partitioning _glp_npp_is_partitioning
+int npp_is_partitioning(NPP *npp, NPPROW *row);
+/* test if constraint is partitioning equality */
+
+#define npp_reduce_ineq_coef _glp_npp_reduce_ineq_coef
+int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
+/* reduce inequality constraint coefficients */
+
+#define npp_clean_prob _glp_npp_clean_prob
+void npp_clean_prob(NPP *npp);
+/* perform initial LP/MIP processing */
+
+#define npp_process_row _glp_npp_process_row
+int npp_process_row(NPP *npp, NPPROW *row, int hard);
+/* perform basic row processing */
+
+#define npp_improve_bounds _glp_npp_improve_bounds
+int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
+/* improve current column bounds */
+
+#define npp_process_col _glp_npp_process_col
+int npp_process_col(NPP *npp, NPPCOL *col);
+/* perform basic column processing */
+
+#define npp_process_prob _glp_npp_process_prob
+int npp_process_prob(NPP *npp, int hard);
+/* perform basic LP/MIP processing */
+
+#define npp_simplex _glp_npp_simplex
+int npp_simplex(NPP *npp, const glp_smcp *parm);
+/* process LP prior to applying primal/dual simplex method */
+
+#define npp_integer _glp_npp_integer
+int npp_integer(NPP *npp, const glp_iocp *parm);
+/* process MIP prior to applying branch-and-bound method */
+
+/**********************************************************************/
+
+#define npp_sat_free_row _glp_npp_sat_free_row
+void npp_sat_free_row(NPP *npp, NPPROW *p);
+/* process free (unbounded) row */
+
+#define npp_sat_fixed_col _glp_npp_sat_fixed_col
+int npp_sat_fixed_col(NPP *npp, NPPCOL *q);
+/* process fixed column */
+
+#define npp_sat_is_bin_comb _glp_npp_sat_is_bin_comb
+int npp_sat_is_bin_comb(NPP *npp, NPPROW *row);
+/* test if row is binary combination */
+
+#define npp_sat_num_pos_coef _glp_npp_sat_num_pos_coef
+int npp_sat_num_pos_coef(NPP *npp, NPPROW *row);
+/* determine number of positive coefficients */
+
+#define npp_sat_num_neg_coef _glp_npp_sat_num_neg_coef
+int npp_sat_num_neg_coef(NPP *npp, NPPROW *row);
+/* determine number of negative coefficients */
+
+#define npp_sat_is_cover_ineq _glp_npp_sat_is_cover_ineq
+int npp_sat_is_cover_ineq(NPP *npp, NPPROW *row);
+/* test if row is covering inequality */
+
+#define npp_sat_is_pack_ineq _glp_npp_sat_is_pack_ineq
+int npp_sat_is_pack_ineq(NPP *npp, NPPROW *row);
+/* test if row is packing inequality */
+
+#define npp_sat_is_partn_eq _glp_npp_sat_is_partn_eq
+int npp_sat_is_partn_eq(NPP *npp, NPPROW *row);
+/* test if row is partitioning equality */
+
+#define npp_sat_reverse_row _glp_npp_sat_reverse_row
+int npp_sat_reverse_row(NPP *npp, NPPROW *row);
+/* multiply both sides of row by -1 */
+
+#define npp_sat_split_pack _glp_npp_sat_split_pack
+NPPROW *npp_sat_split_pack(NPP *npp, NPPROW *row, int nnn);
+/* split packing inequality */
+
+#define npp_sat_encode_pack _glp_npp_sat_encode_pack
+void npp_sat_encode_pack(NPP *npp, NPPROW *row);
+/* encode packing inequality */
+
+typedef struct NPPLIT NPPLIT;
+typedef struct NPPLSE NPPLSE;
+typedef struct NPPSED NPPSED;
+
+struct NPPLIT
+{ /* literal (binary variable or its negation) */
+ NPPCOL *col;
+ /* pointer to binary variable; NULL means constant false */
+ int neg;
+ /* negation flag:
+ 0 - literal is variable (or constant false)
+ 1 - literal is negation of variable (or constant true) */
+};
+
+struct NPPLSE
+{ /* literal set element */
+ NPPLIT lit;
+ /* literal */
+ NPPLSE *next;
+ /* pointer to another element */
+};
+
+struct NPPSED
+{ /* summation encoding descriptor */
+ /* this struct describes the equality
+ x + y + z = s + 2 * c,
+ which was encoded as CNF and included into the transformed
+ problem; here x and y are literals, z is either a literal or
+ constant zero, s and c are binary variables modeling, resp.,
+ the low and high (carry) sum bits */
+ NPPLIT x, y, z;
+ /* literals; if z.col = NULL, z is constant zero */
+ NPPCOL *s, *c;
+ /* binary variables modeling the sum bits */
+};
+
+#define npp_sat_encode_sum2 _glp_npp_sat_encode_sum2
+void npp_sat_encode_sum2(NPP *npp, NPPLSE *set, NPPSED *sed);
+/* encode 2-bit summation */
+
+#define npp_sat_encode_sum3 _glp_npp_sat_encode_sum3
+void npp_sat_encode_sum3(NPP *npp, NPPLSE *set, NPPSED *sed);
+/* encode 3-bit summation */
+
+#define npp_sat_encode_sum_ax _glp_npp_sat_encode_sum_ax
+int npp_sat_encode_sum_ax(NPP *npp, NPPROW *row, NPPLIT y[]);
+/* encode linear combination of 0-1 variables */
+
+#define npp_sat_normalize_clause _glp_npp_sat_normalize_clause
+int npp_sat_normalize_clause(NPP *npp, int size, NPPLIT lit[]);
+/* normalize clause */
+
+#define npp_sat_encode_clause _glp_npp_sat_encode_clause
+NPPROW *npp_sat_encode_clause(NPP *npp, int size, NPPLIT lit[]);
+/* translate clause to cover inequality */
+
+#define npp_sat_encode_geq _glp_npp_sat_encode_geq
+int npp_sat_encode_geq(NPP *npp, int n, NPPLIT y[], int rhs);
+/* encode "not less than" constraint */
+
+#define npp_sat_encode_leq _glp_npp_sat_encode_leq
+int npp_sat_encode_leq(NPP *npp, int n, NPPLIT y[], int rhs);
+/* encode "not greater than" constraint */
+
+#define npp_sat_encode_row _glp_npp_sat_encode_row
+int npp_sat_encode_row(NPP *npp, NPPROW *row);
+/* encode constraint (row) of general type */
+
+#define npp_sat_encode_prob _glp_npp_sat_encode_prob
+int npp_sat_encode_prob(NPP *npp);
+/* encode 0-1 feasibility problem */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp1.c b/test/monniaux/glpk-4.65/src/npp/npp1.c
new file mode 100644
index 00000000..51758bad
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp1.c
@@ -0,0 +1,937 @@
+/* npp1.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+NPP *npp_create_wksp(void)
+{ /* create LP/MIP preprocessor workspace */
+ NPP *npp;
+ npp = xmalloc(sizeof(NPP));
+ npp->orig_dir = 0;
+ npp->orig_m = npp->orig_n = npp->orig_nnz = 0;
+ npp->pool = dmp_create_pool();
+ npp->name = npp->obj = NULL;
+ npp->c0 = 0.0;
+ npp->nrows = npp->ncols = 0;
+ npp->r_head = npp->r_tail = NULL;
+ npp->c_head = npp->c_tail = NULL;
+ npp->stack = dmp_create_pool();
+ npp->top = NULL;
+#if 0 /* 16/XII-2009 */
+ memset(&npp->count, 0, sizeof(npp->count));
+#endif
+ npp->m = npp->n = npp->nnz = 0;
+ npp->row_ref = npp->col_ref = NULL;
+ npp->sol = npp->scaling = 0;
+ npp->p_stat = npp->d_stat = npp->t_stat = npp->i_stat = 0;
+ npp->r_stat = NULL;
+ /*npp->r_prim =*/ npp->r_pi = NULL;
+ npp->c_stat = NULL;
+ npp->c_value = /*npp->c_dual =*/ NULL;
+ return npp;
+}
+
+void npp_insert_row(NPP *npp, NPPROW *row, int where)
+{ /* insert row to the row list */
+ if (where == 0)
+ { /* insert row to the beginning of the row list */
+ row->prev = NULL;
+ row->next = npp->r_head;
+ if (row->next == NULL)
+ npp->r_tail = row;
+ else
+ row->next->prev = row;
+ npp->r_head = row;
+ }
+ else
+ { /* insert row to the end of the row list */
+ row->prev = npp->r_tail;
+ row->next = NULL;
+ if (row->prev == NULL)
+ npp->r_head = row;
+ else
+ row->prev->next = row;
+ npp->r_tail = row;
+ }
+ return;
+}
+
+void npp_remove_row(NPP *npp, NPPROW *row)
+{ /* remove row from the row list */
+ if (row->prev == NULL)
+ npp->r_head = row->next;
+ else
+ row->prev->next = row->next;
+ if (row->next == NULL)
+ npp->r_tail = row->prev;
+ else
+ row->next->prev = row->prev;
+ return;
+}
+
+void npp_activate_row(NPP *npp, NPPROW *row)
+{ /* make row active */
+ if (!row->temp)
+ { row->temp = 1;
+ /* move the row to the beginning of the row list */
+ npp_remove_row(npp, row);
+ npp_insert_row(npp, row, 0);
+ }
+ return;
+}
+
+void npp_deactivate_row(NPP *npp, NPPROW *row)
+{ /* make row inactive */
+ if (row->temp)
+ { row->temp = 0;
+ /* move the row to the end of the row list */
+ npp_remove_row(npp, row);
+ npp_insert_row(npp, row, 1);
+ }
+ return;
+}
+
+void npp_insert_col(NPP *npp, NPPCOL *col, int where)
+{ /* insert column to the column list */
+ if (where == 0)
+ { /* insert column to the beginning of the column list */
+ col->prev = NULL;
+ col->next = npp->c_head;
+ if (col->next == NULL)
+ npp->c_tail = col;
+ else
+ col->next->prev = col;
+ npp->c_head = col;
+ }
+ else
+ { /* insert column to the end of the column list */
+ col->prev = npp->c_tail;
+ col->next = NULL;
+ if (col->prev == NULL)
+ npp->c_head = col;
+ else
+ col->prev->next = col;
+ npp->c_tail = col;
+ }
+ return;
+}
+
+void npp_remove_col(NPP *npp, NPPCOL *col)
+{ /* remove column from the column list */
+ if (col->prev == NULL)
+ npp->c_head = col->next;
+ else
+ col->prev->next = col->next;
+ if (col->next == NULL)
+ npp->c_tail = col->prev;
+ else
+ col->next->prev = col->prev;
+ return;
+}
+
+void npp_activate_col(NPP *npp, NPPCOL *col)
+{ /* make column active */
+ if (!col->temp)
+ { col->temp = 1;
+ /* move the column to the beginning of the column list */
+ npp_remove_col(npp, col);
+ npp_insert_col(npp, col, 0);
+ }
+ return;
+}
+
+void npp_deactivate_col(NPP *npp, NPPCOL *col)
+{ /* make column inactive */
+ if (col->temp)
+ { col->temp = 0;
+ /* move the column to the end of the column list */
+ npp_remove_col(npp, col);
+ npp_insert_col(npp, col, 1);
+ }
+ return;
+}
+
+NPPROW *npp_add_row(NPP *npp)
+{ /* add new row to the current problem */
+ NPPROW *row;
+ row = dmp_get_atom(npp->pool, sizeof(NPPROW));
+ row->i = ++(npp->nrows);
+ row->name = NULL;
+ row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+ row->ptr = NULL;
+ row->temp = 0;
+ npp_insert_row(npp, row, 1);
+ return row;
+}
+
+NPPCOL *npp_add_col(NPP *npp)
+{ /* add new column to the current problem */
+ NPPCOL *col;
+ col = dmp_get_atom(npp->pool, sizeof(NPPCOL));
+ col->j = ++(npp->ncols);
+ col->name = NULL;
+#if 0
+ col->kind = GLP_CV;
+#else
+ col->is_int = 0;
+#endif
+ col->lb = col->ub = col->coef = 0.0;
+ col->ptr = NULL;
+ col->temp = 0;
+ npp_insert_col(npp, col, 1);
+ return col;
+}
+
+NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val)
+{ /* add new element to the constraint matrix */
+ NPPAIJ *aij;
+ aij = dmp_get_atom(npp->pool, sizeof(NPPAIJ));
+ aij->row = row;
+ aij->col = col;
+ aij->val = val;
+ aij->r_prev = NULL;
+ aij->r_next = row->ptr;
+ aij->c_prev = NULL;
+ aij->c_next = col->ptr;
+ if (aij->r_next != NULL)
+ aij->r_next->r_prev = aij;
+ if (aij->c_next != NULL)
+ aij->c_next->c_prev = aij;
+ row->ptr = col->ptr = aij;
+ return aij;
+}
+
+int npp_row_nnz(NPP *npp, NPPROW *row)
+{ /* count number of non-zero coefficients in row */
+ NPPAIJ *aij;
+ int nnz;
+ xassert(npp == npp);
+ nnz = 0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ nnz++;
+ return nnz;
+}
+
+int npp_col_nnz(NPP *npp, NPPCOL *col)
+{ /* count number of non-zero coefficients in column */
+ NPPAIJ *aij;
+ int nnz;
+ xassert(npp == npp);
+ nnz = 0;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ nnz++;
+ return nnz;
+}
+
+void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
+ int size)
+{ /* push new entry to the transformation stack */
+ NPPTSE *tse;
+ tse = dmp_get_atom(npp->stack, sizeof(NPPTSE));
+ tse->func = func;
+ tse->info = dmp_get_atom(npp->stack, size);
+ tse->link = npp->top;
+ npp->top = tse;
+ return tse->info;
+}
+
+#if 1 /* 23/XII-2009 */
+void npp_erase_row(NPP *npp, NPPROW *row)
+{ /* erase row content to make it empty */
+ NPPAIJ *aij;
+ while (row->ptr != NULL)
+ { aij = row->ptr;
+ row->ptr = aij->r_next;
+ if (aij->c_prev == NULL)
+ aij->col->ptr = aij->c_next;
+ else
+ aij->c_prev->c_next = aij->c_next;
+ if (aij->c_next == NULL)
+ ;
+ else
+ aij->c_next->c_prev = aij->c_prev;
+ dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+ }
+ return;
+}
+#endif
+
+void npp_del_row(NPP *npp, NPPROW *row)
+{ /* remove row from the current problem */
+#if 0 /* 23/XII-2009 */
+ NPPAIJ *aij;
+#endif
+ if (row->name != NULL)
+ dmp_free_atom(npp->pool, row->name, strlen(row->name)+1);
+#if 0 /* 23/XII-2009 */
+ while (row->ptr != NULL)
+ { aij = row->ptr;
+ row->ptr = aij->r_next;
+ if (aij->c_prev == NULL)
+ aij->col->ptr = aij->c_next;
+ else
+ aij->c_prev->c_next = aij->c_next;
+ if (aij->c_next == NULL)
+ ;
+ else
+ aij->c_next->c_prev = aij->c_prev;
+ dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+ }
+#else
+ npp_erase_row(npp, row);
+#endif
+ npp_remove_row(npp, row);
+ dmp_free_atom(npp->pool, row, sizeof(NPPROW));
+ return;
+}
+
+void npp_del_col(NPP *npp, NPPCOL *col)
+{ /* remove column from the current problem */
+ NPPAIJ *aij;
+ if (col->name != NULL)
+ dmp_free_atom(npp->pool, col->name, strlen(col->name)+1);
+ while (col->ptr != NULL)
+ { aij = col->ptr;
+ col->ptr = aij->c_next;
+ if (aij->r_prev == NULL)
+ aij->row->ptr = aij->r_next;
+ else
+ aij->r_prev->r_next = aij->r_next;
+ if (aij->r_next == NULL)
+ ;
+ else
+ aij->r_next->r_prev = aij->r_prev;
+ dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+ }
+ npp_remove_col(npp, col);
+ dmp_free_atom(npp->pool, col, sizeof(NPPCOL));
+ return;
+}
+
+void npp_del_aij(NPP *npp, NPPAIJ *aij)
+{ /* remove element from the constraint matrix */
+ if (aij->r_prev == NULL)
+ aij->row->ptr = aij->r_next;
+ else
+ aij->r_prev->r_next = aij->r_next;
+ if (aij->r_next == NULL)
+ ;
+ else
+ aij->r_next->r_prev = aij->r_prev;
+ if (aij->c_prev == NULL)
+ aij->col->ptr = aij->c_next;
+ else
+ aij->c_prev->c_next = aij->c_next;
+ if (aij->c_next == NULL)
+ ;
+ else
+ aij->c_next->c_prev = aij->c_prev;
+ dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+ return;
+}
+
+void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
+ int scaling)
+{ /* load original problem into the preprocessor workspace */
+ int m = orig->m;
+ int n = orig->n;
+ NPPROW **link;
+ int i, j;
+ double dir;
+ xassert(names == GLP_OFF || names == GLP_ON);
+ xassert(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP);
+ xassert(scaling == GLP_OFF || scaling == GLP_ON);
+ if (sol == GLP_MIP) xassert(!scaling);
+ npp->orig_dir = orig->dir;
+ if (npp->orig_dir == GLP_MIN)
+ dir = +1.0;
+ else if (npp->orig_dir == GLP_MAX)
+ dir = -1.0;
+ else
+ xassert(npp != npp);
+ npp->orig_m = m;
+ npp->orig_n = n;
+ npp->orig_nnz = orig->nnz;
+ if (names && orig->name != NULL)
+ { npp->name = dmp_get_atom(npp->pool, strlen(orig->name)+1);
+ strcpy(npp->name, orig->name);
+ }
+ if (names && orig->obj != NULL)
+ { npp->obj = dmp_get_atom(npp->pool, strlen(orig->obj)+1);
+ strcpy(npp->obj, orig->obj);
+ }
+ npp->c0 = dir * orig->c0;
+ /* load rows */
+ link = xcalloc(1+m, sizeof(NPPROW *));
+ for (i = 1; i <= m; i++)
+ { GLPROW *rrr = orig->row[i];
+ NPPROW *row;
+ link[i] = row = npp_add_row(npp);
+ xassert(row->i == i);
+ if (names && rrr->name != NULL)
+ { row->name = dmp_get_atom(npp->pool, strlen(rrr->name)+1);
+ strcpy(row->name, rrr->name);
+ }
+ if (!scaling)
+ { if (rrr->type == GLP_FR)
+ row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+ else if (rrr->type == GLP_LO)
+ row->lb = rrr->lb, row->ub = +DBL_MAX;
+ else if (rrr->type == GLP_UP)
+ row->lb = -DBL_MAX, row->ub = rrr->ub;
+ else if (rrr->type == GLP_DB)
+ row->lb = rrr->lb, row->ub = rrr->ub;
+ else if (rrr->type == GLP_FX)
+ row->lb = row->ub = rrr->lb;
+ else
+ xassert(rrr != rrr);
+ }
+ else
+ { double rii = rrr->rii;
+ if (rrr->type == GLP_FR)
+ row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+ else if (rrr->type == GLP_LO)
+ row->lb = rrr->lb * rii, row->ub = +DBL_MAX;
+ else if (rrr->type == GLP_UP)
+ row->lb = -DBL_MAX, row->ub = rrr->ub * rii;
+ else if (rrr->type == GLP_DB)
+ row->lb = rrr->lb * rii, row->ub = rrr->ub * rii;
+ else if (rrr->type == GLP_FX)
+ row->lb = row->ub = rrr->lb * rii;
+ else
+ xassert(rrr != rrr);
+ }
+ }
+ /* load columns and constraint coefficients */
+ for (j = 1; j <= n; j++)
+ { GLPCOL *ccc = orig->col[j];
+ GLPAIJ *aaa;
+ NPPCOL *col;
+ col = npp_add_col(npp);
+ xassert(col->j == j);
+ if (names && ccc->name != NULL)
+ { col->name = dmp_get_atom(npp->pool, strlen(ccc->name)+1);
+ strcpy(col->name, ccc->name);
+ }
+ if (sol == GLP_MIP)
+#if 0
+ col->kind = ccc->kind;
+#else
+ col->is_int = (char)(ccc->kind == GLP_IV);
+#endif
+ if (!scaling)
+ { if (ccc->type == GLP_FR)
+ col->lb = -DBL_MAX, col->ub = +DBL_MAX;
+ else if (ccc->type == GLP_LO)
+ col->lb = ccc->lb, col->ub = +DBL_MAX;
+ else if (ccc->type == GLP_UP)
+ col->lb = -DBL_MAX, col->ub = ccc->ub;
+ else if (ccc->type == GLP_DB)
+ col->lb = ccc->lb, col->ub = ccc->ub;
+ else if (ccc->type == GLP_FX)
+ col->lb = col->ub = ccc->lb;
+ else
+ xassert(ccc != ccc);
+ col->coef = dir * ccc->coef;
+ for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
+ npp_add_aij(npp, link[aaa->row->i], col, aaa->val);
+ }
+ else
+ { double sjj = ccc->sjj;
+ if (ccc->type == GLP_FR)
+ col->lb = -DBL_MAX, col->ub = +DBL_MAX;
+ else if (ccc->type == GLP_LO)
+ col->lb = ccc->lb / sjj, col->ub = +DBL_MAX;
+ else if (ccc->type == GLP_UP)
+ col->lb = -DBL_MAX, col->ub = ccc->ub / sjj;
+ else if (ccc->type == GLP_DB)
+ col->lb = ccc->lb / sjj, col->ub = ccc->ub / sjj;
+ else if (ccc->type == GLP_FX)
+ col->lb = col->ub = ccc->lb / sjj;
+ else
+ xassert(ccc != ccc);
+ col->coef = dir * ccc->coef * sjj;
+ for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
+ npp_add_aij(npp, link[aaa->row->i], col,
+ aaa->row->rii * aaa->val * sjj);
+ }
+ }
+ xfree(link);
+ /* keep solution indicator and scaling option */
+ npp->sol = sol;
+ npp->scaling = scaling;
+ return;
+}
+
+void npp_build_prob(NPP *npp, glp_prob *prob)
+{ /* build resultant (preprocessed) problem */
+ NPPROW *row;
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int i, j, type, len, *ind;
+ double dir, *val;
+ glp_erase_prob(prob);
+ glp_set_prob_name(prob, npp->name);
+ glp_set_obj_name(prob, npp->obj);
+ glp_set_obj_dir(prob, npp->orig_dir);
+ if (npp->orig_dir == GLP_MIN)
+ dir = +1.0;
+ else if (npp->orig_dir == GLP_MAX)
+ dir = -1.0;
+ else
+ xassert(npp != npp);
+ glp_set_obj_coef(prob, 0, dir * npp->c0);
+ /* build rows */
+ for (row = npp->r_head; row != NULL; row = row->next)
+ { row->temp = i = glp_add_rows(prob, 1);
+ glp_set_row_name(prob, i, row->name);
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ type = GLP_FR;
+ else if (row->ub == +DBL_MAX)
+ type = GLP_LO;
+ else if (row->lb == -DBL_MAX)
+ type = GLP_UP;
+ else if (row->lb != row->ub)
+ type = GLP_DB;
+ else
+ type = GLP_FX;
+ glp_set_row_bnds(prob, i, type, row->lb, row->ub);
+ }
+ /* build columns and the constraint matrix */
+ ind = xcalloc(1+prob->m, sizeof(int));
+ val = xcalloc(1+prob->m, sizeof(double));
+ for (col = npp->c_head; col != NULL; col = col->next)
+ { j = glp_add_cols(prob, 1);
+ glp_set_col_name(prob, j, col->name);
+#if 0
+ glp_set_col_kind(prob, j, col->kind);
+#else
+ glp_set_col_kind(prob, j, col->is_int ? GLP_IV : GLP_CV);
+#endif
+ if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
+ type = GLP_FR;
+ else if (col->ub == +DBL_MAX)
+ type = GLP_LO;
+ else if (col->lb == -DBL_MAX)
+ type = GLP_UP;
+ else if (col->lb != col->ub)
+ type = GLP_DB;
+ else
+ type = GLP_FX;
+ glp_set_col_bnds(prob, j, type, col->lb, col->ub);
+ glp_set_obj_coef(prob, j, dir * col->coef);
+ len = 0;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ { len++;
+ ind[len] = aij->row->temp;
+ val[len] = aij->val;
+ }
+ glp_set_mat_col(prob, j, len, ind, val);
+ }
+ xfree(ind);
+ xfree(val);
+ /* resultant problem has been built */
+ npp->m = prob->m;
+ npp->n = prob->n;
+ npp->nnz = prob->nnz;
+ npp->row_ref = xcalloc(1+npp->m, sizeof(int));
+ npp->col_ref = xcalloc(1+npp->n, sizeof(int));
+ for (row = npp->r_head, i = 0; row != NULL; row = row->next)
+ npp->row_ref[++i] = row->i;
+ for (col = npp->c_head, j = 0; col != NULL; col = col->next)
+ npp->col_ref[++j] = col->j;
+ /* transformed problem segment is no longer needed */
+ dmp_delete_pool(npp->pool), npp->pool = NULL;
+ npp->name = npp->obj = NULL;
+ npp->c0 = 0.0;
+ npp->r_head = npp->r_tail = NULL;
+ npp->c_head = npp->c_tail = NULL;
+ return;
+}
+
+void npp_postprocess(NPP *npp, glp_prob *prob)
+{ /* postprocess solution from the resultant problem */
+ GLPROW *row;
+ GLPCOL *col;
+ NPPTSE *tse;
+ int i, j, k;
+ double dir;
+ xassert(npp->orig_dir == prob->dir);
+ if (npp->orig_dir == GLP_MIN)
+ dir = +1.0;
+ else if (npp->orig_dir == GLP_MAX)
+ dir = -1.0;
+ else
+ xassert(npp != npp);
+#if 0 /* 11/VII-2013; due to call from ios_main */
+ xassert(npp->m == prob->m);
+#else
+ if (npp->sol != GLP_MIP)
+ xassert(npp->m == prob->m);
+#endif
+ xassert(npp->n == prob->n);
+#if 0 /* 11/VII-2013; due to call from ios_main */
+ xassert(npp->nnz == prob->nnz);
+#else
+ if (npp->sol != GLP_MIP)
+ xassert(npp->nnz == prob->nnz);
+#endif
+ /* copy solution status */
+ if (npp->sol == GLP_SOL)
+ { npp->p_stat = prob->pbs_stat;
+ npp->d_stat = prob->dbs_stat;
+ }
+ else if (npp->sol == GLP_IPT)
+ npp->t_stat = prob->ipt_stat;
+ else if (npp->sol == GLP_MIP)
+ npp->i_stat = prob->mip_stat;
+ else
+ xassert(npp != npp);
+ /* allocate solution arrays */
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat == NULL)
+ npp->r_stat = xcalloc(1+npp->nrows, sizeof(char));
+ for (i = 1; i <= npp->nrows; i++)
+ npp->r_stat[i] = 0;
+ if (npp->c_stat == NULL)
+ npp->c_stat = xcalloc(1+npp->ncols, sizeof(char));
+ for (j = 1; j <= npp->ncols; j++)
+ npp->c_stat[j] = 0;
+ }
+#if 0
+ if (npp->r_prim == NULL)
+ npp->r_prim = xcalloc(1+npp->nrows, sizeof(double));
+ for (i = 1; i <= npp->nrows; i++)
+ npp->r_prim[i] = DBL_MAX;
+#endif
+ if (npp->c_value == NULL)
+ npp->c_value = xcalloc(1+npp->ncols, sizeof(double));
+ for (j = 1; j <= npp->ncols; j++)
+ npp->c_value[j] = DBL_MAX;
+ if (npp->sol != GLP_MIP)
+ { if (npp->r_pi == NULL)
+ npp->r_pi = xcalloc(1+npp->nrows, sizeof(double));
+ for (i = 1; i <= npp->nrows; i++)
+ npp->r_pi[i] = DBL_MAX;
+#if 0
+ if (npp->c_dual == NULL)
+ npp->c_dual = xcalloc(1+npp->ncols, sizeof(double));
+ for (j = 1; j <= npp->ncols; j++)
+ npp->c_dual[j] = DBL_MAX;
+#endif
+ }
+ /* copy solution components from the resultant problem */
+ if (npp->sol == GLP_SOL)
+ { for (i = 1; i <= npp->m; i++)
+ { row = prob->row[i];
+ k = npp->row_ref[i];
+ npp->r_stat[k] = (char)row->stat;
+ /*npp->r_prim[k] = row->prim;*/
+ npp->r_pi[k] = dir * row->dual;
+ }
+ for (j = 1; j <= npp->n; j++)
+ { col = prob->col[j];
+ k = npp->col_ref[j];
+ npp->c_stat[k] = (char)col->stat;
+ npp->c_value[k] = col->prim;
+ /*npp->c_dual[k] = dir * col->dual;*/
+ }
+ }
+ else if (npp->sol == GLP_IPT)
+ { for (i = 1; i <= npp->m; i++)
+ { row = prob->row[i];
+ k = npp->row_ref[i];
+ /*npp->r_prim[k] = row->pval;*/
+ npp->r_pi[k] = dir * row->dval;
+ }
+ for (j = 1; j <= npp->n; j++)
+ { col = prob->col[j];
+ k = npp->col_ref[j];
+ npp->c_value[k] = col->pval;
+ /*npp->c_dual[k] = dir * col->dval;*/
+ }
+ }
+ else if (npp->sol == GLP_MIP)
+ {
+#if 0
+ for (i = 1; i <= npp->m; i++)
+ { row = prob->row[i];
+ k = npp->row_ref[i];
+ /*npp->r_prim[k] = row->mipx;*/
+ }
+#endif
+ for (j = 1; j <= npp->n; j++)
+ { col = prob->col[j];
+ k = npp->col_ref[j];
+ npp->c_value[k] = col->mipx;
+ }
+ }
+ else
+ xassert(npp != npp);
+ /* perform postprocessing to construct solution to the original
+ problem */
+ for (tse = npp->top; tse != NULL; tse = tse->link)
+ { xassert(tse->func != NULL);
+ xassert(tse->func(npp, tse->info) == 0);
+ }
+ return;
+}
+
+void npp_unload_sol(NPP *npp, glp_prob *orig)
+{ /* store solution to the original problem */
+ GLPROW *row;
+ GLPCOL *col;
+ int i, j;
+ double dir;
+ xassert(npp->orig_dir == orig->dir);
+ if (npp->orig_dir == GLP_MIN)
+ dir = +1.0;
+ else if (npp->orig_dir == GLP_MAX)
+ dir = -1.0;
+ else
+ xassert(npp != npp);
+ xassert(npp->orig_m == orig->m);
+ xassert(npp->orig_n == orig->n);
+ xassert(npp->orig_nnz == orig->nnz);
+ if (npp->sol == GLP_SOL)
+ { /* store basic solution */
+ orig->valid = 0;
+ orig->pbs_stat = npp->p_stat;
+ orig->dbs_stat = npp->d_stat;
+ orig->obj_val = orig->c0;
+ orig->some = 0;
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ row->stat = npp->r_stat[i];
+ if (!npp->scaling)
+ { /*row->prim = npp->r_prim[i];*/
+ row->dual = dir * npp->r_pi[i];
+ }
+ else
+ { /*row->prim = npp->r_prim[i] / row->rii;*/
+ row->dual = dir * npp->r_pi[i] * row->rii;
+ }
+ if (row->stat == GLP_BS)
+ row->dual = 0.0;
+ else if (row->stat == GLP_NL)
+ { xassert(row->type == GLP_LO || row->type == GLP_DB);
+ row->prim = row->lb;
+ }
+ else if (row->stat == GLP_NU)
+ { xassert(row->type == GLP_UP || row->type == GLP_DB);
+ row->prim = row->ub;
+ }
+ else if (row->stat == GLP_NF)
+ { xassert(row->type == GLP_FR);
+ row->prim = 0.0;
+ }
+ else if (row->stat == GLP_NS)
+ { xassert(row->type == GLP_FX);
+ row->prim = row->lb;
+ }
+ else
+ xassert(row != row);
+ }
+ for (j = 1; j <= orig->n; j++)
+ { col = orig->col[j];
+ col->stat = npp->c_stat[j];
+ if (!npp->scaling)
+ { col->prim = npp->c_value[j];
+ /*col->dual = dir * npp->c_dual[j];*/
+ }
+ else
+ { col->prim = npp->c_value[j] * col->sjj;
+ /*col->dual = dir * npp->c_dual[j] / col->sjj;*/
+ }
+ if (col->stat == GLP_BS)
+ col->dual = 0.0;
+#if 1
+ else if (col->stat == GLP_NL)
+ { xassert(col->type == GLP_LO || col->type == GLP_DB);
+ col->prim = col->lb;
+ }
+ else if (col->stat == GLP_NU)
+ { xassert(col->type == GLP_UP || col->type == GLP_DB);
+ col->prim = col->ub;
+ }
+ else if (col->stat == GLP_NF)
+ { xassert(col->type == GLP_FR);
+ col->prim = 0.0;
+ }
+ else if (col->stat == GLP_NS)
+ { xassert(col->type == GLP_FX);
+ col->prim = col->lb;
+ }
+ else
+ xassert(col != col);
+#endif
+ orig->obj_val += col->coef * col->prim;
+ }
+#if 1
+ /* compute primal values of inactive rows */
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ if (row->stat == GLP_BS)
+ { GLPAIJ *aij;
+ double temp;
+ temp = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ temp += aij->val * aij->col->prim;
+ row->prim = temp;
+ }
+ }
+ /* compute reduced costs of active columns */
+ for (j = 1; j <= orig->n; j++)
+ { col = orig->col[j];
+ if (col->stat != GLP_BS)
+ { GLPAIJ *aij;
+ double temp;
+ temp = col->coef;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ temp -= aij->val * aij->row->dual;
+ col->dual = temp;
+ }
+ }
+#endif
+ }
+ else if (npp->sol == GLP_IPT)
+ { /* store interior-point solution */
+ orig->ipt_stat = npp->t_stat;
+ orig->ipt_obj = orig->c0;
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ if (!npp->scaling)
+ { /*row->pval = npp->r_prim[i];*/
+ row->dval = dir * npp->r_pi[i];
+ }
+ else
+ { /*row->pval = npp->r_prim[i] / row->rii;*/
+ row->dval = dir * npp->r_pi[i] * row->rii;
+ }
+ }
+ for (j = 1; j <= orig->n; j++)
+ { col = orig->col[j];
+ if (!npp->scaling)
+ { col->pval = npp->c_value[j];
+ /*col->dval = dir * npp->c_dual[j];*/
+ }
+ else
+ { col->pval = npp->c_value[j] * col->sjj;
+ /*col->dval = dir * npp->c_dual[j] / col->sjj;*/
+ }
+ orig->ipt_obj += col->coef * col->pval;
+ }
+#if 1
+ /* compute row primal values */
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ { GLPAIJ *aij;
+ double temp;
+ temp = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ temp += aij->val * aij->col->pval;
+ row->pval = temp;
+ }
+ }
+ /* compute column dual values */
+ for (j = 1; j <= orig->n; j++)
+ { col = orig->col[j];
+ { GLPAIJ *aij;
+ double temp;
+ temp = col->coef;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ temp -= aij->val * aij->row->dval;
+ col->dval = temp;
+ }
+ }
+#endif
+ }
+ else if (npp->sol == GLP_MIP)
+ { /* store MIP solution */
+ xassert(!npp->scaling);
+ orig->mip_stat = npp->i_stat;
+ orig->mip_obj = orig->c0;
+#if 0
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ /*row->mipx = npp->r_prim[i];*/
+ }
+#endif
+ for (j = 1; j <= orig->n; j++)
+ { col = orig->col[j];
+ col->mipx = npp->c_value[j];
+ if (col->kind == GLP_IV)
+ xassert(col->mipx == floor(col->mipx));
+ orig->mip_obj += col->coef * col->mipx;
+ }
+#if 1
+ /* compute row primal values */
+ for (i = 1; i <= orig->m; i++)
+ { row = orig->row[i];
+ { GLPAIJ *aij;
+ double temp;
+ temp = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ temp += aij->val * aij->col->mipx;
+ row->mipx = temp;
+ }
+ }
+#endif
+ }
+ else
+ xassert(npp != npp);
+ return;
+}
+
+void npp_delete_wksp(NPP *npp)
+{ /* delete LP/MIP preprocessor workspace */
+ if (npp->pool != NULL)
+ dmp_delete_pool(npp->pool);
+ if (npp->stack != NULL)
+ dmp_delete_pool(npp->stack);
+ if (npp->row_ref != NULL)
+ xfree(npp->row_ref);
+ if (npp->col_ref != NULL)
+ xfree(npp->col_ref);
+ if (npp->r_stat != NULL)
+ xfree(npp->r_stat);
+#if 0
+ if (npp->r_prim != NULL)
+ xfree(npp->r_prim);
+#endif
+ if (npp->r_pi != NULL)
+ xfree(npp->r_pi);
+ if (npp->c_stat != NULL)
+ xfree(npp->c_stat);
+ if (npp->c_value != NULL)
+ xfree(npp->c_value);
+#if 0
+ if (npp->c_dual != NULL)
+ xfree(npp->c_dual);
+#endif
+ xfree(npp);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp2.c b/test/monniaux/glpk-4.65/src/npp/npp2.c
new file mode 100644
index 00000000..4efcf1d1
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp2.c
@@ -0,0 +1,1433 @@
+/* npp2.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+/***********************************************************************
+* NAME
+*
+* npp_free_row - process free (unbounded) row
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_free_row(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_free_row processes row p, which is free (i.e. has
+* no finite bounds):
+*
+* -inf < sum a[p,j] x[j] < +inf. (1)
+* j
+*
+* PROBLEM TRANSFORMATION
+*
+* Constraint (1) cannot be active, so it is redundant and can be
+* removed from the original problem.
+*
+* Removing row p leads to removing a column of multiplier pi[p] for
+* this row in the dual system. Since row p has no bounds, pi[p] = 0,
+* so removing the column does not affect the dual solution.
+*
+* RECOVERING BASIC SOLUTION
+*
+* In solution to the original problem row p is inactive constraint,
+* so it is assigned status GLP_BS, and multiplier pi[p] is assigned
+* zero value.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* In solution to the original problem row p is inactive constraint,
+* so its multiplier pi[p] is assigned zero value.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct free_row
+{ /* free (unbounded) row */
+ int p;
+ /* row reference number */
+};
+
+static int rcv_free_row(NPP *npp, void *info);
+
+void npp_free_row(NPP *npp, NPPROW *p)
+{ /* process free (unbounded) row */
+ struct free_row *info;
+ /* the row must be free */
+ xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_free_row, sizeof(struct free_row));
+ info->p = p->i;
+ /* remove the row from the problem */
+ npp_del_row(npp, p);
+ return;
+}
+
+static int rcv_free_row(NPP *npp, void *_info)
+{ /* recover free (unbounded) row */
+ struct free_row *info = _info;
+ if (npp->sol == GLP_SOL)
+ npp->r_stat[info->p] = GLP_BS;
+ if (npp->sol != GLP_MIP)
+ npp->r_pi[info->p] = 0.0;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_geq_row - process row of 'not less than' type
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_geq_row(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_geq_row processes row p, which is 'not less than'
+* inequality constraint:
+*
+* L[p] <= sum a[p,j] x[j] (<= U[p]), (1)
+* j
+*
+* where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
+*
+* PROBLEM TRANSFORMATION
+*
+* Constraint (1) can be replaced by equality constraint:
+*
+* sum a[p,j] x[j] - s = L[p], (2)
+* j
+*
+* where
+*
+* 0 <= s (<= U[p] - L[p]) (3)
+*
+* is a non-negative surplus variable.
+*
+* Since in the primal system there appears column s having the only
+* non-zero coefficient in row p, in the dual system there appears a
+* new row:
+*
+* (-1) pi[p] + lambda = 0, (4)
+*
+* where (-1) is coefficient of column s in row p, pi[p] is multiplier
+* of row p, lambda is multiplier of column q, 0 is coefficient of
+* column s in the objective row.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of row p in solution to the original problem is determined
+* by its status and status of column q in solution to the transformed
+* problem as follows:
+*
+* +--------------------------------------+------------------+
+* | Transformed problem | Original problem |
+* +-----------------+--------------------+------------------+
+* | Status of row p | Status of column s | Status of row p |
+* +-----------------+--------------------+------------------+
+* | GLP_BS | GLP_BS | N/A |
+* | GLP_BS | GLP_NL | GLP_BS |
+* | GLP_BS | GLP_NU | GLP_BS |
+* | GLP_NS | GLP_BS | GLP_BS |
+* | GLP_NS | GLP_NL | GLP_NL |
+* | GLP_NS | GLP_NU | GLP_NU |
+* +-----------------+--------------------+------------------+
+*
+* Value of row multiplier pi[p] in solution to the original problem
+* is the same as in solution to the transformed problem.
+*
+* 1. In solution to the transformed problem row p and column q cannot
+* be basic at the same time; otherwise the basis matrix would have
+* two linear dependent columns: unity column of auxiliary variable
+* of row p and unity column of variable s.
+*
+* 2. Though in the transformed problem row p is equality constraint,
+* it may be basic due to primal degenerate solution.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of row multiplier pi[p] in solution to the original problem
+* is the same as in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct ineq_row
+{ /* inequality constraint row */
+ int p;
+ /* row reference number */
+ int s;
+ /* column reference number for slack/surplus variable */
+};
+
+static int rcv_geq_row(NPP *npp, void *info);
+
+void npp_geq_row(NPP *npp, NPPROW *p)
+{ /* process row of 'not less than' type */
+ struct ineq_row *info;
+ NPPCOL *s;
+ /* the row must have lower bound */
+ xassert(p->lb != -DBL_MAX);
+ xassert(p->lb < p->ub);
+ /* create column for surplus variable */
+ s = npp_add_col(npp);
+ s->lb = 0.0;
+ s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb);
+ /* and add it to the transformed problem */
+ npp_add_aij(npp, p, s, -1.0);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_geq_row, sizeof(struct ineq_row));
+ info->p = p->i;
+ info->s = s->j;
+ /* replace the row by equality constraint */
+ p->ub = p->lb;
+ return;
+}
+
+static int rcv_geq_row(NPP *npp, void *_info)
+{ /* recover row of 'not less than' type */
+ struct ineq_row *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] == GLP_BS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ { npp_error();
+ return 1;
+ }
+ else if (npp->c_stat[info->s] == GLP_NL ||
+ npp->c_stat[info->s] == GLP_NU)
+ npp->r_stat[info->p] = GLP_BS;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else if (npp->r_stat[info->p] == GLP_NS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ npp->r_stat[info->p] = GLP_BS;
+ else if (npp->c_stat[info->s] == GLP_NL)
+ npp->r_stat[info->p] = GLP_NL;
+ else if (npp->c_stat[info->s] == GLP_NU)
+ npp->r_stat[info->p] = GLP_NU;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_leq_row - process row of 'not greater than' type
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_leq_row(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_leq_row processes row p, which is 'not greater than'
+* inequality constraint:
+*
+* (L[p] <=) sum a[p,j] x[j] <= U[p], (1)
+* j
+*
+* where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
+*
+* PROBLEM TRANSFORMATION
+*
+* Constraint (1) can be replaced by equality constraint:
+*
+* sum a[p,j] x[j] + s = L[p], (2)
+* j
+*
+* where
+*
+* 0 <= s (<= U[p] - L[p]) (3)
+*
+* is a non-negative slack variable.
+*
+* Since in the primal system there appears column s having the only
+* non-zero coefficient in row p, in the dual system there appears a
+* new row:
+*
+* (+1) pi[p] + lambda = 0, (4)
+*
+* where (+1) is coefficient of column s in row p, pi[p] is multiplier
+* of row p, lambda is multiplier of column q, 0 is coefficient of
+* column s in the objective row.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of row p in solution to the original problem is determined
+* by its status and status of column q in solution to the transformed
+* problem as follows:
+*
+* +--------------------------------------+------------------+
+* | Transformed problem | Original problem |
+* +-----------------+--------------------+------------------+
+* | Status of row p | Status of column s | Status of row p |
+* +-----------------+--------------------+------------------+
+* | GLP_BS | GLP_BS | N/A |
+* | GLP_BS | GLP_NL | GLP_BS |
+* | GLP_BS | GLP_NU | GLP_BS |
+* | GLP_NS | GLP_BS | GLP_BS |
+* | GLP_NS | GLP_NL | GLP_NU |
+* | GLP_NS | GLP_NU | GLP_NL |
+* +-----------------+--------------------+------------------+
+*
+* Value of row multiplier pi[p] in solution to the original problem
+* is the same as in solution to the transformed problem.
+*
+* 1. In solution to the transformed problem row p and column q cannot
+* be basic at the same time; otherwise the basis matrix would have
+* two linear dependent columns: unity column of auxiliary variable
+* of row p and unity column of variable s.
+*
+* 2. Though in the transformed problem row p is equality constraint,
+* it may be basic due to primal degeneracy.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of row multiplier pi[p] in solution to the original problem
+* is the same as in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+static int rcv_leq_row(NPP *npp, void *info);
+
+void npp_leq_row(NPP *npp, NPPROW *p)
+{ /* process row of 'not greater than' type */
+ struct ineq_row *info;
+ NPPCOL *s;
+ /* the row must have upper bound */
+ xassert(p->ub != +DBL_MAX);
+ xassert(p->lb < p->ub);
+ /* create column for slack variable */
+ s = npp_add_col(npp);
+ s->lb = 0.0;
+ s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb);
+ /* and add it to the transformed problem */
+ npp_add_aij(npp, p, s, +1.0);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_leq_row, sizeof(struct ineq_row));
+ info->p = p->i;
+ info->s = s->j;
+ /* replace the row by equality constraint */
+ p->lb = p->ub;
+ return;
+}
+
+static int rcv_leq_row(NPP *npp, void *_info)
+{ /* recover row of 'not greater than' type */
+ struct ineq_row *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] == GLP_BS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ { npp_error();
+ return 1;
+ }
+ else if (npp->c_stat[info->s] == GLP_NL ||
+ npp->c_stat[info->s] == GLP_NU)
+ npp->r_stat[info->p] = GLP_BS;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else if (npp->r_stat[info->p] == GLP_NS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ npp->r_stat[info->p] = GLP_BS;
+ else if (npp->c_stat[info->s] == GLP_NL)
+ npp->r_stat[info->p] = GLP_NU;
+ else if (npp->c_stat[info->s] == GLP_NU)
+ npp->r_stat[info->p] = GLP_NL;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_free_col - process free (unbounded) column
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_free_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_free_col processes column q, which is free (i.e. has
+* no finite bounds):
+*
+* -oo < x[q] < +oo. (1)
+*
+* PROBLEM TRANSFORMATION
+*
+* Free (unbounded) variable can be replaced by the difference of two
+* non-negative variables:
+*
+* x[q] = s' - s'', s', s'' >= 0. (2)
+*
+* Assuming that in the transformed problem x[q] becomes s',
+* transformation (2) causes new column s'' to appear, which differs
+* from column s' only in the sign of coefficients in constraint and
+* objective rows. Thus, if in the dual system the following row
+* corresponds to column s':
+*
+* sum a[i,q] pi[i] + lambda' = c[q], (3)
+* i
+*
+* the row which corresponds to column s'' is the following:
+*
+* sum (-a[i,q]) pi[i] + lambda'' = -c[q]. (4)
+* i
+*
+* Then from (3) and (4) it follows that:
+*
+* lambda' + lambda'' = 0 => lambda' = lmabda'' = 0, (5)
+*
+* where lambda' and lambda'' are multipliers for columns s' and s'',
+* resp.
+*
+* RECOVERING BASIC SOLUTION
+*
+* With respect to (5) status of column q in solution to the original
+* problem is determined by statuses of columns s' and s'' in solution
+* to the transformed problem as follows:
+*
+* +--------------------------------------+------------------+
+* | Transformed problem | Original problem |
+* +------------------+-------------------+------------------+
+* | Status of col s' | Status of col s'' | Status of col q |
+* +------------------+-------------------+------------------+
+* | GLP_BS | GLP_BS | N/A |
+* | GLP_BS | GLP_NL | GLP_BS |
+* | GLP_NL | GLP_BS | GLP_BS |
+* | GLP_NL | GLP_NL | GLP_NF |
+* +------------------+-------------------+------------------+
+*
+* Value of column q is computed with formula (2).
+*
+* 1. In solution to the transformed problem columns s' and s'' cannot
+* be basic at the same time, because they differ only in the sign,
+* hence, are linear dependent.
+*
+* 2. Though column q is free, it can be non-basic due to dual
+* degeneracy.
+*
+* 3. If column q is integral, columns s' and s'' are also integral.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q is computed with formula (2).
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is computed with formula (2). */
+
+struct free_col
+{ /* free (unbounded) column */
+ int q;
+ /* column reference number for variables x[q] and s' */
+ int s;
+ /* column reference number for variable s'' */
+};
+
+static int rcv_free_col(NPP *npp, void *info);
+
+void npp_free_col(NPP *npp, NPPCOL *q)
+{ /* process free (unbounded) column */
+ struct free_col *info;
+ NPPCOL *s;
+ NPPAIJ *aij;
+ /* the column must be free */
+ xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX);
+ /* variable x[q] becomes s' */
+ q->lb = 0.0, q->ub = +DBL_MAX;
+ /* create variable s'' */
+ s = npp_add_col(npp);
+ s->is_int = q->is_int;
+ s->lb = 0.0, s->ub = +DBL_MAX;
+ /* duplicate objective coefficient */
+ s->coef = -q->coef;
+ /* duplicate column of the constraint matrix */
+ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ npp_add_aij(npp, aij->row, s, -aij->val);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_free_col, sizeof(struct free_col));
+ info->q = q->j;
+ info->s = s->j;
+ return;
+}
+
+static int rcv_free_col(NPP *npp, void *_info)
+{ /* recover free (unbounded) column */
+ struct free_col *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->c_stat[info->q] == GLP_BS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ { npp_error();
+ return 1;
+ }
+ else if (npp->c_stat[info->s] == GLP_NL)
+ npp->c_stat[info->q] = GLP_BS;
+ else
+ { npp_error();
+ return -1;
+ }
+ }
+ else if (npp->c_stat[info->q] == GLP_NL)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ npp->c_stat[info->q] = GLP_BS;
+ else if (npp->c_stat[info->s] == GLP_NL)
+ npp->c_stat[info->q] = GLP_NF;
+ else
+ { npp_error();
+ return -1;
+ }
+ }
+ else
+ { npp_error();
+ return -1;
+ }
+ }
+ /* compute value of x[q] with formula (2) */
+ npp->c_value[info->q] -= npp->c_value[info->s];
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_lbnd_col - process column with (non-zero) lower bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_lbnd_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_lbnd_col processes column q, which has (non-zero)
+* lower bound:
+*
+* l[q] <= x[q] (<= u[q]), (1)
+*
+* where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
+*
+* PROBLEM TRANSFORMATION
+*
+* Column q can be replaced as follows:
+*
+* x[q] = l[q] + s, (2)
+*
+* where
+*
+* 0 <= s (<= u[q] - l[q]) (3)
+*
+* is a non-negative variable.
+*
+* Substituting x[q] from (2) into the objective row, we have:
+*
+* z = sum c[j] x[j] + c0 =
+* j
+*
+* = sum c[j] x[j] + c[q] x[q] + c0 =
+* j!=q
+*
+* = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
+* j!=q
+*
+* = sum c[j] x[j] + c[q] s + c~0,
+*
+* where
+*
+* c~0 = c0 + c[q] l[q] (4)
+*
+* is the constant term of the objective in the transformed problem.
+* Similarly, substituting x[q] into constraint row i, we have:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i] ==>
+* j
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
+* j!=q
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i] ==>
+* j!=q
+*
+* L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
+* j!=q
+*
+* where
+*
+* L~[i] = L[i] - a[i,q] l[q], U~[i] = U[i] - a[i,q] l[q] (5)
+*
+* are lower and upper bounds of row i in the transformed problem,
+* resp.
+*
+* Transformation (2) does not affect the dual system.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of column q in solution to the original problem is the same
+* as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
+* Value of column q is computed with formula (2).
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q is computed with formula (2).
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is computed with formula (2). */
+
+struct bnd_col
+{ /* bounded column */
+ int q;
+ /* column reference number for variables x[q] and s */
+ double bnd;
+ /* lower/upper bound l[q] or u[q] */
+};
+
+static int rcv_lbnd_col(NPP *npp, void *info);
+
+void npp_lbnd_col(NPP *npp, NPPCOL *q)
+{ /* process column with (non-zero) lower bound */
+ struct bnd_col *info;
+ NPPROW *i;
+ NPPAIJ *aij;
+ /* the column must have non-zero lower bound */
+ xassert(q->lb != 0.0);
+ xassert(q->lb != -DBL_MAX);
+ xassert(q->lb < q->ub);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_lbnd_col, sizeof(struct bnd_col));
+ info->q = q->j;
+ info->bnd = q->lb;
+ /* substitute x[q] into objective row */
+ npp->c0 += q->coef * q->lb;
+ /* substitute x[q] into constraint rows */
+ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { i = aij->row;
+ if (i->lb == i->ub)
+ i->ub = (i->lb -= aij->val * q->lb);
+ else
+ { if (i->lb != -DBL_MAX)
+ i->lb -= aij->val * q->lb;
+ if (i->ub != +DBL_MAX)
+ i->ub -= aij->val * q->lb;
+ }
+ }
+ /* column x[q] becomes column s */
+ if (q->ub != +DBL_MAX)
+ q->ub -= q->lb;
+ q->lb = 0.0;
+ return;
+}
+
+static int rcv_lbnd_col(NPP *npp, void *_info)
+{ /* recover column with (non-zero) lower bound */
+ struct bnd_col *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->c_stat[info->q] == GLP_BS ||
+ npp->c_stat[info->q] == GLP_NL ||
+ npp->c_stat[info->q] == GLP_NU)
+ npp->c_stat[info->q] = npp->c_stat[info->q];
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ /* compute value of x[q] with formula (2) */
+ npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_ubnd_col - process column with upper bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_ubnd_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_ubnd_col processes column q, which has upper bound:
+*
+* (l[q] <=) x[q] <= u[q], (1)
+*
+* where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
+*
+* PROBLEM TRANSFORMATION
+*
+* Column q can be replaced as follows:
+*
+* x[q] = u[q] - s, (2)
+*
+* where
+*
+* 0 <= s (<= u[q] - l[q]) (3)
+*
+* is a non-negative variable.
+*
+* Substituting x[q] from (2) into the objective row, we have:
+*
+* z = sum c[j] x[j] + c0 =
+* j
+*
+* = sum c[j] x[j] + c[q] x[q] + c0 =
+* j!=q
+*
+* = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
+* j!=q
+*
+* = sum c[j] x[j] - c[q] s + c~0,
+*
+* where
+*
+* c~0 = c0 + c[q] u[q] (4)
+*
+* is the constant term of the objective in the transformed problem.
+* Similarly, substituting x[q] into constraint row i, we have:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i] ==>
+* j
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
+* j!=q
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i] ==>
+* j!=q
+*
+* L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
+* j!=q
+*
+* where
+*
+* L~[i] = L[i] - a[i,q] u[q], U~[i] = U[i] - a[i,q] u[q] (5)
+*
+* are lower and upper bounds of row i in the transformed problem,
+* resp.
+*
+* Note that in the transformed problem coefficients c[q] and a[i,q]
+* change their sign. Thus, the row of the dual system corresponding to
+* column q:
+*
+* sum a[i,q] pi[i] + lambda[q] = c[q] (6)
+* i
+*
+* in the transformed problem becomes the following:
+*
+* sum (-a[i,q]) pi[i] + lambda[s] = -c[q]. (7)
+* i
+*
+* Therefore:
+*
+* lambda[q] = - lambda[s], (8)
+*
+* where lambda[q] is multiplier for column q, lambda[s] is multiplier
+* for column s.
+*
+* RECOVERING BASIC SOLUTION
+*
+* With respect to (8) status of column q in solution to the original
+* problem is determined by status of column s in solution to the
+* transformed problem as follows:
+*
+* +-----------------------+--------------------+
+* | Status of column s | Status of column q |
+* | (transformed problem) | (original problem) |
+* +-----------------------+--------------------+
+* | GLP_BS | GLP_BS |
+* | GLP_NL | GLP_NU |
+* | GLP_NU | GLP_NL |
+* +-----------------------+--------------------+
+*
+* Value of column q is computed with formula (2).
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q is computed with formula (2).
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is computed with formula (2). */
+
+static int rcv_ubnd_col(NPP *npp, void *info);
+
+void npp_ubnd_col(NPP *npp, NPPCOL *q)
+{ /* process column with upper bound */
+ struct bnd_col *info;
+ NPPROW *i;
+ NPPAIJ *aij;
+ /* the column must have upper bound */
+ xassert(q->ub != +DBL_MAX);
+ xassert(q->lb < q->ub);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_ubnd_col, sizeof(struct bnd_col));
+ info->q = q->j;
+ info->bnd = q->ub;
+ /* substitute x[q] into objective row */
+ npp->c0 += q->coef * q->ub;
+ q->coef = -q->coef;
+ /* substitute x[q] into constraint rows */
+ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { i = aij->row;
+ if (i->lb == i->ub)
+ i->ub = (i->lb -= aij->val * q->ub);
+ else
+ { if (i->lb != -DBL_MAX)
+ i->lb -= aij->val * q->ub;
+ if (i->ub != +DBL_MAX)
+ i->ub -= aij->val * q->ub;
+ }
+ aij->val = -aij->val;
+ }
+ /* column x[q] becomes column s */
+ if (q->lb != -DBL_MAX)
+ q->ub -= q->lb;
+ else
+ q->ub = +DBL_MAX;
+ q->lb = 0.0;
+ return;
+}
+
+static int rcv_ubnd_col(NPP *npp, void *_info)
+{ /* recover column with upper bound */
+ struct bnd_col *info = _info;
+ if (npp->sol == GLP_BS)
+ { if (npp->c_stat[info->q] == GLP_BS)
+ npp->c_stat[info->q] = GLP_BS;
+ else if (npp->c_stat[info->q] == GLP_NL)
+ npp->c_stat[info->q] = GLP_NU;
+ else if (npp->c_stat[info->q] == GLP_NU)
+ npp->c_stat[info->q] = GLP_NL;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ /* compute value of x[q] with formula (2) */
+ npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_dbnd_col - process non-negative column with upper bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_dbnd_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_dbnd_col processes column q, which is non-negative
+* and has upper bound:
+*
+* 0 <= x[q] <= u[q], (1)
+*
+* where u[q] > 0.
+*
+* PROBLEM TRANSFORMATION
+*
+* Upper bound of column q can be replaced by the following equality
+* constraint:
+*
+* x[q] + s = u[q], (2)
+*
+* where s >= 0 is a non-negative complement variable.
+*
+* Since in the primal system along with new row (2) there appears a
+* new column s having the only non-zero coefficient in this row, in
+* the dual system there appears a new row:
+*
+* (+1)pi + lambda[s] = 0, (3)
+*
+* where (+1) is coefficient at column s in row (2), pi is multiplier
+* for row (2), lambda[s] is multiplier for column s, 0 is coefficient
+* at column s in the objective row.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of column q in solution to the original problem is determined
+* by its status and status of column s in solution to the transformed
+* problem as follows:
+*
+* +-----------------------------------+------------------+
+* | Transformed problem | Original problem |
+* +-----------------+-----------------+------------------+
+* | Status of col q | Status of col s | Status of col q |
+* +-----------------+-----------------+------------------+
+* | GLP_BS | GLP_BS | GLP_BS |
+* | GLP_BS | GLP_NL | GLP_NU |
+* | GLP_NL | GLP_BS | GLP_NL |
+* | GLP_NL | GLP_NL | GLP_NL (*) |
+* +-----------------+-----------------+------------------+
+*
+* Value of column q in solution to the original problem is the same as
+* in solution to the transformed problem.
+*
+* 1. Formally, in solution to the transformed problem columns q and s
+* cannot be non-basic at the same time, since the constraint (2)
+* would be violated. However, if u[q] is close to zero, violation
+* may be less than a working precision even if both columns q and s
+* are non-basic. In this degenerate case row (2) can be only basic,
+* i.e. non-active constraint (otherwise corresponding row of the
+* basis matrix would be zero). This allows to pivot out auxiliary
+* variable and pivot in column s, in which case the row becomes
+* active while column s becomes basic.
+*
+* 2. If column q is integral, column s is also integral.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q in solution to the original problem is the same as
+* in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q in solution to the original problem is the same as
+* in solution to the transformed problem. */
+
+struct dbnd_col
+{ /* double-bounded column */
+ int q;
+ /* column reference number for variable x[q] */
+ int s;
+ /* column reference number for complement variable s */
+};
+
+static int rcv_dbnd_col(NPP *npp, void *info);
+
+void npp_dbnd_col(NPP *npp, NPPCOL *q)
+{ /* process non-negative column with upper bound */
+ struct dbnd_col *info;
+ NPPROW *p;
+ NPPCOL *s;
+ /* the column must be non-negative with upper bound */
+ xassert(q->lb == 0.0);
+ xassert(q->ub > 0.0);
+ xassert(q->ub != +DBL_MAX);
+ /* create variable s */
+ s = npp_add_col(npp);
+ s->is_int = q->is_int;
+ s->lb = 0.0, s->ub = +DBL_MAX;
+ /* create equality constraint (2) */
+ p = npp_add_row(npp);
+ p->lb = p->ub = q->ub;
+ npp_add_aij(npp, p, q, +1.0);
+ npp_add_aij(npp, p, s, +1.0);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_dbnd_col, sizeof(struct dbnd_col));
+ info->q = q->j;
+ info->s = s->j;
+ /* remove upper bound of x[q] */
+ q->ub = +DBL_MAX;
+ return;
+}
+
+static int rcv_dbnd_col(NPP *npp, void *_info)
+{ /* recover non-negative column with upper bound */
+ struct dbnd_col *info = _info;
+ if (npp->sol == GLP_BS)
+ { if (npp->c_stat[info->q] == GLP_BS)
+ { if (npp->c_stat[info->s] == GLP_BS)
+ npp->c_stat[info->q] = GLP_BS;
+ else if (npp->c_stat[info->s] == GLP_NL)
+ npp->c_stat[info->q] = GLP_NU;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else if (npp->c_stat[info->q] == GLP_NL)
+ { if (npp->c_stat[info->s] == GLP_BS ||
+ npp->c_stat[info->s] == GLP_NL)
+ npp->c_stat[info->q] = GLP_NL;
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_fixed_col - process fixed column
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_fixed_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_fixed_col processes column q, which is fixed:
+*
+* x[q] = s[q], (1)
+*
+* where s[q] is a fixed column value.
+*
+* PROBLEM TRANSFORMATION
+*
+* The value of a fixed column can be substituted into the objective
+* and constraint rows that allows removing the column from the problem.
+*
+* Substituting x[q] = s[q] into the objective row, we have:
+*
+* z = sum c[j] x[j] + c0 =
+* j
+*
+* = sum c[j] x[j] + c[q] x[q] + c0 =
+* j!=q
+*
+* = sum c[j] x[j] + c[q] s[q] + c0 =
+* j!=q
+*
+* = sum c[j] x[j] + c~0,
+* j!=q
+*
+* where
+*
+* c~0 = c0 + c[q] s[q] (2)
+*
+* is the constant term of the objective in the transformed problem.
+* Similarly, substituting x[q] = s[q] into constraint row i, we have:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i] ==>
+* j
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
+* j!=q
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==>
+* j!=q
+*
+* L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
+* j!=q
+*
+* where
+*
+* L~[i] = L[i] - a[i,q] s[q], U~[i] = U[i] - a[i,q] s[q] (3)
+*
+* are lower and upper bounds of row i in the transformed problem,
+* resp.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Column q is assigned status GLP_NS and its value is assigned s[q].
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q is assigned s[q].
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is assigned s[q]. */
+
+struct fixed_col
+{ /* fixed column */
+ int q;
+ /* column reference number for variable x[q] */
+ double s;
+ /* value, at which x[q] is fixed */
+};
+
+static int rcv_fixed_col(NPP *npp, void *info);
+
+void npp_fixed_col(NPP *npp, NPPCOL *q)
+{ /* process fixed column */
+ struct fixed_col *info;
+ NPPROW *i;
+ NPPAIJ *aij;
+ /* the column must be fixed */
+ xassert(q->lb == q->ub);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_fixed_col, sizeof(struct fixed_col));
+ info->q = q->j;
+ info->s = q->lb;
+ /* substitute x[q] = s[q] into objective row */
+ npp->c0 += q->coef * q->lb;
+ /* substitute x[q] = s[q] into constraint rows */
+ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { i = aij->row;
+ if (i->lb == i->ub)
+ i->ub = (i->lb -= aij->val * q->lb);
+ else
+ { if (i->lb != -DBL_MAX)
+ i->lb -= aij->val * q->lb;
+ if (i->ub != +DBL_MAX)
+ i->ub -= aij->val * q->lb;
+ }
+ }
+ /* remove the column from the problem */
+ npp_del_col(npp, q);
+ return;
+}
+
+static int rcv_fixed_col(NPP *npp, void *_info)
+{ /* recover fixed column */
+ struct fixed_col *info = _info;
+ if (npp->sol == GLP_SOL)
+ npp->c_stat[info->q] = GLP_NS;
+ npp->c_value[info->q] = info->s;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_make_equality - process row with almost identical bounds
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_make_equality(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_make_equality processes row p:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p], (1)
+* j
+*
+* where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
+* constraint.
+*
+* RETURNS
+*
+* 0 - row bounds have not been changed;
+*
+* 1 - row has been replaced by equality constraint.
+*
+* PROBLEM TRANSFORMATION
+*
+* If bounds of row (1) are very close to each other:
+*
+* U[p] - L[p] <= eps, (2)
+*
+* where eps is an absolute tolerance for row value, the row can be
+* replaced by the following almost equivalent equiality constraint:
+*
+* sum a[p,j] x[j] = b, (3)
+* j
+*
+* where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
+* to be very close to its nearest integer:
+*
+* |b - floor(b + 0.5)| <= eps, (4)
+*
+* it is reasonable to use this nearest integer as the right-hand side.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of row p in solution to the original problem is determined
+* by its status and the sign of its multiplier pi[p] in solution to
+* the transformed problem as follows:
+*
+* +-----------------------+---------+--------------------+
+* | Status of row p | Sign of | Status of row p |
+* | (transformed problem) | pi[p] | (original problem) |
+* +-----------------------+---------+--------------------+
+* | GLP_BS | + / - | GLP_BS |
+* | GLP_NS | + | GLP_NL |
+* | GLP_NS | - | GLP_NU |
+* +-----------------------+---------+--------------------+
+*
+* Value of row multiplier pi[p] in solution to the original problem is
+* the same as in solution to the transformed problem.
+*
+* RECOVERING INTERIOR POINT SOLUTION
+*
+* Value of row multiplier pi[p] in solution to the original problem is
+* the same as in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct make_equality
+{ /* row with almost identical bounds */
+ int p;
+ /* row reference number */
+};
+
+static int rcv_make_equality(NPP *npp, void *info);
+
+int npp_make_equality(NPP *npp, NPPROW *p)
+{ /* process row with almost identical bounds */
+ struct make_equality *info;
+ double b, eps, nint;
+ /* the row must be double-sided inequality */
+ xassert(p->lb != -DBL_MAX);
+ xassert(p->ub != +DBL_MAX);
+ xassert(p->lb < p->ub);
+ /* check row bounds */
+ eps = 1e-9 + 1e-12 * fabs(p->lb);
+ if (p->ub - p->lb > eps) return 0;
+ /* row bounds are very close to each other */
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_make_equality, sizeof(struct make_equality));
+ info->p = p->i;
+ /* compute right-hand side */
+ b = 0.5 * (p->ub + p->lb);
+ nint = floor(b + 0.5);
+ if (fabs(b - nint) <= eps) b = nint;
+ /* replace row p by almost equivalent equality constraint */
+ p->lb = p->ub = b;
+ return 1;
+}
+
+int rcv_make_equality(NPP *npp, void *_info)
+{ /* recover row with almost identical bounds */
+ struct make_equality *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] == GLP_BS)
+ npp->r_stat[info->p] = GLP_BS;
+ else if (npp->r_stat[info->p] == GLP_NS)
+ { if (npp->r_pi[info->p] >= 0.0)
+ npp->r_stat[info->p] = GLP_NL;
+ else
+ npp->r_stat[info->p] = GLP_NU;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_make_fixed - process column with almost identical bounds
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_make_fixed(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_make_fixed processes column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
+* bounds.
+*
+* RETURNS
+*
+* 0 - column bounds have not been changed;
+*
+* 1 - column has been fixed.
+*
+* PROBLEM TRANSFORMATION
+*
+* If bounds of column (1) are very close to each other:
+*
+* u[q] - l[q] <= eps, (2)
+*
+* where eps is an absolute tolerance for column value, the column can
+* be fixed:
+*
+* x[q] = s[q], (3)
+*
+* where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
+* happens to be very close to its nearest integer:
+*
+* |s[q] - floor(s[q] + 0.5)| <= eps, (4)
+*
+* it is reasonable to use this nearest integer as the fixed value.
+*
+* RECOVERING BASIC SOLUTION
+*
+* In the dual system of the original (as well as transformed) problem
+* column q corresponds to the following row:
+*
+* sum a[i,q] pi[i] + lambda[q] = c[q]. (5)
+* i
+*
+* Since multipliers pi[i] are known for all rows from solution to the
+* transformed problem, formula (5) allows computing value of multiplier
+* (reduced cost) for column q:
+*
+* lambda[q] = c[q] - sum a[i,q] pi[i]. (6)
+* i
+*
+* Status of column q in solution to the original problem is determined
+* by its status and the sign of its multiplier lambda[q] in solution to
+* the transformed problem as follows:
+*
+* +-----------------------+-----------+--------------------+
+* | Status of column q | Sign of | Status of column q |
+* | (transformed problem) | lambda[q] | (original problem) |
+* +-----------------------+-----------+--------------------+
+* | GLP_BS | + / - | GLP_BS |
+* | GLP_NS | + | GLP_NL |
+* | GLP_NS | - | GLP_NU |
+* +-----------------------+-----------+--------------------+
+*
+* Value of column q in solution to the original problem is the same as
+* in solution to the transformed problem.
+*
+* RECOVERING INTERIOR POINT SOLUTION
+*
+* Value of column q in solution to the original problem is the same as
+* in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct make_fixed
+{ /* column with almost identical bounds */
+ int q;
+ /* column reference number */
+ double c;
+ /* objective coefficient at x[q] */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[i,q] */
+};
+
+static int rcv_make_fixed(NPP *npp, void *info);
+
+int npp_make_fixed(NPP *npp, NPPCOL *q)
+{ /* process column with almost identical bounds */
+ struct make_fixed *info;
+ NPPAIJ *aij;
+ NPPLFE *lfe;
+ double s, eps, nint;
+ /* the column must be double-bounded */
+ xassert(q->lb != -DBL_MAX);
+ xassert(q->ub != +DBL_MAX);
+ xassert(q->lb < q->ub);
+ /* check column bounds */
+ eps = 1e-9 + 1e-12 * fabs(q->lb);
+ if (q->ub - q->lb > eps) return 0;
+ /* column bounds are very close to each other */
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_make_fixed, sizeof(struct make_fixed));
+ info->q = q->j;
+ info->c = q->coef;
+ info->ptr = NULL;
+ /* save column coefficients a[i,q] (needed for basic solution
+ only) */
+ if (npp->sol == GLP_SOL)
+ { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = aij->row->i;
+ lfe->val = aij->val;
+ lfe->next = info->ptr;
+ info->ptr = lfe;
+ }
+ }
+ /* compute column fixed value */
+ s = 0.5 * (q->ub + q->lb);
+ nint = floor(s + 0.5);
+ if (fabs(s - nint) <= eps) s = nint;
+ /* make column q fixed */
+ q->lb = q->ub = s;
+ return 1;
+}
+
+static int rcv_make_fixed(NPP *npp, void *_info)
+{ /* recover column with almost identical bounds */
+ struct make_fixed *info = _info;
+ NPPLFE *lfe;
+ double lambda;
+ if (npp->sol == GLP_SOL)
+ { if (npp->c_stat[info->q] == GLP_BS)
+ npp->c_stat[info->q] = GLP_BS;
+ else if (npp->c_stat[info->q] == GLP_NS)
+ { /* compute multiplier for column q with formula (6) */
+ lambda = info->c;
+ for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+ lambda -= lfe->val * npp->r_pi[lfe->ref];
+ /* assign status to non-basic column */
+ if (lambda >= 0.0)
+ npp->c_stat[info->q] = GLP_NL;
+ else
+ npp->c_stat[info->q] = GLP_NU;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp3.c b/test/monniaux/glpk-4.65/src/npp/npp3.c
new file mode 100644
index 00000000..883af127
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp3.c
@@ -0,0 +1,2861 @@
+/* npp3.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+/***********************************************************************
+* NAME
+*
+* npp_empty_row - process empty row
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_empty_row(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_empty_row processes row p, which is empty, i.e.
+* coefficients at all columns in this row are zero:
+*
+* L[p] <= sum 0 x[j] <= U[p], (1)
+*
+* where L[p] <= U[p].
+*
+* RETURNS
+*
+* 0 - success;
+*
+* 1 - problem has no primal feasible solution.
+*
+* PROBLEM TRANSFORMATION
+*
+* If the following conditions hold:
+*
+* L[p] <= +eps, U[p] >= -eps, (2)
+*
+* where eps is an absolute tolerance for row value, the row p is
+* redundant. In this case it can be replaced by equivalent redundant
+* row, which is free (unbounded), and then removed from the problem.
+* Otherwise, the row p is infeasible and, thus, the problem has no
+* primal feasible solution.
+*
+* RECOVERING BASIC SOLUTION
+*
+* See the routine npp_free_row.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* See the routine npp_free_row.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+int npp_empty_row(NPP *npp, NPPROW *p)
+{ /* process empty row */
+ double eps = 1e-3;
+ /* the row must be empty */
+ xassert(p->ptr == NULL);
+ /* check primal feasibility */
+ if (p->lb > +eps || p->ub < -eps)
+ return 1;
+ /* replace the row by equivalent free (unbounded) row */
+ p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+ /* and process it */
+ npp_free_row(npp, p);
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_empty_col - process empty column
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_empty_col(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_empty_col processes column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] <= u[q], which is empty, i.e. has zero coefficients in
+* all constraint rows.
+*
+* RETURNS
+*
+* 0 - success;
+*
+* 1 - problem has no dual feasible solution.
+*
+* PROBLEM TRANSFORMATION
+*
+* The row of the dual system corresponding to the empty column is the
+* following:
+*
+* sum 0 pi[i] + lambda[q] = c[q], (2)
+* i
+*
+* from which it follows that:
+*
+* lambda[q] = c[q]. (3)
+*
+* If the following condition holds:
+*
+* c[q] < - eps, (4)
+*
+* where eps is an absolute tolerance for column multiplier, the lower
+* column bound l[q] must be active to provide dual feasibility (note
+* that being preprocessed the problem is always minimization). In this
+* case the column can be fixed on its lower bound and removed from the
+* problem (if the column is integral, its bounds are also assumed to
+* be integral). And if the column has no lower bound (l[q] = -oo), the
+* problem has no dual feasible solution.
+*
+* If the following condition holds:
+*
+* c[q] > + eps, (5)
+*
+* the upper column bound u[q] must be active to provide dual
+* feasibility. In this case the column can be fixed on its upper bound
+* and removed from the problem. And if the column has no upper bound
+* (u[q] = +oo), the problem has no dual feasible solution.
+*
+* Finally, if the following condition holds:
+*
+* - eps <= c[q] <= +eps, (6)
+*
+* dual feasibility does not depend on a particular value of column q.
+* In this case the column can be fixed either on its lower bound (if
+* l[q] > -oo) or on its upper bound (if u[q] < +oo) or at zero (if the
+* column is unbounded) and then removed from the problem.
+*
+* RECOVERING BASIC SOLUTION
+*
+* See the routine npp_fixed_col. Having been recovered the column
+* is assigned status GLP_NS. However, if actually it is not fixed
+* (l[q] < u[q]), its status should be changed to GLP_NL, GLP_NU, or
+* GLP_NF depending on which bound it was fixed on transformation stage.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* See the routine npp_fixed_col.
+*
+* RECOVERING MIP SOLUTION
+*
+* See the routine npp_fixed_col. */
+
+struct empty_col
+{ /* empty column */
+ int q;
+ /* column reference number */
+ char stat;
+ /* status in basic solution */
+};
+
+static int rcv_empty_col(NPP *npp, void *info);
+
+int npp_empty_col(NPP *npp, NPPCOL *q)
+{ /* process empty column */
+ struct empty_col *info;
+ double eps = 1e-3;
+ /* the column must be empty */
+ xassert(q->ptr == NULL);
+ /* check dual feasibility */
+ if (q->coef > +eps && q->lb == -DBL_MAX)
+ return 1;
+ if (q->coef < -eps && q->ub == +DBL_MAX)
+ return 1;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_empty_col, sizeof(struct empty_col));
+ info->q = q->j;
+ /* fix the column */
+ if (q->lb == -DBL_MAX && q->ub == +DBL_MAX)
+ { /* free column */
+ info->stat = GLP_NF;
+ q->lb = q->ub = 0.0;
+ }
+ else if (q->ub == +DBL_MAX)
+lo: { /* column with lower bound */
+ info->stat = GLP_NL;
+ q->ub = q->lb;
+ }
+ else if (q->lb == -DBL_MAX)
+up: { /* column with upper bound */
+ info->stat = GLP_NU;
+ q->lb = q->ub;
+ }
+ else if (q->lb != q->ub)
+ { /* double-bounded column */
+ if (q->coef >= +DBL_EPSILON) goto lo;
+ if (q->coef <= -DBL_EPSILON) goto up;
+ if (fabs(q->lb) <= fabs(q->ub)) goto lo; else goto up;
+ }
+ else
+ { /* fixed column */
+ info->stat = GLP_NS;
+ }
+ /* process fixed column */
+ npp_fixed_col(npp, q);
+ return 0;
+}
+
+static int rcv_empty_col(NPP *npp, void *_info)
+{ /* recover empty column */
+ struct empty_col *info = _info;
+ if (npp->sol == GLP_SOL)
+ npp->c_stat[info->q] = info->stat;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_value - process implied column value
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_implied_value(NPP *npp, NPPCOL *q, double s);
+*
+* DESCRIPTION
+*
+* For column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] < u[q], the routine npp_implied_value processes its
+* implied value s[q]. If this implied value satisfies to the current
+* column bounds and integrality condition, the routine fixes column q
+* at the given point. Note that the column is kept in the problem in
+* any case.
+*
+* RETURNS
+*
+* 0 - column has been fixed;
+*
+* 1 - implied value violates to current column bounds;
+*
+* 2 - implied value violates integrality condition.
+*
+* ALGORITHM
+*
+* Implied column value s[q] satisfies to the current column bounds if
+* the following condition holds:
+*
+* l[q] - eps <= s[q] <= u[q] + eps, (2)
+*
+* where eps is an absolute tolerance for column value. If the column
+* is integral, the following condition also must hold:
+*
+* |s[q] - floor(s[q]+0.5)| <= eps, (3)
+*
+* where floor(s[q]+0.5) is the nearest integer to s[q].
+*
+* If both condition (2) and (3) are satisfied, the column can be fixed
+* at the value s[q], or, if it is integral, at floor(s[q]+0.5).
+* Otherwise, if s[q] violates (2) or (3), the problem has no feasible
+* solution.
+*
+* Note: If s[q] is close to l[q] or u[q], it seems to be reasonable to
+* fix the column at its lower or upper bound, resp. rather than at the
+* implied value. */
+
+int npp_implied_value(NPP *npp, NPPCOL *q, double s)
+{ /* process implied column value */
+ double eps, nint;
+ xassert(npp == npp);
+ /* column must not be fixed */
+ xassert(q->lb < q->ub);
+ /* check integrality */
+ if (q->is_int)
+ { nint = floor(s + 0.5);
+ if (fabs(s - nint) <= 1e-5)
+ s = nint;
+ else
+ return 2;
+ }
+ /* check current column lower bound */
+ if (q->lb != -DBL_MAX)
+ { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
+ if (s < q->lb - eps) return 1;
+ /* if s[q] is close to l[q], fix column at its lower bound
+ rather than at the implied value */
+ if (s < q->lb + 1e-3 * eps)
+ { q->ub = q->lb;
+ return 0;
+ }
+ }
+ /* check current column upper bound */
+ if (q->ub != +DBL_MAX)
+ { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
+ if (s > q->ub + eps) return 1;
+ /* if s[q] is close to u[q], fix column at its upper bound
+ rather than at the implied value */
+ if (s > q->ub - 1e-3 * eps)
+ { q->lb = q->ub;
+ return 0;
+ }
+ }
+ /* fix column at the implied value */
+ q->lb = q->ub = s;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_eq_singlet - process row singleton (equality constraint)
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_eq_singlet(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_eq_singlet processes row p, which is equiality
+* constraint having the only non-zero coefficient:
+*
+* a[p,q] x[q] = b. (1)
+*
+* RETURNS
+*
+* 0 - success;
+*
+* 1 - problem has no primal feasible solution;
+*
+* 2 - problem has no integer feasible solution.
+*
+* PROBLEM TRANSFORMATION
+*
+* The equality constraint defines implied value of column q:
+*
+* x[q] = s[q] = b / a[p,q]. (2)
+*
+* If the implied value s[q] satisfies to the column bounds (see the
+* routine npp_implied_value), the column can be fixed at s[q] and
+* removed from the problem. In this case row p becomes redundant, so
+* it can be replaced by equivalent free row and also removed from the
+* problem.
+*
+* Note that the routine removes from the problem only row p. Column q
+* becomes fixed, however, it is kept in the problem.
+*
+* RECOVERING BASIC SOLUTION
+*
+* In solution to the original problem row p is assigned status GLP_NS
+* (active equality constraint), and column q is assigned status GLP_BS
+* (basic column).
+*
+* Multiplier for row p can be computed as follows. In the dual system
+* of the original problem column q corresponds to the following row:
+*
+* sum a[i,q] pi[i] + lambda[q] = c[q] ==>
+* i
+*
+* sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q].
+* i!=p
+*
+* Therefore:
+*
+* 1
+* pi[p] = ------ (c[q] - lambda[q] - sum a[i,q] pi[i]), (3)
+* a[p,q] i!=q
+*
+* where lambda[q] = 0 (since column[q] is basic), and pi[i] for all
+* i != p are known in solution to the transformed problem.
+*
+* Value of column q in solution to the original problem is assigned
+* its implied value s[q].
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Multiplier for row p is computed with formula (3). Value of column
+* q is assigned its implied value s[q].
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is assigned its implied value s[q]. */
+
+struct eq_singlet
+{ /* row singleton (equality constraint) */
+ int p;
+ /* row reference number */
+ int q;
+ /* column reference number */
+ double apq;
+ /* constraint coefficient a[p,q] */
+ double c;
+ /* objective coefficient at x[q] */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_eq_singlet(NPP *npp, void *info);
+
+int npp_eq_singlet(NPP *npp, NPPROW *p)
+{ /* process row singleton (equality constraint) */
+ struct eq_singlet *info;
+ NPPCOL *q;
+ NPPAIJ *aij;
+ NPPLFE *lfe;
+ int ret;
+ double s;
+ /* the row must be singleton equality constraint */
+ xassert(p->lb == p->ub);
+ xassert(p->ptr != NULL && p->ptr->r_next == NULL);
+ /* compute and process implied column value */
+ aij = p->ptr;
+ q = aij->col;
+ s = p->lb / aij->val;
+ ret = npp_implied_value(npp, q, s);
+ xassert(0 <= ret && ret <= 2);
+ if (ret != 0) return ret;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_eq_singlet, sizeof(struct eq_singlet));
+ info->p = p->i;
+ info->q = q->j;
+ info->apq = aij->val;
+ info->c = q->coef;
+ info->ptr = NULL;
+ /* save column coefficients a[i,q], i != p (not needed for MIP
+ solution) */
+ if (npp->sol != GLP_MIP)
+ { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { if (aij->row == p) continue; /* skip a[p,q] */
+ lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = aij->row->i;
+ lfe->val = aij->val;
+ lfe->next = info->ptr;
+ info->ptr = lfe;
+ }
+ }
+ /* remove the row from the problem */
+ npp_del_row(npp, p);
+ return 0;
+}
+
+static int rcv_eq_singlet(NPP *npp, void *_info)
+{ /* recover row singleton (equality constraint) */
+ struct eq_singlet *info = _info;
+ NPPLFE *lfe;
+ double temp;
+ if (npp->sol == GLP_SOL)
+ { /* column q must be already recovered as GLP_NS */
+ if (npp->c_stat[info->q] != GLP_NS)
+ { npp_error();
+ return 1;
+ }
+ npp->r_stat[info->p] = GLP_NS;
+ npp->c_stat[info->q] = GLP_BS;
+ }
+ if (npp->sol != GLP_MIP)
+ { /* compute multiplier for row p with formula (3) */
+ temp = info->c;
+ for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+ temp -= lfe->val * npp->r_pi[lfe->ref];
+ npp->r_pi[info->p] = temp / info->apq;
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_lower - process implied column lower bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
+*
+* DESCRIPTION
+*
+* For column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] < u[q], the routine npp_implied_lower processes its
+* implied lower bound l'[q]. As the result the current column lower
+* bound may increase. Note that the column is kept in the problem in
+* any case.
+*
+* RETURNS
+*
+* 0 - current column lower bound has not changed;
+*
+* 1 - current column lower bound has changed, but not significantly;
+*
+* 2 - current column lower bound has significantly changed;
+*
+* 3 - column has been fixed on its upper bound;
+*
+* 4 - implied lower bound violates current column upper bound.
+*
+* ALGORITHM
+*
+* If column q is integral, before processing its implied lower bound
+* should be rounded up:
+*
+* ( floor(l'[q]+0.5), if |l'[q] - floor(l'[q]+0.5)| <= eps
+* l'[q] := < (2)
+* ( ceil(l'[q]), otherwise
+*
+* where floor(l'[q]+0.5) is the nearest integer to l'[q], ceil(l'[q])
+* is smallest integer not less than l'[q], and eps is an absolute
+* tolerance for column value.
+*
+* Processing implied column lower bound l'[q] includes the following
+* cases:
+*
+* 1) if l'[q] < l[q] + eps, implied lower bound is redundant;
+*
+* 2) if l[q] + eps <= l[q] <= u[q] + eps, current column lower bound
+* l[q] can be strengthened by replacing it with l'[q]. If in this
+* case new column lower bound becomes close to current column upper
+* bound u[q], the column can be fixed on its upper bound;
+*
+* 3) if l'[q] > u[q] + eps, implied lower bound violates current
+* column upper bound u[q], in which case the problem has no primal
+* feasible solution. */
+
+int npp_implied_lower(NPP *npp, NPPCOL *q, double l)
+{ /* process implied column lower bound */
+ int ret;
+ double eps, nint;
+ xassert(npp == npp);
+ /* column must not be fixed */
+ xassert(q->lb < q->ub);
+ /* implied lower bound must be finite */
+ xassert(l != -DBL_MAX);
+ /* if column is integral, round up l'[q] */
+ if (q->is_int)
+ { nint = floor(l + 0.5);
+ if (fabs(l - nint) <= 1e-5)
+ l = nint;
+ else
+ l = ceil(l);
+ }
+ /* check current column lower bound */
+ if (q->lb != -DBL_MAX)
+ { eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->lb));
+ if (l < q->lb + eps)
+ { ret = 0; /* redundant */
+ goto done;
+ }
+ }
+ /* check current column upper bound */
+ if (q->ub != +DBL_MAX)
+ { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
+ if (l > q->ub + eps)
+ { ret = 4; /* infeasible */
+ goto done;
+ }
+ /* if l'[q] is close to u[q], fix column at its upper bound */
+ if (l > q->ub - 1e-3 * eps)
+ { q->lb = q->ub;
+ ret = 3; /* fixed */
+ goto done;
+ }
+ }
+ /* check if column lower bound changes significantly */
+ if (q->lb == -DBL_MAX)
+ ret = 2; /* significantly */
+ else if (q->is_int && l > q->lb + 0.5)
+ ret = 2; /* significantly */
+ else if (l > q->lb + 0.30 * (1.0 + fabs(q->lb)))
+ ret = 2; /* significantly */
+ else
+ ret = 1; /* not significantly */
+ /* set new column lower bound */
+ q->lb = l;
+done: return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_upper - process implied column upper bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
+*
+* DESCRIPTION
+*
+* For column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] < u[q], the routine npp_implied_upper processes its
+* implied upper bound u'[q]. As the result the current column upper
+* bound may decrease. Note that the column is kept in the problem in
+* any case.
+*
+* RETURNS
+*
+* 0 - current column upper bound has not changed;
+*
+* 1 - current column upper bound has changed, but not significantly;
+*
+* 2 - current column upper bound has significantly changed;
+*
+* 3 - column has been fixed on its lower bound;
+*
+* 4 - implied upper bound violates current column lower bound.
+*
+* ALGORITHM
+*
+* If column q is integral, before processing its implied upper bound
+* should be rounded down:
+*
+* ( floor(u'[q]+0.5), if |u'[q] - floor(l'[q]+0.5)| <= eps
+* u'[q] := < (2)
+* ( floor(l'[q]), otherwise
+*
+* where floor(u'[q]+0.5) is the nearest integer to u'[q],
+* floor(u'[q]) is largest integer not greater than u'[q], and eps is
+* an absolute tolerance for column value.
+*
+* Processing implied column upper bound u'[q] includes the following
+* cases:
+*
+* 1) if u'[q] > u[q] - eps, implied upper bound is redundant;
+*
+* 2) if l[q] - eps <= u[q] <= u[q] - eps, current column upper bound
+* u[q] can be strengthened by replacing it with u'[q]. If in this
+* case new column upper bound becomes close to current column lower
+* bound, the column can be fixed on its lower bound;
+*
+* 3) if u'[q] < l[q] - eps, implied upper bound violates current
+* column lower bound l[q], in which case the problem has no primal
+* feasible solution. */
+
+int npp_implied_upper(NPP *npp, NPPCOL *q, double u)
+{ int ret;
+ double eps, nint;
+ xassert(npp == npp);
+ /* column must not be fixed */
+ xassert(q->lb < q->ub);
+ /* implied upper bound must be finite */
+ xassert(u != +DBL_MAX);
+ /* if column is integral, round down u'[q] */
+ if (q->is_int)
+ { nint = floor(u + 0.5);
+ if (fabs(u - nint) <= 1e-5)
+ u = nint;
+ else
+ u = floor(u);
+ }
+ /* check current column upper bound */
+ if (q->ub != +DBL_MAX)
+ { eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->ub));
+ if (u > q->ub - eps)
+ { ret = 0; /* redundant */
+ goto done;
+ }
+ }
+ /* check current column lower bound */
+ if (q->lb != -DBL_MAX)
+ { eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
+ if (u < q->lb - eps)
+ { ret = 4; /* infeasible */
+ goto done;
+ }
+ /* if u'[q] is close to l[q], fix column at its lower bound */
+ if (u < q->lb + 1e-3 * eps)
+ { q->ub = q->lb;
+ ret = 3; /* fixed */
+ goto done;
+ }
+ }
+ /* check if column upper bound changes significantly */
+ if (q->ub == +DBL_MAX)
+ ret = 2; /* significantly */
+ else if (q->is_int && u < q->ub - 0.5)
+ ret = 2; /* significantly */
+ else if (u < q->ub - 0.30 * (1.0 + fabs(q->ub)))
+ ret = 2; /* significantly */
+ else
+ ret = 1; /* not significantly */
+ /* set new column upper bound */
+ q->ub = u;
+done: return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_ineq_singlet - process row singleton (inequality constraint)
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_ineq_singlet(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_ineq_singlet processes row p, which is inequality
+* constraint having the only non-zero coefficient:
+*
+* L[p] <= a[p,q] * x[q] <= U[p], (1)
+*
+* where L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
+*
+* RETURNS
+*
+* 0 - current column bounds have not changed;
+*
+* 1 - current column bounds have changed, but not significantly;
+*
+* 2 - current column bounds have significantly changed;
+*
+* 3 - column has been fixed on its lower or upper bound;
+*
+* 4 - problem has no primal feasible solution.
+*
+* PROBLEM TRANSFORMATION
+*
+* Inequality constraint (1) defines implied bounds of column q:
+*
+* ( L[p] / a[p,q], if a[p,q] > 0
+* l'[q] = < (2)
+* ( U[p] / a[p,q], if a[p,q] < 0
+*
+* ( U[p] / a[p,q], if a[p,q] > 0
+* u'[q] = < (3)
+* ( L[p] / a[p,q], if a[p,q] < 0
+*
+* If these implied bounds do not violate current bounds of column q:
+*
+* l[q] <= x[q] <= u[q], (4)
+*
+* they can be used to strengthen the current column bounds:
+*
+* l[q] := max(l[q], l'[q]), (5)
+*
+* u[q] := min(u[q], u'[q]). (6)
+*
+* (See the routines npp_implied_lower and npp_implied_upper.)
+*
+* Once bounds of row p (1) have been carried over column q, the row
+* becomes redundant, so it can be replaced by equivalent free row and
+* removed from the problem.
+*
+* Note that the routine removes from the problem only row p. Column q,
+* even it has been fixed, is kept in the problem.
+*
+* RECOVERING BASIC SOLUTION
+*
+* Note that the row in the dual system corresponding to column q is
+* the following:
+*
+* sum a[i,q] pi[i] + lambda[q] = c[q] ==>
+* i
+* (7)
+* sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q],
+* i!=p
+*
+* where pi[i] for all i != p are known in solution to the transformed
+* problem. Row p does not exist in the transformed problem, so it has
+* zero multiplier there. This allows computing multiplier for column q
+* in solution to the transformed problem:
+*
+* lambda~[q] = c[q] - sum a[i,q] pi[i]. (8)
+* i!=p
+*
+* Let in solution to the transformed problem column q be non-basic
+* with lower bound active (GLP_NL, lambda~[q] >= 0), and this lower
+* bound be implied one l'[q]. From the original problem's standpoint
+* this then means that actually the original column lower bound l[q]
+* is inactive, and active is that row bound L[p] or U[p] that defines
+* the implied bound l'[q] (2). In this case in solution to the
+* original problem column q is assigned status GLP_BS while row p is
+* assigned status GLP_NL (if a[p,q] > 0) or GLP_NU (if a[p,q] < 0).
+* Since now column q is basic, its multiplier lambda[q] is zero. This
+* allows using (7) and (8) to find multiplier for row p in solution to
+* the original problem:
+*
+* 1
+* pi[p] = ------ (c[q] - sum a[i,q] pi[i]) = lambda~[q] / a[p,q] (9)
+* a[p,q] i!=p
+*
+* Now let in solution to the transformed problem column q be non-basic
+* with upper bound active (GLP_NU, lambda~[q] <= 0), and this upper
+* bound be implied one u'[q]. As in the previous case this then means
+* that from the original problem's standpoint actually the original
+* column upper bound u[q] is inactive, and active is that row bound
+* L[p] or U[p] that defines the implied bound u'[q] (3). In this case
+* in solution to the original problem column q is assigned status
+* GLP_BS, row p is assigned status GLP_NU (if a[p,q] > 0) or GLP_NL
+* (if a[p,q] < 0), and its multiplier is computed with formula (9).
+*
+* Strengthening bounds of column q according to (5) and (6) may make
+* it fixed. Thus, if in solution to the transformed problem column q is
+* non-basic and fixed (GLP_NS), we can suppose that if lambda~[q] > 0,
+* column q has active lower bound (GLP_NL), and if lambda~[q] < 0,
+* column q has active upper bound (GLP_NU), reducing this case to two
+* previous ones. If, however, lambda~[q] is close to zero or
+* corresponding bound of row p does not exist (this may happen if
+* lambda~[q] has wrong sign due to round-off errors, in which case it
+* is expected to be close to zero, since solution is assumed to be dual
+* feasible), column q can be assigned status GLP_BS (basic), and row p
+* can be made active on its existing bound. In the latter case row
+* multiplier pi[p] computed with formula (9) will be also close to
+* zero, and dual feasibility will be kept.
+*
+* In all other cases, namely, if in solution to the transformed
+* problem column q is basic (GLP_BS), or non-basic with original lower
+* bound l[q] active (GLP_NL), or non-basic with original upper bound
+* u[q] active (GLP_NU), constraint (1) is inactive. So in solution to
+* the original problem status of column q remains unchanged, row p is
+* assigned status GLP_BS, and its multiplier pi[p] is assigned zero
+* value.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* First, value of multiplier for column q in solution to the original
+* problem is computed with formula (8). If lambda~[q] > 0 and column q
+* has implied lower bound, or if lambda~[q] < 0 and column q has
+* implied upper bound, this means that from the original problem's
+* standpoint actually row p has corresponding active bound, in which
+* case its multiplier pi[p] is computed with formula (9). In other
+* cases, when the sign of lambda~[q] corresponds to original bound of
+* column q, or when lambda~[q] =~ 0, value of row multiplier pi[p] is
+* assigned zero value.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct ineq_singlet
+{ /* row singleton (inequality constraint) */
+ int p;
+ /* row reference number */
+ int q;
+ /* column reference number */
+ double apq;
+ /* constraint coefficient a[p,q] */
+ double c;
+ /* objective coefficient at x[q] */
+ double lb;
+ /* row lower bound */
+ double ub;
+ /* row upper bound */
+ char lb_changed;
+ /* this flag is set if column lower bound was changed */
+ char ub_changed;
+ /* this flag is set if column upper bound was changed */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_ineq_singlet(NPP *npp, void *info);
+
+int npp_ineq_singlet(NPP *npp, NPPROW *p)
+{ /* process row singleton (inequality constraint) */
+ struct ineq_singlet *info;
+ NPPCOL *q;
+ NPPAIJ *apq, *aij;
+ NPPLFE *lfe;
+ int lb_changed, ub_changed;
+ double ll, uu;
+ /* the row must be singleton inequality constraint */
+ xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
+ xassert(p->lb < p->ub);
+ xassert(p->ptr != NULL && p->ptr->r_next == NULL);
+ /* compute implied column bounds */
+ apq = p->ptr;
+ q = apq->col;
+ xassert(q->lb < q->ub);
+ if (apq->val > 0.0)
+ { ll = (p->lb == -DBL_MAX ? -DBL_MAX : p->lb / apq->val);
+ uu = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub / apq->val);
+ }
+ else
+ { ll = (p->ub == +DBL_MAX ? -DBL_MAX : p->ub / apq->val);
+ uu = (p->lb == -DBL_MAX ? +DBL_MAX : p->lb / apq->val);
+ }
+ /* process implied column lower bound */
+ if (ll == -DBL_MAX)
+ lb_changed = 0;
+ else
+ { lb_changed = npp_implied_lower(npp, q, ll);
+ xassert(0 <= lb_changed && lb_changed <= 4);
+ if (lb_changed == 4) return 4; /* infeasible */
+ }
+ /* process implied column upper bound */
+ if (uu == +DBL_MAX)
+ ub_changed = 0;
+ else if (lb_changed == 3)
+ { /* column was fixed on its upper bound due to l'[q] = u[q] */
+ /* note that L[p] < U[p], so l'[q] = u[q] < u'[q] */
+ ub_changed = 0;
+ }
+ else
+ { ub_changed = npp_implied_upper(npp, q, uu);
+ xassert(0 <= ub_changed && ub_changed <= 4);
+ if (ub_changed == 4) return 4; /* infeasible */
+ }
+ /* if neither lower nor upper column bound was changed, the row
+ is originally redundant and can be replaced by free row */
+ if (!lb_changed && !ub_changed)
+ { p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+ npp_free_row(npp, p);
+ return 0;
+ }
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_ineq_singlet, sizeof(struct ineq_singlet));
+ info->p = p->i;
+ info->q = q->j;
+ info->apq = apq->val;
+ info->c = q->coef;
+ info->lb = p->lb;
+ info->ub = p->ub;
+ info->lb_changed = (char)lb_changed;
+ info->ub_changed = (char)ub_changed;
+ info->ptr = NULL;
+ /* save column coefficients a[i,q], i != p (not needed for MIP
+ solution) */
+ if (npp->sol != GLP_MIP)
+ { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { if (aij == apq) continue; /* skip a[p,q] */
+ lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = aij->row->i;
+ lfe->val = aij->val;
+ lfe->next = info->ptr;
+ info->ptr = lfe;
+ }
+ }
+ /* remove the row from the problem */
+ npp_del_row(npp, p);
+ return lb_changed >= ub_changed ? lb_changed : ub_changed;
+}
+
+static int rcv_ineq_singlet(NPP *npp, void *_info)
+{ /* recover row singleton (inequality constraint) */
+ struct ineq_singlet *info = _info;
+ NPPLFE *lfe;
+ double lambda;
+ if (npp->sol == GLP_MIP) goto done;
+ /* compute lambda~[q] in solution to the transformed problem
+ with formula (8) */
+ lambda = info->c;
+ for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+ lambda -= lfe->val * npp->r_pi[lfe->ref];
+ if (npp->sol == GLP_SOL)
+ { /* recover basic solution */
+ if (npp->c_stat[info->q] == GLP_BS)
+ { /* column q is basic, so row p is inactive */
+ npp->r_stat[info->p] = GLP_BS;
+ npp->r_pi[info->p] = 0.0;
+ }
+ else if (npp->c_stat[info->q] == GLP_NL)
+nl: { /* column q is non-basic with lower bound active */
+ if (info->lb_changed)
+ { /* it is implied bound, so actually row p is active
+ while column q is basic */
+ npp->r_stat[info->p] =
+ (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
+ npp->c_stat[info->q] = GLP_BS;
+ npp->r_pi[info->p] = lambda / info->apq;
+ }
+ else
+ { /* it is original bound, so row p is inactive */
+ npp->r_stat[info->p] = GLP_BS;
+ npp->r_pi[info->p] = 0.0;
+ }
+ }
+ else if (npp->c_stat[info->q] == GLP_NU)
+nu: { /* column q is non-basic with upper bound active */
+ if (info->ub_changed)
+ { /* it is implied bound, so actually row p is active
+ while column q is basic */
+ npp->r_stat[info->p] =
+ (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
+ npp->c_stat[info->q] = GLP_BS;
+ npp->r_pi[info->p] = lambda / info->apq;
+ }
+ else
+ { /* it is original bound, so row p is inactive */
+ npp->r_stat[info->p] = GLP_BS;
+ npp->r_pi[info->p] = 0.0;
+ }
+ }
+ else if (npp->c_stat[info->q] == GLP_NS)
+ { /* column q is non-basic and fixed; note, however, that in
+ in the original problem it is non-fixed */
+ if (lambda > +1e-7)
+ { if (info->apq > 0.0 && info->lb != -DBL_MAX ||
+ info->apq < 0.0 && info->ub != +DBL_MAX ||
+ !info->lb_changed)
+ { /* either corresponding bound of row p exists or
+ column q remains non-basic with its original lower
+ bound active */
+ npp->c_stat[info->q] = GLP_NL;
+ goto nl;
+ }
+ }
+ if (lambda < -1e-7)
+ { if (info->apq > 0.0 && info->ub != +DBL_MAX ||
+ info->apq < 0.0 && info->lb != -DBL_MAX ||
+ !info->ub_changed)
+ { /* either corresponding bound of row p exists or
+ column q remains non-basic with its original upper
+ bound active */
+ npp->c_stat[info->q] = GLP_NU;
+ goto nu;
+ }
+ }
+ /* either lambda~[q] is close to zero, or corresponding
+ bound of row p does not exist, because lambda~[q] has
+ wrong sign due to round-off errors; in the latter case
+ lambda~[q] is also assumed to be close to zero; so, we
+ can make row p active on its existing bound and column q
+ basic; pi[p] will have wrong sign, but it also will be
+ close to zero (rarus casus of dual degeneracy) */
+ if (info->lb != -DBL_MAX && info->ub == +DBL_MAX)
+ { /* row lower bound exists, but upper bound doesn't */
+ npp->r_stat[info->p] = GLP_NL;
+ }
+ else if (info->lb == -DBL_MAX && info->ub != +DBL_MAX)
+ { /* row upper bound exists, but lower bound doesn't */
+ npp->r_stat[info->p] = GLP_NU;
+ }
+ else if (info->lb != -DBL_MAX && info->ub != +DBL_MAX)
+ { /* both row lower and upper bounds exist */
+ /* to choose proper active row bound we should not use
+ lambda~[q], because its value being close to zero is
+ unreliable; so we choose that bound which provides
+ primal feasibility for original constraint (1) */
+ if (info->apq * npp->c_value[info->q] <=
+ 0.5 * (info->lb + info->ub))
+ npp->r_stat[info->p] = GLP_NL;
+ else
+ npp->r_stat[info->p] = GLP_NU;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ npp->c_stat[info->q] = GLP_BS;
+ npp->r_pi[info->p] = lambda / info->apq;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ if (npp->sol == GLP_IPT)
+ { /* recover interior-point solution */
+ if (lambda > +DBL_EPSILON && info->lb_changed ||
+ lambda < -DBL_EPSILON && info->ub_changed)
+ { /* actually row p has corresponding active bound */
+ npp->r_pi[info->p] = lambda / info->apq;
+ }
+ else
+ { /* either bounds of column q are both inactive or its
+ original bound is active */
+ npp->r_pi[info->p] = 0.0;
+ }
+ }
+done: return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_slack - process column singleton (implied slack variable)
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_implied_slack(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_implied_slack processes column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] < u[q], having the only non-zero coefficient in row p,
+* which is equality constraint:
+*
+* sum a[p,j] x[j] + a[p,q] x[q] = b. (2)
+* j!=q
+*
+* PROBLEM TRANSFORMATION
+*
+* (If x[q] is integral, this transformation must not be used.)
+*
+* The term a[p,q] x[q] in constraint (2) can be considered as a slack
+* variable that allows to carry bounds of column q over row p and then
+* remove column q from the problem.
+*
+* Constraint (2) can be written as follows:
+*
+* sum a[p,j] x[j] = b - a[p,q] x[q]. (3)
+* j!=q
+*
+* According to (1) constraint (3) is equivalent to the following
+* inequality constraint:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p], (4)
+* j!=q
+*
+* where
+*
+* ( b - a[p,q] u[q], if a[p,q] > 0
+* L[p] = < (5)
+* ( b - a[p,q] l[q], if a[p,q] < 0
+*
+* ( b - a[p,q] l[q], if a[p,q] > 0
+* U[p] = < (6)
+* ( b - a[p,q] u[q], if a[p,q] < 0
+*
+* From (2) it follows that:
+*
+* 1
+* x[q] = ------ (b - sum a[p,j] x[j]). (7)
+* a[p,q] j!=q
+*
+* In order to eliminate x[q] from the objective row we substitute it
+* from (6) to that row:
+*
+* z = sum c[j] x[j] + c[q] x[q] + c[0] =
+* j!=q
+* 1
+* = sum c[j] x[j] + c[q] [------ (b - sum a[p,j] x[j])] + c0 =
+* j!=q a[p,q] j!=q
+*
+* = sum c~[j] x[j] + c~[0],
+* j!=q
+* a[p,j] b
+* c~[j] = c[j] - c[q] ------, c~0 = c0 - c[q] ------ (8)
+* a[p,q] a[p,q]
+*
+* are values of objective coefficients and constant term, resp., in
+* the transformed problem.
+*
+* Note that column q is column singleton, so in the dual system of the
+* original problem it corresponds to the following row singleton:
+*
+* a[p,q] pi[p] + lambda[q] = c[q]. (9)
+*
+* In the transformed problem row (9) would be the following:
+*
+* a[p,q] pi~[p] + lambda[q] = c~[q] = 0. (10)
+*
+* Subtracting (10) from (9) we have:
+*
+* a[p,q] (pi[p] - pi~[p]) = c[q]
+*
+* that gives the following formula to compute multiplier for row p in
+* solution to the original problem using its value in solution to the
+* transformed problem:
+*
+* pi[p] = pi~[p] + c[q] / a[p,q]. (11)
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of column q in solution to the original problem is defined
+* by status of row p in solution to the transformed problem and the
+* sign of coefficient a[p,q] in the original inequality constraint (2)
+* as follows:
+*
+* +-----------------------+---------+--------------------+
+* | Status of row p | Sign of | Status of column q |
+* | (transformed problem) | a[p,q] | (original problem) |
+* +-----------------------+---------+--------------------+
+* | GLP_BS | + / - | GLP_BS |
+* | GLP_NL | + | GLP_NU |
+* | GLP_NL | - | GLP_NL |
+* | GLP_NU | + | GLP_NL |
+* | GLP_NU | - | GLP_NU |
+* | GLP_NF | + / - | GLP_NF |
+* +-----------------------+---------+--------------------+
+*
+* Value of column q is computed with formula (7). Since originally row
+* p is equality constraint, its status is assigned GLP_NS, and value of
+* its multiplier pi[p] is computed with formula (11).
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of column q is computed with formula (7). Row multiplier value
+* pi[p] is computed with formula (11).
+*
+* RECOVERING MIP SOLUTION
+*
+* Value of column q is computed with formula (7). */
+
+struct implied_slack
+{ /* column singleton (implied slack variable) */
+ int p;
+ /* row reference number */
+ int q;
+ /* column reference number */
+ double apq;
+ /* constraint coefficient a[p,q] */
+ double b;
+ /* right-hand side of original equality constraint */
+ double c;
+ /* original objective coefficient at x[q] */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[p,j], j != q */
+};
+
+static int rcv_implied_slack(NPP *npp, void *info);
+
+void npp_implied_slack(NPP *npp, NPPCOL *q)
+{ /* process column singleton (implied slack variable) */
+ struct implied_slack *info;
+ NPPROW *p;
+ NPPAIJ *aij;
+ NPPLFE *lfe;
+ /* the column must be non-integral non-fixed singleton */
+ xassert(!q->is_int);
+ xassert(q->lb < q->ub);
+ xassert(q->ptr != NULL && q->ptr->c_next == NULL);
+ /* corresponding row must be equality constraint */
+ aij = q->ptr;
+ p = aij->row;
+ xassert(p->lb == p->ub);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_implied_slack, sizeof(struct implied_slack));
+ info->p = p->i;
+ info->q = q->j;
+ info->apq = aij->val;
+ info->b = p->lb;
+ info->c = q->coef;
+ info->ptr = NULL;
+ /* save row coefficients a[p,j], j != q, and substitute x[q]
+ into the objective row */
+ for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->col == q) continue; /* skip a[p,q] */
+ lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = aij->col->j;
+ lfe->val = aij->val;
+ lfe->next = info->ptr;
+ info->ptr = lfe;
+ aij->col->coef -= info->c * (aij->val / info->apq);
+ }
+ npp->c0 += info->c * (info->b / info->apq);
+ /* compute new row bounds */
+ if (info->apq > 0.0)
+ { p->lb = (q->ub == +DBL_MAX ?
+ -DBL_MAX : info->b - info->apq * q->ub);
+ p->ub = (q->lb == -DBL_MAX ?
+ +DBL_MAX : info->b - info->apq * q->lb);
+ }
+ else
+ { p->lb = (q->lb == -DBL_MAX ?
+ -DBL_MAX : info->b - info->apq * q->lb);
+ p->ub = (q->ub == +DBL_MAX ?
+ +DBL_MAX : info->b - info->apq * q->ub);
+ }
+ /* remove the column from the problem */
+ npp_del_col(npp, q);
+ return;
+}
+
+static int rcv_implied_slack(NPP *npp, void *_info)
+{ /* recover column singleton (implied slack variable) */
+ struct implied_slack *info = _info;
+ NPPLFE *lfe;
+ double temp;
+ if (npp->sol == GLP_SOL)
+ { /* assign statuses to row p and column q */
+ if (npp->r_stat[info->p] == GLP_BS ||
+ npp->r_stat[info->p] == GLP_NF)
+ npp->c_stat[info->q] = npp->r_stat[info->p];
+ else if (npp->r_stat[info->p] == GLP_NL)
+ npp->c_stat[info->q] =
+ (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
+ else if (npp->r_stat[info->p] == GLP_NU)
+ npp->c_stat[info->q] =
+ (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
+ else
+ { npp_error();
+ return 1;
+ }
+ npp->r_stat[info->p] = GLP_NS;
+ }
+ if (npp->sol != GLP_MIP)
+ { /* compute multiplier for row p */
+ npp->r_pi[info->p] += info->c / info->apq;
+ }
+ /* compute value of column q */
+ temp = info->b;
+ for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+ temp -= lfe->val * npp->c_value[lfe->ref];
+ npp->c_value[info->q] = temp / info->apq;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_free - process column singleton (implied free variable)
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_implied_free(NPP *npp, NPPCOL *q);
+*
+* DESCRIPTION
+*
+* The routine npp_implied_free processes column q:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* having non-zero coefficient in the only row p, which is inequality
+* constraint:
+*
+* L[p] <= sum a[p,j] x[j] + a[p,q] x[q] <= U[p], (2)
+* j!=q
+*
+* where l[q] < u[q], L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
+*
+* RETURNS
+*
+* 0 - success;
+*
+* 1 - column lower and/or upper bound(s) can be active;
+*
+* 2 - problem has no dual feasible solution.
+*
+* PROBLEM TRANSFORMATION
+*
+* Constraint (2) can be written as follows:
+*
+* L[p] - sum a[p,j] x[j] <= a[p,q] x[q] <= U[p] - sum a[p,j] x[j],
+* j!=q j!=q
+*
+* from which it follows that:
+*
+* alfa <= a[p,q] x[q] <= beta, (3)
+*
+* where
+*
+* alfa = inf(L[p] - sum a[p,j] x[j]) =
+* j!=q
+*
+* = L[p] - sup sum a[p,j] x[j] = (4)
+* j!=q
+*
+* = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j],
+* j in Jp j in Jn
+*
+* beta = sup(L[p] - sum a[p,j] x[j]) =
+* j!=q
+*
+* = L[p] - inf sum a[p,j] x[j] = (5)
+* j!=q
+*
+* = L[p] - sum a[p,j] l[j] - sum a[p,j] u[j],
+* j in Jp j in Jn
+*
+* Jp = {j != q: a[p,j] > 0}, Jn = {j != q: a[p,j] < 0}. (6)
+*
+* Inequality (3) defines implied bounds of variable x[q]:
+*
+* l'[q] <= x[q] <= u'[q], (7)
+*
+* where
+*
+* ( alfa / a[p,q], if a[p,q] > 0
+* l'[q] = < (8a)
+* ( beta / a[p,q], if a[p,q] < 0
+*
+* ( beta / a[p,q], if a[p,q] > 0
+* u'[q] = < (8b)
+* ( alfa / a[p,q], if a[p,q] < 0
+*
+* Thus, if l'[q] > l[q] - eps and u'[q] < u[q] + eps, where eps is
+* an absolute tolerance for column value, column bounds (1) cannot be
+* active, in which case column q can be replaced by equivalent free
+* (unbounded) column.
+*
+* Note that column q is column singleton, so in the dual system of the
+* original problem it corresponds to the following row singleton:
+*
+* a[p,q] pi[p] + lambda[q] = c[q], (9)
+*
+* from which it follows that:
+*
+* pi[p] = (c[q] - lambda[q]) / a[p,q]. (10)
+*
+* Let x[q] be implied free (unbounded) variable. Then column q can be
+* only basic, so its multiplier lambda[q] is equal to zero, and from
+* (10) we have:
+*
+* pi[p] = c[q] / a[p,q]. (11)
+*
+* There are possible three cases:
+*
+* 1) pi[p] < -eps, where eps is an absolute tolerance for row
+* multiplier. In this case, to provide dual feasibility of the
+* original problem, row p must be active on its lower bound, and
+* if its lower bound does not exist (L[p] = -oo), the problem has
+* no dual feasible solution;
+*
+* 2) pi[p] > +eps. In this case row p must be active on its upper
+* bound, and if its upper bound does not exist (U[p] = +oo), the
+* problem has no dual feasible solution;
+*
+* 3) -eps <= pi[p] <= +eps. In this case any (either lower or upper)
+* bound of row p can be active, because this does not affect dual
+* feasibility.
+*
+* Thus, in all three cases original inequality constraint (2) can be
+* replaced by equality constraint, where the right-hand side is either
+* lower or upper bound of row p, and bounds of column q can be removed
+* that makes it free (unbounded). (May note that this transformation
+* can be followed by transformation "Column singleton (implied slack
+* variable)" performed by the routine npp_implied_slack.)
+*
+* RECOVERING BASIC SOLUTION
+*
+* Status of row p in solution to the original problem is determined
+* by its status in solution to the transformed problem and its bound,
+* which was choosen to be active:
+*
+* +-----------------------+--------+--------------------+
+* | Status of row p | Active | Status of row p |
+* | (transformed problem) | bound | (original problem) |
+* +-----------------------+--------+--------------------+
+* | GLP_BS | L[p] | GLP_BS |
+* | GLP_BS | U[p] | GLP_BS |
+* | GLP_NS | L[p] | GLP_NL |
+* | GLP_NS | U[p] | GLP_NU |
+* +-----------------------+--------+--------------------+
+*
+* Value of row multiplier pi[p] (as well as value of column q) in
+* solution to the original problem is the same as in solution to the
+* transformed problem.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of row multiplier pi[p] in solution to the original problem is
+* the same as in solution to the transformed problem.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct implied_free
+{ /* column singleton (implied free variable) */
+ int p;
+ /* row reference number */
+ char stat;
+ /* row status:
+ GLP_NL - active constraint on lower bound
+ GLP_NU - active constraint on upper bound */
+};
+
+static int rcv_implied_free(NPP *npp, void *info);
+
+int npp_implied_free(NPP *npp, NPPCOL *q)
+{ /* process column singleton (implied free variable) */
+ struct implied_free *info;
+ NPPROW *p;
+ NPPAIJ *apq, *aij;
+ double alfa, beta, l, u, pi, eps;
+ /* the column must be non-fixed singleton */
+ xassert(q->lb < q->ub);
+ xassert(q->ptr != NULL && q->ptr->c_next == NULL);
+ /* corresponding row must be inequality constraint */
+ apq = q->ptr;
+ p = apq->row;
+ xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
+ xassert(p->lb < p->ub);
+ /* compute alfa */
+ alfa = p->lb;
+ if (alfa != -DBL_MAX)
+ { for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij == apq) continue; /* skip a[p,q] */
+ if (aij->val > 0.0)
+ { if (aij->col->ub == +DBL_MAX)
+ { alfa = -DBL_MAX;
+ break;
+ }
+ alfa -= aij->val * aij->col->ub;
+ }
+ else /* < 0.0 */
+ { if (aij->col->lb == -DBL_MAX)
+ { alfa = -DBL_MAX;
+ break;
+ }
+ alfa -= aij->val * aij->col->lb;
+ }
+ }
+ }
+ /* compute beta */
+ beta = p->ub;
+ if (beta != +DBL_MAX)
+ { for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij == apq) continue; /* skip a[p,q] */
+ if (aij->val > 0.0)
+ { if (aij->col->lb == -DBL_MAX)
+ { beta = +DBL_MAX;
+ break;
+ }
+ beta -= aij->val * aij->col->lb;
+ }
+ else /* < 0.0 */
+ { if (aij->col->ub == +DBL_MAX)
+ { beta = +DBL_MAX;
+ break;
+ }
+ beta -= aij->val * aij->col->ub;
+ }
+ }
+ }
+ /* compute implied column lower bound l'[q] */
+ if (apq->val > 0.0)
+ l = (alfa == -DBL_MAX ? -DBL_MAX : alfa / apq->val);
+ else /* < 0.0 */
+ l = (beta == +DBL_MAX ? -DBL_MAX : beta / apq->val);
+ /* compute implied column upper bound u'[q] */
+ if (apq->val > 0.0)
+ u = (beta == +DBL_MAX ? +DBL_MAX : beta / apq->val);
+ else
+ u = (alfa == -DBL_MAX ? +DBL_MAX : alfa / apq->val);
+ /* check if column lower bound l[q] can be active */
+ if (q->lb != -DBL_MAX)
+ { eps = 1e-9 + 1e-12 * fabs(q->lb);
+ if (l < q->lb - eps) return 1; /* yes, it can */
+ }
+ /* check if column upper bound u[q] can be active */
+ if (q->ub != +DBL_MAX)
+ { eps = 1e-9 + 1e-12 * fabs(q->ub);
+ if (u > q->ub + eps) return 1; /* yes, it can */
+ }
+ /* okay; make column q free (unbounded) */
+ q->lb = -DBL_MAX, q->ub = +DBL_MAX;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_implied_free, sizeof(struct implied_free));
+ info->p = p->i;
+ info->stat = -1;
+ /* compute row multiplier pi[p] */
+ pi = q->coef / apq->val;
+ /* check dual feasibility for row p */
+ if (pi > +DBL_EPSILON)
+ { /* lower bound L[p] must be active */
+ if (p->lb != -DBL_MAX)
+nl: { info->stat = GLP_NL;
+ p->ub = p->lb;
+ }
+ else
+ { if (pi > +1e-5) return 2; /* dual infeasibility */
+ /* take a chance on U[p] */
+ xassert(p->ub != +DBL_MAX);
+ goto nu;
+ }
+ }
+ else if (pi < -DBL_EPSILON)
+ { /* upper bound U[p] must be active */
+ if (p->ub != +DBL_MAX)
+nu: { info->stat = GLP_NU;
+ p->lb = p->ub;
+ }
+ else
+ { if (pi < -1e-5) return 2; /* dual infeasibility */
+ /* take a chance on L[p] */
+ xassert(p->lb != -DBL_MAX);
+ goto nl;
+ }
+ }
+ else
+ { /* any bound (either L[p] or U[p]) can be made active */
+ if (p->ub == +DBL_MAX)
+ { xassert(p->lb != -DBL_MAX);
+ goto nl;
+ }
+ if (p->lb == -DBL_MAX)
+ { xassert(p->ub != +DBL_MAX);
+ goto nu;
+ }
+ if (fabs(p->lb) <= fabs(p->ub)) goto nl; else goto nu;
+ }
+ return 0;
+}
+
+static int rcv_implied_free(NPP *npp, void *_info)
+{ /* recover column singleton (implied free variable) */
+ struct implied_free *info = _info;
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] == GLP_BS)
+ npp->r_stat[info->p] = GLP_BS;
+ else if (npp->r_stat[info->p] == GLP_NS)
+ { xassert(info->stat == GLP_NL || info->stat == GLP_NU);
+ npp->r_stat[info->p] = info->stat;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_eq_doublet - process row doubleton (equality constraint)
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_eq_doublet processes row p, which is equality
+* constraint having exactly two non-zero coefficients:
+*
+* a[p,q] x[q] + a[p,r] x[r] = b. (1)
+*
+* As the result of processing one of columns q or r is eliminated from
+* all other rows and, thus, becomes column singleton of type "implied
+* slack variable". Row p is not changed and along with column q and r
+* remains in the problem.
+*
+* RETURNS
+*
+* The routine npp_eq_doublet returns pointer to the descriptor of that
+* column q or r which has been eliminated. If, due to some reason, the
+* elimination was not performed, the routine returns NULL.
+*
+* PROBLEM TRANSFORMATION
+*
+* First, we decide which column q or r will be eliminated. Let it be
+* column q. Consider i-th constraint row, where column q has non-zero
+* coefficient a[i,q] != 0:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i]. (2)
+* j
+*
+* In order to eliminate column q from row (2) we subtract from it row
+* (1) multiplied by gamma[i] = a[i,q] / a[p,q], i.e. we replace in the
+* transformed problem row (2) by its linear combination with row (1).
+* This transformation changes only coefficients in columns q and r,
+* and bounds of row i as follows:
+*
+* a~[i,q] = a[i,q] - gamma[i] a[p,q] = 0, (3)
+*
+* a~[i,r] = a[i,r] - gamma[i] a[p,r], (4)
+*
+* L~[i] = L[i] - gamma[i] b, (5)
+*
+* U~[i] = U[i] - gamma[i] b. (6)
+*
+* RECOVERING BASIC SOLUTION
+*
+* The transformation of the primal system of the original problem:
+*
+* L <= A x <= U (7)
+*
+* is equivalent to multiplying from the left a transformation matrix F
+* by components of this primal system, which in the transformed problem
+* becomes the following:
+*
+* F L <= F A x <= F U ==> L~ <= A~x <= U~. (8)
+*
+* The matrix F has the following structure:
+*
+* ( 1 -gamma[1] )
+* ( )
+* ( 1 -gamma[2] )
+* ( )
+* ( ... ... )
+* ( )
+* F = ( 1 -gamma[p-1] ) (9)
+* ( )
+* ( 1 )
+* ( )
+* ( -gamma[p+1] 1 )
+* ( )
+* ( ... ... )
+*
+* where its column containing elements -gamma[i] corresponds to row p
+* of the primal system.
+*
+* From (8) it follows that the dual system of the original problem:
+*
+* A'pi + lambda = c, (10)
+*
+* in the transformed problem becomes the following:
+*
+* A'F'inv(F')pi + lambda = c ==> (A~)'pi~ + lambda = c, (11)
+*
+* where:
+*
+* pi~ = inv(F')pi (12)
+*
+* is the vector of row multipliers in the transformed problem. Thus:
+*
+* pi = F'pi~. (13)
+*
+* Therefore, as it follows from (13), value of multiplier for row p in
+* solution to the original problem can be computed as follows:
+*
+* pi[p] = pi~[p] - sum gamma[i] pi~[i], (14)
+* i
+*
+* where pi~[i] = pi[i] is multiplier for row i (i != p).
+*
+* Note that the statuses of all rows and columns are not changed.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Multiplier for row p in solution to the original problem is computed
+* with formula (14).
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct eq_doublet
+{ /* row doubleton (equality constraint) */
+ int p;
+ /* row reference number */
+ double apq;
+ /* constraint coefficient a[p,q] */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_eq_doublet(NPP *npp, void *info);
+
+NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p)
+{ /* process row doubleton (equality constraint) */
+ struct eq_doublet *info;
+ NPPROW *i;
+ NPPCOL *q, *r;
+ NPPAIJ *apq, *apr, *aiq, *air, *next;
+ NPPLFE *lfe;
+ double gamma;
+ /* the row must be doubleton equality constraint */
+ xassert(p->lb == p->ub);
+ xassert(p->ptr != NULL && p->ptr->r_next != NULL &&
+ p->ptr->r_next->r_next == NULL);
+ /* choose column to be eliminated */
+ { NPPAIJ *a1, *a2;
+ a1 = p->ptr, a2 = a1->r_next;
+ if (fabs(a2->val) < 0.001 * fabs(a1->val))
+ { /* only first column can be eliminated, because second one
+ has too small constraint coefficient */
+ apq = a1, apr = a2;
+ }
+ else if (fabs(a1->val) < 0.001 * fabs(a2->val))
+ { /* only second column can be eliminated, because first one
+ has too small constraint coefficient */
+ apq = a2, apr = a1;
+ }
+ else
+ { /* both columns are appropriate; choose that one which is
+ shorter to minimize fill-in */
+ if (npp_col_nnz(npp, a1->col) <= npp_col_nnz(npp, a2->col))
+ { /* first column is shorter */
+ apq = a1, apr = a2;
+ }
+ else
+ { /* second column is shorter */
+ apq = a2, apr = a1;
+ }
+ }
+ }
+ /* now columns q and r have been chosen */
+ q = apq->col, r = apr->col;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_eq_doublet, sizeof(struct eq_doublet));
+ info->p = p->i;
+ info->apq = apq->val;
+ info->ptr = NULL;
+ /* transform each row i (i != p), where a[i,q] != 0, to eliminate
+ column q */
+ for (aiq = q->ptr; aiq != NULL; aiq = next)
+ { next = aiq->c_next;
+ if (aiq == apq) continue; /* skip row p */
+ i = aiq->row; /* row i to be transformed */
+ /* save constraint coefficient a[i,q] */
+ if (npp->sol != GLP_MIP)
+ { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = i->i;
+ lfe->val = aiq->val;
+ lfe->next = info->ptr;
+ info->ptr = lfe;
+ }
+ /* find coefficient a[i,r] in row i */
+ for (air = i->ptr; air != NULL; air = air->r_next)
+ if (air->col == r) break;
+ /* if a[i,r] does not exist, create a[i,r] = 0 */
+ if (air == NULL)
+ air = npp_add_aij(npp, i, r, 0.0);
+ /* compute gamma[i] = a[i,q] / a[p,q] */
+ gamma = aiq->val / apq->val;
+ /* (row i) := (row i) - gamma[i] * (row p); see (3)-(6) */
+ /* new a[i,q] is exact zero due to elimnation; remove it from
+ row i */
+ npp_del_aij(npp, aiq);
+ /* compute new a[i,r] */
+ air->val -= gamma * apr->val;
+ /* if new a[i,r] is close to zero due to numeric cancelation,
+ remove it from row i */
+ if (fabs(air->val) <= 1e-10)
+ npp_del_aij(npp, air);
+ /* compute new lower and upper bounds of row i */
+ if (i->lb == i->ub)
+ i->lb = i->ub = (i->lb - gamma * p->lb);
+ else
+ { if (i->lb != -DBL_MAX)
+ i->lb -= gamma * p->lb;
+ if (i->ub != +DBL_MAX)
+ i->ub -= gamma * p->lb;
+ }
+ }
+ return q;
+}
+
+static int rcv_eq_doublet(NPP *npp, void *_info)
+{ /* recover row doubleton (equality constraint) */
+ struct eq_doublet *info = _info;
+ NPPLFE *lfe;
+ double gamma, temp;
+ /* we assume that processing row p is followed by processing
+ column q as singleton of type "implied slack variable", in
+ which case row p must always be active equality constraint */
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] != GLP_NS)
+ { npp_error();
+ return 1;
+ }
+ }
+ if (npp->sol != GLP_MIP)
+ { /* compute value of multiplier for row p; see (14) */
+ temp = npp->r_pi[info->p];
+ for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+ { gamma = lfe->val / info->apq; /* a[i,q] / a[p,q] */
+ temp -= gamma * npp->r_pi[lfe->ref];
+ }
+ npp->r_pi[info->p] = temp;
+ }
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_forcing_row - process forcing row
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_forcing_row(NPP *npp, NPPROW *p, int at);
+*
+* DESCRIPTION
+*
+* The routine npp_forcing row processes row p of general format:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p], (1)
+* j
+*
+* l[j] <= x[j] <= u[j], (2)
+*
+* where L[p] <= U[p] and l[j] < u[j] for all a[p,j] != 0. It is also
+* assumed that:
+*
+* 1) if at = 0 then |L[p] - U'[p]| <= eps, where U'[p] is implied
+* row upper bound (see below), eps is an absolute tolerance for row
+* value;
+*
+* 2) if at = 1 then |U[p] - L'[p]| <= eps, where L'[p] is implied
+* row lower bound (see below).
+*
+* RETURNS
+*
+* 0 - success;
+*
+* 1 - cannot fix columns due to too small constraint coefficients.
+*
+* PROBLEM TRANSFORMATION
+*
+* Implied lower and upper bounds of row (1) are determined by bounds
+* of corresponding columns (variables) as follows:
+*
+* L'[p] = inf sum a[p,j] x[j] =
+* j
+* (3)
+* = sum a[p,j] l[j] + sum a[p,j] u[j],
+* j in Jp j in Jn
+*
+* U'[p] = sup sum a[p,j] x[j] =
+* (4)
+* = sum a[p,j] u[j] + sum a[p,j] l[j],
+* j in Jp j in Jn
+*
+* Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
+*
+* If L[p] =~ U'[p] (at = 0), solution can be primal feasible only when
+* all variables take their boundary values as defined by (4):
+*
+* ( u[j], if j in Jp
+* x[j] = < (6)
+* ( l[j], if j in Jn
+*
+* Similarly, if U[p] =~ L'[p] (at = 1), solution can be primal feasible
+* only when all variables take their boundary values as defined by (3):
+*
+* ( l[j], if j in Jp
+* x[j] = < (7)
+* ( u[j], if j in Jn
+*
+* Condition (6) or (7) allows fixing all columns (variables x[j])
+* in row (1) on their bounds and then removing them from the problem
+* (see the routine npp_fixed_col). Due to this row p becomes redundant,
+* so it can be replaced by equivalent free (unbounded) row and also
+* removed from the problem (see the routine npp_free_row).
+*
+* 1. To apply this transformation row (1) should not have coefficients
+* whose magnitude is too small, i.e. all a[p,j] should satisfy to
+* the following condition:
+*
+* |a[p,j]| >= eps * max(1, |a[p,k]|), (8)
+* k
+* where eps is a relative tolerance for constraint coefficients.
+* Otherwise, fixing columns may be numerically unreliable and may
+* lead to wrong solution.
+*
+* 2. The routine fixes columns and remove bounds of row p, however,
+* it does not remove the row and columns from the problem.
+*
+* RECOVERING BASIC SOLUTION
+*
+* In the transformed problem row p being inactive constraint is
+* assigned status GLP_BS (as the result of transformation of free
+* row), and all columns in this row are assigned status GLP_NS (as the
+* result of transformation of fixed columns).
+*
+* Note that in the dual system of the transformed (as well as original)
+* problem every column j in row p corresponds to the following row:
+*
+* sum a[i,j] pi[i] + a[p,j] pi[p] + lambda[j] = c[j], (9)
+* i!=p
+*
+* from which it follows that:
+*
+* lambda[j] = c[j] - sum a[i,j] pi[i] - a[p,j] pi[p]. (10)
+* i!=p
+*
+* In the transformed problem values of all multipliers pi[i] are known
+* (including pi[i], whose value is zero, since row p is inactive).
+* Thus, using formula (10) it is possible to compute values of
+* multipliers lambda[j] for all columns in row p.
+*
+* Note also that in the original problem all columns in row p are
+* bounded, not fixed. So status GLP_NS assigned to every such column
+* must be changed to GLP_NL or GLP_NU depending on which bound the
+* corresponding column has been fixed. This status change may lead to
+* dual feasibility violation for solution of the original problem,
+* because now column multipliers must satisfy to the following
+* condition:
+*
+* ( >= 0, if status of column j is GLP_NL,
+* lambda[j] < (11)
+* ( <= 0, if status of column j is GLP_NU.
+*
+* If this condition holds, solution to the original problem is the
+* same as to the transformed problem. Otherwise, we have to perform
+* one degenerate pivoting step of the primal simplex method to obtain
+* dual feasible (hence, optimal) solution to the original problem as
+* follows. If, on problem transformation, row p was made active on its
+* lower bound (case at = 0), we change its status to GLP_NL (or GLP_NS)
+* and start increasing its multiplier pi[p]. Otherwise, if row p was
+* made active on its upper bound (case at = 1), we change its status
+* to GLP_NU (or GLP_NS) and start decreasing pi[p]. From (10) it
+* follows that:
+*
+* delta lambda[j] = - a[p,j] * delta pi[p] = - a[p,j] pi[p]. (12)
+*
+* Simple analysis of formulae (3)-(5) shows that changing pi[p] in the
+* specified direction causes increasing lambda[j] for every column j
+* assigned status GLP_NL (delta lambda[j] > 0) and decreasing lambda[j]
+* for every column j assigned status GLP_NU (delta lambda[j] < 0). It
+* is understood that once the last lambda[q], which violates condition
+* (11), has reached zero, multipliers lambda[j] for all columns get
+* valid signs. Such column q can be determined as follows. Let d[j] be
+* initial value of lambda[j] (i.e. reduced cost of column j) in the
+* transformed problem computed with formula (10) when pi[p] = 0. Then
+* lambda[j] = d[j] + delta lambda[j], and from (12) it follows that
+* lambda[j] becomes zero if:
+*
+* delta lambda[j] = - a[p,j] pi[p] = - d[j] ==>
+* (13)
+* pi[p] = d[j] / a[p,j].
+*
+* Therefore, the last column q, for which lambda[q] becomes zero, can
+* be determined from the following condition:
+*
+* |d[q] / a[p,q]| = max |pi[p]| = max |d[j] / a[p,j]|, (14)
+* j in D j in D
+*
+* where D is a set of columns j whose, reduced costs d[j] have invalid
+* signs, i.e. violate condition (11). (Thus, if D is empty, solution
+* to the original problem is the same as solution to the transformed
+* problem, and no correction is needed as was noticed above.) In
+* solution to the original problem column q is assigned status GLP_BS,
+* since it replaces column of auxiliary variable of row p (becoming
+* active) in the basis, and multiplier for row p is assigned its new
+* value, which is pi[p] = d[q] / a[p,q]. Note that due to primal
+* degeneracy values of all columns having non-zero coefficients in row
+* p remain unchanged.
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* Value of multiplier pi[p] in solution to the original problem is
+* corrected in the same way as for basic solution. Values of all
+* columns having non-zero coefficients in row p remain unchanged.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct forcing_col
+{ /* column fixed on its bound by forcing row */
+ int j;
+ /* column reference number */
+ char stat;
+ /* original column status:
+ GLP_NL - fixed on lower bound
+ GLP_NU - fixed on upper bound */
+ double a;
+ /* constraint coefficient a[p,j] */
+ double c;
+ /* objective coefficient c[j] */
+ NPPLFE *ptr;
+ /* list of non-zero coefficients a[i,j], i != p */
+ struct forcing_col *next;
+ /* pointer to another column fixed by forcing row */
+};
+
+struct forcing_row
+{ /* forcing row */
+ int p;
+ /* row reference number */
+ char stat;
+ /* status assigned to the row if it becomes active:
+ GLP_NS - active equality constraint
+ GLP_NL - inequality constraint with lower bound active
+ GLP_NU - inequality constraint with upper bound active */
+ struct forcing_col *ptr;
+ /* list of all columns having non-zero constraint coefficient
+ a[p,j] in the forcing row */
+};
+
+static int rcv_forcing_row(NPP *npp, void *info);
+
+int npp_forcing_row(NPP *npp, NPPROW *p, int at)
+{ /* process forcing row */
+ struct forcing_row *info;
+ struct forcing_col *col = NULL;
+ NPPCOL *j;
+ NPPAIJ *apj, *aij;
+ NPPLFE *lfe;
+ double big;
+ xassert(at == 0 || at == 1);
+ /* determine maximal magnitude of the row coefficients */
+ big = 1.0;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ if (big < fabs(apj->val)) big = fabs(apj->val);
+ /* if there are too small coefficients in the row, transformation
+ should not be applied */
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ if (fabs(apj->val) < 1e-7 * big) return 1;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_forcing_row, sizeof(struct forcing_row));
+ info->p = p->i;
+ if (p->lb == p->ub)
+ { /* equality constraint */
+ info->stat = GLP_NS;
+ }
+ else if (at == 0)
+ { /* inequality constraint; case L[p] = U'[p] */
+ info->stat = GLP_NL;
+ xassert(p->lb != -DBL_MAX);
+ }
+ else /* at == 1 */
+ { /* inequality constraint; case U[p] = L'[p] */
+ info->stat = GLP_NU;
+ xassert(p->ub != +DBL_MAX);
+ }
+ info->ptr = NULL;
+ /* scan the forcing row, fix columns at corresponding bounds, and
+ save column information (the latter is not needed for MIP) */
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { /* column j has non-zero coefficient in the forcing row */
+ j = apj->col;
+ /* it must be non-fixed */
+ xassert(j->lb < j->ub);
+ /* allocate stack entry to save column information */
+ if (npp->sol != GLP_MIP)
+ { col = dmp_get_atom(npp->stack, sizeof(struct forcing_col));
+ col->j = j->j;
+ col->stat = -1; /* will be set below */
+ col->a = apj->val;
+ col->c = j->coef;
+ col->ptr = NULL;
+ col->next = info->ptr;
+ info->ptr = col;
+ }
+ /* fix column j */
+ if (at == 0 && apj->val < 0.0 || at != 0 && apj->val > 0.0)
+ { /* at its lower bound */
+ if (npp->sol != GLP_MIP)
+ col->stat = GLP_NL;
+ xassert(j->lb != -DBL_MAX);
+ j->ub = j->lb;
+ }
+ else
+ { /* at its upper bound */
+ if (npp->sol != GLP_MIP)
+ col->stat = GLP_NU;
+ xassert(j->ub != +DBL_MAX);
+ j->lb = j->ub;
+ }
+ /* save column coefficients a[i,j], i != p */
+ if (npp->sol != GLP_MIP)
+ { for (aij = j->ptr; aij != NULL; aij = aij->c_next)
+ { if (aij == apj) continue; /* skip a[p,j] */
+ lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+ lfe->ref = aij->row->i;
+ lfe->val = aij->val;
+ lfe->next = col->ptr;
+ col->ptr = lfe;
+ }
+ }
+ }
+ /* make the row free (unbounded) */
+ p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+ return 0;
+}
+
+static int rcv_forcing_row(NPP *npp, void *_info)
+{ /* recover forcing row */
+ struct forcing_row *info = _info;
+ struct forcing_col *col, *piv;
+ NPPLFE *lfe;
+ double d, big, temp;
+ if (npp->sol == GLP_MIP) goto done;
+ /* initially solution to the original problem is the same as
+ to the transformed problem, where row p is inactive constraint
+ with pi[p] = 0, and all columns are non-basic */
+ if (npp->sol == GLP_SOL)
+ { if (npp->r_stat[info->p] != GLP_BS)
+ { npp_error();
+ return 1;
+ }
+ for (col = info->ptr; col != NULL; col = col->next)
+ { if (npp->c_stat[col->j] != GLP_NS)
+ { npp_error();
+ return 1;
+ }
+ npp->c_stat[col->j] = col->stat; /* original status */
+ }
+ }
+ /* compute reduced costs d[j] for all columns with formula (10)
+ and store them in col.c instead objective coefficients */
+ for (col = info->ptr; col != NULL; col = col->next)
+ { d = col->c;
+ for (lfe = col->ptr; lfe != NULL; lfe = lfe->next)
+ d -= lfe->val * npp->r_pi[lfe->ref];
+ col->c = d;
+ }
+ /* consider columns j, whose multipliers lambda[j] has wrong
+ sign in solution to the transformed problem (where lambda[j] =
+ d[j]), and choose column q, whose multipler lambda[q] reaches
+ zero last on changing row multiplier pi[p]; see (14) */
+ piv = NULL, big = 0.0;
+ for (col = info->ptr; col != NULL; col = col->next)
+ { d = col->c; /* d[j] */
+ temp = fabs(d / col->a);
+ if (col->stat == GLP_NL)
+ { /* column j has active lower bound */
+ if (d < 0.0 && big < temp)
+ piv = col, big = temp;
+ }
+ else if (col->stat == GLP_NU)
+ { /* column j has active upper bound */
+ if (d > 0.0 && big < temp)
+ piv = col, big = temp;
+ }
+ else
+ { npp_error();
+ return 1;
+ }
+ }
+ /* if column q does not exist, no correction is needed */
+ if (piv != NULL)
+ { /* correct solution; row p becomes active constraint while
+ column q becomes basic */
+ if (npp->sol == GLP_SOL)
+ { npp->r_stat[info->p] = info->stat;
+ npp->c_stat[piv->j] = GLP_BS;
+ }
+ /* assign new value to row multiplier pi[p] = d[p] / a[p,q] */
+ npp->r_pi[info->p] = piv->c / piv->a;
+ }
+done: return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_analyze_row - perform general row analysis
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_analyze_row(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_analyze_row performs analysis of row p of general
+* format:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p], (1)
+* j
+*
+* l[j] <= x[j] <= u[j], (2)
+*
+* where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0.
+*
+* RETURNS
+*
+* 0x?0 - row lower bound does not exist or is redundant;
+*
+* 0x?1 - row lower bound can be active;
+*
+* 0x?2 - row lower bound is a forcing bound;
+*
+* 0x0? - row upper bound does not exist or is redundant;
+*
+* 0x1? - row upper bound can be active;
+*
+* 0x2? - row upper bound is a forcing bound;
+*
+* 0x33 - row bounds are inconsistent with column bounds.
+*
+* ALGORITHM
+*
+* Analysis of row (1) is based on analysis of its implied lower and
+* upper bounds, which are determined by bounds of corresponding columns
+* (variables) as follows:
+*
+* L'[p] = inf sum a[p,j] x[j] =
+* j
+* (3)
+* = sum a[p,j] l[j] + sum a[p,j] u[j],
+* j in Jp j in Jn
+*
+* U'[p] = sup sum a[p,j] x[j] =
+* (4)
+* = sum a[p,j] u[j] + sum a[p,j] l[j],
+* j in Jp j in Jn
+*
+* Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
+*
+* (Note that bounds of all columns in row p are assumed to be correct,
+* so L'[p] <= U'[p].)
+*
+* Analysis of row lower bound L[p] includes the following cases:
+*
+* 1) if L[p] > U'[p] + eps, where eps is an absolute tolerance for row
+* value, row lower bound L[p] and implied row upper bound U'[p] are
+* inconsistent, ergo, the problem has no primal feasible solution;
+*
+* 2) if U'[p] - eps <= L[p] <= U'[p] + eps, i.e. if L[p] =~ U'[p],
+* the row is a forcing row on its lower bound (see description of
+* the routine npp_forcing_row);
+*
+* 3) if L[p] > L'[p] + eps, row lower bound L[p] can be active (this
+* conclusion does not account other rows in the problem);
+*
+* 4) if L[p] <= L'[p] + eps, row lower bound L[p] cannot be active, so
+* it is redundant and can be removed (replaced by -oo).
+*
+* Analysis of row upper bound U[p] is performed in a similar way and
+* includes the following cases:
+*
+* 1) if U[p] < L'[p] - eps, row upper bound U[p] and implied row lower
+* bound L'[p] are inconsistent, ergo the problem has no primal
+* feasible solution;
+*
+* 2) if L'[p] - eps <= U[p] <= L'[p] + eps, i.e. if U[p] =~ L'[p],
+* the row is a forcing row on its upper bound (see description of
+* the routine npp_forcing_row);
+*
+* 3) if U[p] < U'[p] - eps, row upper bound U[p] can be active (this
+* conclusion does not account other rows in the problem);
+*
+* 4) if U[p] >= U'[p] - eps, row upper bound U[p] cannot be active, so
+* it is redundant and can be removed (replaced by +oo). */
+
+int npp_analyze_row(NPP *npp, NPPROW *p)
+{ /* perform general row analysis */
+ NPPAIJ *aij;
+ int ret = 0x00;
+ double l, u, eps;
+ xassert(npp == npp);
+ /* compute implied lower bound L'[p]; see (3) */
+ l = 0.0;
+ for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->val > 0.0)
+ { if (aij->col->lb == -DBL_MAX)
+ { l = -DBL_MAX;
+ break;
+ }
+ l += aij->val * aij->col->lb;
+ }
+ else /* aij->val < 0.0 */
+ { if (aij->col->ub == +DBL_MAX)
+ { l = -DBL_MAX;
+ break;
+ }
+ l += aij->val * aij->col->ub;
+ }
+ }
+ /* compute implied upper bound U'[p]; see (4) */
+ u = 0.0;
+ for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->val > 0.0)
+ { if (aij->col->ub == +DBL_MAX)
+ { u = +DBL_MAX;
+ break;
+ }
+ u += aij->val * aij->col->ub;
+ }
+ else /* aij->val < 0.0 */
+ { if (aij->col->lb == -DBL_MAX)
+ { u = +DBL_MAX;
+ break;
+ }
+ u += aij->val * aij->col->lb;
+ }
+ }
+ /* column bounds are assumed correct, so L'[p] <= U'[p] */
+ /* check if row lower bound is consistent */
+ if (p->lb != -DBL_MAX)
+ { eps = 1e-3 + 1e-6 * fabs(p->lb);
+ if (p->lb - eps > u)
+ { ret = 0x33;
+ goto done;
+ }
+ }
+ /* check if row upper bound is consistent */
+ if (p->ub != +DBL_MAX)
+ { eps = 1e-3 + 1e-6 * fabs(p->ub);
+ if (p->ub + eps < l)
+ { ret = 0x33;
+ goto done;
+ }
+ }
+ /* check if row lower bound can be active/forcing */
+ if (p->lb != -DBL_MAX)
+ { eps = 1e-9 + 1e-12 * fabs(p->lb);
+ if (p->lb - eps > l)
+ { if (p->lb + eps <= u)
+ ret |= 0x01;
+ else
+ ret |= 0x02;
+ }
+ }
+ /* check if row upper bound can be active/forcing */
+ if (p->ub != +DBL_MAX)
+ { eps = 1e-9 + 1e-12 * fabs(p->ub);
+ if (p->ub + eps < u)
+ { /* check if the upper bound is forcing */
+ if (p->ub - eps >= l)
+ ret |= 0x10;
+ else
+ ret |= 0x20;
+ }
+ }
+done: return ret;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_inactive_bound - remove row lower/upper inactive bound
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
+*
+* DESCRIPTION
+*
+* The routine npp_inactive_bound removes lower (if which = 0) or upper
+* (if which = 1) bound of row p:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p],
+*
+* which (bound) is assumed to be redundant.
+*
+* PROBLEM TRANSFORMATION
+*
+* If which = 0, current lower bound L[p] of row p is assigned -oo.
+* If which = 1, current upper bound U[p] of row p is assigned +oo.
+*
+* RECOVERING BASIC SOLUTION
+*
+* If in solution to the transformed problem row p is inactive
+* constraint (GLP_BS), its status is not changed in solution to the
+* original problem. Otherwise, status of row p in solution to the
+* original problem is defined by its type before transformation and
+* its status in solution to the transformed problem as follows:
+*
+* +---------------------+-------+---------------+---------------+
+* | Row | Flag | Row status in | Row status in |
+* | type | which | transfmd soln | original soln |
+* +---------------------+-------+---------------+---------------+
+* | sum >= L[p] | 0 | GLP_NF | GLP_NL |
+* | sum <= U[p] | 1 | GLP_NF | GLP_NU |
+* | L[p] <= sum <= U[p] | 0 | GLP_NU | GLP_NU |
+* | L[p] <= sum <= U[p] | 1 | GLP_NL | GLP_NL |
+* | sum = L[p] = U[p] | 0 | GLP_NU | GLP_NS |
+* | sum = L[p] = U[p] | 1 | GLP_NL | GLP_NS |
+* +---------------------+-------+---------------+---------------+
+*
+* RECOVERING INTERIOR-POINT SOLUTION
+*
+* None needed.
+*
+* RECOVERING MIP SOLUTION
+*
+* None needed. */
+
+struct inactive_bound
+{ /* row inactive bound */
+ int p;
+ /* row reference number */
+ char stat;
+ /* row status (if active constraint) */
+};
+
+static int rcv_inactive_bound(NPP *npp, void *info);
+
+void npp_inactive_bound(NPP *npp, NPPROW *p, int which)
+{ /* remove row lower/upper inactive bound */
+ struct inactive_bound *info;
+ if (npp->sol == GLP_SOL)
+ { /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_inactive_bound, sizeof(struct inactive_bound));
+ info->p = p->i;
+ if (p->ub == +DBL_MAX)
+ info->stat = GLP_NL;
+ else if (p->lb == -DBL_MAX)
+ info->stat = GLP_NU;
+ else if (p->lb != p->ub)
+ info->stat = (char)(which == 0 ? GLP_NU : GLP_NL);
+ else
+ info->stat = GLP_NS;
+ }
+ /* remove row inactive bound */
+ if (which == 0)
+ { xassert(p->lb != -DBL_MAX);
+ p->lb = -DBL_MAX;
+ }
+ else if (which == 1)
+ { xassert(p->ub != +DBL_MAX);
+ p->ub = +DBL_MAX;
+ }
+ else
+ xassert(which != which);
+ return;
+}
+
+static int rcv_inactive_bound(NPP *npp, void *_info)
+{ /* recover row status */
+ struct inactive_bound *info = _info;
+ if (npp->sol != GLP_SOL)
+ { npp_error();
+ return 1;
+ }
+ if (npp->r_stat[info->p] == GLP_BS)
+ npp->r_stat[info->p] = GLP_BS;
+ else
+ npp->r_stat[info->p] = info->stat;
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_bounds - determine implied column bounds
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_implied_bounds(NPP *npp, NPPROW *p);
+*
+* DESCRIPTION
+*
+* The routine npp_implied_bounds inspects general row (constraint) p:
+*
+* L[p] <= sum a[p,j] x[j] <= U[p], (1)
+*
+* l[j] <= x[j] <= u[j], (2)
+*
+* where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0, to compute
+* implied bounds of columns (variables x[j]) in this row.
+*
+* The routine stores implied column bounds l'[j] and u'[j] in column
+* descriptors (NPPCOL); it does not change current column bounds l[j]
+* and u[j]. (Implied column bounds can be then used to strengthen the
+* current column bounds; see the routines npp_implied_lower and
+* npp_implied_upper).
+*
+* ALGORITHM
+*
+* Current column bounds (2) define implied lower and upper bounds of
+* row (1) as follows:
+*
+* L'[p] = inf sum a[p,j] x[j] =
+* j
+* (3)
+* = sum a[p,j] l[j] + sum a[p,j] u[j],
+* j in Jp j in Jn
+*
+* U'[p] = sup sum a[p,j] x[j] =
+* (4)
+* = sum a[p,j] u[j] + sum a[p,j] l[j],
+* j in Jp j in Jn
+*
+* Jp = {j: a[p,j] > 0}, Jn = {j: a[p,j] < 0}. (5)
+*
+* (Note that bounds of all columns in row p are assumed to be correct,
+* so L'[p] <= U'[p].)
+*
+* If L[p] > L'[p] and/or U[p] < U'[p], the lower and/or upper bound of
+* row (1) can be active, in which case such row defines implied bounds
+* of its variables.
+*
+* Let x[k] be some variable having in row (1) coefficient a[p,k] != 0.
+* Consider a case when row lower bound can be active (L[p] > L'[p]):
+*
+* sum a[p,j] x[j] >= L[p] ==>
+* j
+*
+* sum a[p,j] x[j] + a[p,k] x[k] >= L[p] ==>
+* j!=k
+* (6)
+* a[p,k] x[k] >= L[p] - sum a[p,j] x[j] ==>
+* j!=k
+*
+* a[p,k] x[k] >= L[p,k],
+*
+* where
+*
+* L[p,k] = inf(L[p] - sum a[p,j] x[j]) =
+* j!=k
+*
+* = L[p] - sup sum a[p,j] x[j] = (7)
+* j!=k
+*
+* = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j].
+* j in Jp\{k} j in Jn\{k}
+*
+* Thus:
+*
+* x[k] >= l'[k] = L[p,k] / a[p,k], if a[p,k] > 0, (8)
+*
+* x[k] <= u'[k] = L[p,k] / a[p,k], if a[p,k] < 0. (9)
+*
+* where l'[k] and u'[k] are implied lower and upper bounds of variable
+* x[k], resp.
+*
+* Now consider a similar case when row upper bound can be active
+* (U[p] < U'[p]):
+*
+* sum a[p,j] x[j] <= U[p] ==>
+* j
+*
+* sum a[p,j] x[j] + a[p,k] x[k] <= U[p] ==>
+* j!=k
+* (10)
+* a[p,k] x[k] <= U[p] - sum a[p,j] x[j] ==>
+* j!=k
+*
+* a[p,k] x[k] <= U[p,k],
+*
+* where:
+*
+* U[p,k] = sup(U[p] - sum a[p,j] x[j]) =
+* j!=k
+*
+* = U[p] - inf sum a[p,j] x[j] = (11)
+* j!=k
+*
+* = U[p] - sum a[p,j] l[j] - sum a[p,j] u[j].
+* j in Jp\{k} j in Jn\{k}
+*
+* Thus:
+*
+* x[k] <= u'[k] = U[p,k] / a[p,k], if a[p,k] > 0, (12)
+*
+* x[k] >= l'[k] = U[p,k] / a[p,k], if a[p,k] < 0. (13)
+*
+* Note that in formulae (8), (9), (12), and (13) coefficient a[p,k]
+* must not be too small in magnitude relatively to other non-zero
+* coefficients in row (1), i.e. the following condition must hold:
+*
+* |a[p,k]| >= eps * max(1, |a[p,j]|), (14)
+* j
+*
+* where eps is a relative tolerance for constraint coefficients.
+* Otherwise the implied column bounds can be numerical inreliable. For
+* example, using formula (8) for the following inequality constraint:
+*
+* 1e-12 x1 - x2 - x3 >= 0,
+*
+* where x1 >= -1, x2, x3, >= 0, may lead to numerically unreliable
+* conclusion that x1 >= 0.
+*
+* Using formulae (8), (9), (12), and (13) to compute implied bounds
+* for one variable requires |J| operations, where J = {j: a[p,j] != 0},
+* because this needs computing L[p,k] and U[p,k]. Thus, computing
+* implied bounds for all variables in row (1) would require |J|^2
+* operations, that is not a good technique. However, the total number
+* of operations can be reduced to |J| as follows.
+*
+* Let a[p,k] > 0. Then from (7) and (11) we have:
+*
+* L[p,k] = L[p] - (U'[p] - a[p,k] u[k]) =
+*
+* = L[p] - U'[p] + a[p,k] u[k],
+*
+* U[p,k] = U[p] - (L'[p] - a[p,k] l[k]) =
+*
+* = U[p] - L'[p] + a[p,k] l[k],
+*
+* where L'[p] and U'[p] are implied row lower and upper bounds defined
+* by formulae (3) and (4). Substituting these expressions into (8) and
+* (12) gives:
+*
+* l'[k] = L[p,k] / a[p,k] = u[k] + (L[p] - U'[p]) / a[p,k], (15)
+*
+* u'[k] = U[p,k] / a[p,k] = l[k] + (U[p] - L'[p]) / a[p,k]. (16)
+*
+* Similarly, if a[p,k] < 0, according to (7) and (11) we have:
+*
+* L[p,k] = L[p] - (U'[p] - a[p,k] l[k]) =
+*
+* = L[p] - U'[p] + a[p,k] l[k],
+*
+* U[p,k] = U[p] - (L'[p] - a[p,k] u[k]) =
+*
+* = U[p] - L'[p] + a[p,k] u[k],
+*
+* and substituting these expressions into (8) and (12) gives:
+*
+* l'[k] = U[p,k] / a[p,k] = u[k] + (U[p] - L'[p]) / a[p,k], (17)
+*
+* u'[k] = L[p,k] / a[p,k] = l[k] + (L[p] - U'[p]) / a[p,k]. (18)
+*
+* Note that formulae (15)-(18) can be used only if L'[p] and U'[p]
+* exist. However, if for some variable x[j] it happens that l[j] = -oo
+* and/or u[j] = +oo, values of L'[p] (if a[p,j] > 0) and/or U'[p] (if
+* a[p,j] < 0) are undefined. Consider, therefore, the most general
+* situation, when some column bounds (2) may not exist.
+*
+* Let:
+*
+* J' = {j : (a[p,j] > 0 and l[j] = -oo) or
+* (19)
+* (a[p,j] < 0 and u[j] = +oo)}.
+*
+* Then (assuming that row upper bound U[p] can be active) the following
+* three cases are possible:
+*
+* 1) |J'| = 0. In this case L'[p] exists, thus, for all variables x[j]
+* in row (1) we can use formulae (16) and (17);
+*
+* 2) J' = {k}. In this case L'[p] = -oo, however, U[p,k] (11) exists,
+* so for variable x[k] we can use formulae (12) and (13). Note that
+* for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] < 0)
+* or u'[j] = +oo (if a[p,j] > 0);
+*
+* 3) |J'| > 1. In this case for all variables x[j] in row [1] we have
+* l'[j] = -oo (if a[p,j] < 0) or u'[j] = +oo (if a[p,j] > 0).
+*
+* Similarly, let:
+*
+* J'' = {j : (a[p,j] > 0 and u[j] = +oo) or
+* (20)
+* (a[p,j] < 0 and l[j] = -oo)}.
+*
+* Then (assuming that row lower bound L[p] can be active) the following
+* three cases are possible:
+*
+* 1) |J''| = 0. In this case U'[p] exists, thus, for all variables x[j]
+* in row (1) we can use formulae (15) and (18);
+*
+* 2) J'' = {k}. In this case U'[p] = +oo, however, L[p,k] (7) exists,
+* so for variable x[k] we can use formulae (8) and (9). Note that
+* for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] > 0)
+* or u'[j] = +oo (if a[p,j] < 0);
+*
+* 3) |J''| > 1. In this case for all variables x[j] in row (1) we have
+* l'[j] = -oo (if a[p,j] > 0) or u'[j] = +oo (if a[p,j] < 0). */
+
+void npp_implied_bounds(NPP *npp, NPPROW *p)
+{ NPPAIJ *apj, *apk;
+ double big, eps, temp;
+ xassert(npp == npp);
+ /* initialize implied bounds for all variables and determine
+ maximal magnitude of row coefficients a[p,j] */
+ big = 1.0;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { apj->col->ll.ll = -DBL_MAX, apj->col->uu.uu = +DBL_MAX;
+ if (big < fabs(apj->val)) big = fabs(apj->val);
+ }
+ eps = 1e-6 * big;
+ /* process row lower bound (assuming that it can be active) */
+ if (p->lb != -DBL_MAX)
+ { apk = NULL;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj->val > 0.0 && apj->col->ub == +DBL_MAX ||
+ apj->val < 0.0 && apj->col->lb == -DBL_MAX)
+ { if (apk == NULL)
+ apk = apj;
+ else
+ goto skip1;
+ }
+ }
+ /* if a[p,k] = NULL then |J'| = 0 else J' = { k } */
+ temp = p->lb;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj == apk)
+ /* skip a[p,k] */;
+ else if (apj->val > 0.0)
+ temp -= apj->val * apj->col->ub;
+ else /* apj->val < 0.0 */
+ temp -= apj->val * apj->col->lb;
+ }
+ /* compute column implied bounds */
+ if (apk == NULL)
+ { /* temp = L[p] - U'[p] */
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj->val >= +eps)
+ { /* l'[j] := u[j] + (L[p] - U'[p]) / a[p,j] */
+ apj->col->ll.ll = apj->col->ub + temp / apj->val;
+ }
+ else if (apj->val <= -eps)
+ { /* u'[j] := l[j] + (L[p] - U'[p]) / a[p,j] */
+ apj->col->uu.uu = apj->col->lb + temp / apj->val;
+ }
+ }
+ }
+ else
+ { /* temp = L[p,k] */
+ if (apk->val >= +eps)
+ { /* l'[k] := L[p,k] / a[p,k] */
+ apk->col->ll.ll = temp / apk->val;
+ }
+ else if (apk->val <= -eps)
+ { /* u'[k] := L[p,k] / a[p,k] */
+ apk->col->uu.uu = temp / apk->val;
+ }
+ }
+skip1: ;
+ }
+ /* process row upper bound (assuming that it can be active) */
+ if (p->ub != +DBL_MAX)
+ { apk = NULL;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj->val > 0.0 && apj->col->lb == -DBL_MAX ||
+ apj->val < 0.0 && apj->col->ub == +DBL_MAX)
+ { if (apk == NULL)
+ apk = apj;
+ else
+ goto skip2;
+ }
+ }
+ /* if a[p,k] = NULL then |J''| = 0 else J'' = { k } */
+ temp = p->ub;
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj == apk)
+ /* skip a[p,k] */;
+ else if (apj->val > 0.0)
+ temp -= apj->val * apj->col->lb;
+ else /* apj->val < 0.0 */
+ temp -= apj->val * apj->col->ub;
+ }
+ /* compute column implied bounds */
+ if (apk == NULL)
+ { /* temp = U[p] - L'[p] */
+ for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+ { if (apj->val >= +eps)
+ { /* u'[j] := l[j] + (U[p] - L'[p]) / a[p,j] */
+ apj->col->uu.uu = apj->col->lb + temp / apj->val;
+ }
+ else if (apj->val <= -eps)
+ { /* l'[j] := u[j] + (U[p] - L'[p]) / a[p,j] */
+ apj->col->ll.ll = apj->col->ub + temp / apj->val;
+ }
+ }
+ }
+ else
+ { /* temp = U[p,k] */
+ if (apk->val >= +eps)
+ { /* u'[k] := U[p,k] / a[p,k] */
+ apk->col->uu.uu = temp / apk->val;
+ }
+ else if (apk->val <= -eps)
+ { /* l'[k] := U[p,k] / a[p,k] */
+ apk->col->ll.ll = temp / apk->val;
+ }
+ }
+skip2: ;
+ }
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp4.c b/test/monniaux/glpk-4.65/src/npp/npp4.c
new file mode 100644
index 00000000..d7dd0e86
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp4.c
@@ -0,0 +1,1414 @@
+/* npp4.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+/***********************************************************************
+* NAME
+*
+* npp_binarize_prob - binarize MIP problem
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_binarize_prob(NPP *npp);
+*
+* DESCRIPTION
+*
+* The routine npp_binarize_prob replaces in the original MIP problem
+* every integer variable:
+*
+* l[q] <= x[q] <= u[q], (1)
+*
+* where l[q] < u[q], by an equivalent sum of binary variables.
+*
+* RETURNS
+*
+* The routine returns the number of integer variables for which the
+* transformation failed, because u[q] - l[q] > d_max.
+*
+* PROBLEM TRANSFORMATION
+*
+* If variable x[q] has non-zero lower bound, it is first processed
+* with the routine npp_lbnd_col. Thus, we can assume that:
+*
+* 0 <= x[q] <= u[q]. (2)
+*
+* If u[q] = 1, variable x[q] is already binary, so further processing
+* is not needed. Let, therefore, that 2 <= u[q] <= d_max, and n be a
+* smallest integer such that u[q] <= 2^n - 1 (n >= 2, since u[q] >= 2).
+* Then variable x[q] can be replaced by the following sum:
+*
+* n-1
+* x[q] = sum 2^k x[k], (3)
+* k=0
+*
+* where x[k] are binary columns (variables). If u[q] < 2^n - 1, the
+* following additional inequality constraint must be also included in
+* the transformed problem:
+*
+* n-1
+* sum 2^k x[k] <= u[q]. (4)
+* k=0
+*
+* Note: Assuming that in the transformed problem x[q] becomes binary
+* variable x[0], this transformation causes new n-1 binary variables
+* to appear.
+*
+* Substituting x[q] from (3) to the objective row gives:
+*
+* z = sum c[j] x[j] + c[0] =
+* j
+*
+* = sum c[j] x[j] + c[q] x[q] + c[0] =
+* j!=q
+* n-1
+* = sum c[j] x[j] + c[q] sum 2^k x[k] + c[0] =
+* j!=q k=0
+* n-1
+* = sum c[j] x[j] + sum c[k] x[k] + c[0],
+* j!=q k=0
+*
+* where:
+*
+* c[k] = 2^k c[q], k = 0, ..., n-1. (5)
+*
+* And substituting x[q] from (3) to i-th constraint row i gives:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i] ==>
+* j
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
+* j!=q
+* n-1
+* L[i] <= sum a[i,j] x[j] + a[i,q] sum 2^k x[k] <= U[i] ==>
+* j!=q k=0
+* n-1
+* L[i] <= sum a[i,j] x[j] + sum a[i,k] x[k] <= U[i],
+* j!=q k=0
+*
+* where:
+*
+* a[i,k] = 2^k a[i,q], k = 0, ..., n-1. (6)
+*
+* RECOVERING SOLUTION
+*
+* Value of variable x[q] is computed with formula (3). */
+
+struct binarize
+{ int q;
+ /* column reference number for x[q] = x[0] */
+ int j;
+ /* column reference number for x[1]; x[2] has reference number
+ j+1, x[3] - j+2, etc. */
+ int n;
+ /* total number of binary variables, n >= 2 */
+};
+
+static int rcv_binarize_prob(NPP *npp, void *info);
+
+int npp_binarize_prob(NPP *npp)
+{ /* binarize MIP problem */
+ struct binarize *info;
+ NPPROW *row;
+ NPPCOL *col, *bin;
+ NPPAIJ *aij;
+ int u, n, k, temp, nfails, nvars, nbins, nrows;
+ /* new variables will be added to the end of the column list, so
+ we go from the end to beginning of the column list */
+ nfails = nvars = nbins = nrows = 0;
+ for (col = npp->c_tail; col != NULL; col = col->prev)
+ { /* skip continuous variable */
+ if (!col->is_int) continue;
+ /* skip fixed variable */
+ if (col->lb == col->ub) continue;
+ /* skip binary variable */
+ if (col->lb == 0.0 && col->ub == 1.0) continue;
+ /* check if the transformation is applicable */
+ if (col->lb < -1e6 || col->ub > +1e6 ||
+ col->ub - col->lb > 4095.0)
+ { /* unfortunately, not */
+ nfails++;
+ continue;
+ }
+ /* process integer non-binary variable x[q] */
+ nvars++;
+ /* make x[q] non-negative, if its lower bound is non-zero */
+ if (col->lb != 0.0)
+ npp_lbnd_col(npp, col);
+ /* now 0 <= x[q] <= u[q] */
+ xassert(col->lb == 0.0);
+ u = (int)col->ub;
+ xassert(col->ub == (double)u);
+ /* if x[q] is binary, further processing is not needed */
+ if (u == 1) continue;
+ /* determine smallest n such that u <= 2^n - 1 (thus, n is the
+ number of binary variables needed) */
+ n = 2, temp = 4;
+ while (u >= temp)
+ n++, temp += temp;
+ nbins += n;
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_binarize_prob, sizeof(struct binarize));
+ info->q = col->j;
+ info->j = 0; /* will be set below */
+ info->n = n;
+ /* if u < 2^n - 1, we need one additional row for (4) */
+ if (u < temp - 1)
+ { row = npp_add_row(npp), nrows++;
+ row->lb = -DBL_MAX, row->ub = u;
+ }
+ else
+ row = NULL;
+ /* in the transformed problem variable x[q] becomes binary
+ variable x[0], so its objective and constraint coefficients
+ are not changed */
+ col->ub = 1.0;
+ /* include x[0] into constraint (4) */
+ if (row != NULL)
+ npp_add_aij(npp, row, col, 1.0);
+ /* add other binary variables x[1], ..., x[n-1] */
+ for (k = 1, temp = 2; k < n; k++, temp += temp)
+ { /* add new binary variable x[k] */
+ bin = npp_add_col(npp);
+ bin->is_int = 1;
+ bin->lb = 0.0, bin->ub = 1.0;
+ bin->coef = (double)temp * col->coef;
+ /* store column reference number for x[1] */
+ if (info->j == 0)
+ info->j = bin->j;
+ else
+ xassert(info->j + (k-1) == bin->j);
+ /* duplicate constraint coefficients for x[k]; this also
+ automatically includes x[k] into constraint (4) */
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ npp_add_aij(npp, aij->row, bin, (double)temp * aij->val);
+ }
+ }
+ if (nvars > 0)
+ xprintf("%d integer variable(s) were replaced by %d binary one"
+ "s\n", nvars, nbins);
+ if (nrows > 0)
+ xprintf("%d row(s) were added due to binarization\n", nrows);
+ if (nfails > 0)
+ xprintf("Binarization failed for %d integer variable(s)\n",
+ nfails);
+ return nfails;
+}
+
+static int rcv_binarize_prob(NPP *npp, void *_info)
+{ /* recovery binarized variable */
+ struct binarize *info = _info;
+ int k, temp;
+ double sum;
+ /* compute value of x[q]; see formula (3) */
+ sum = npp->c_value[info->q];
+ for (k = 1, temp = 2; k < info->n; k++, temp += temp)
+ sum += (double)temp * npp->c_value[info->j + (k-1)];
+ npp->c_value[info->q] = sum;
+ return 0;
+}
+
+/**********************************************************************/
+
+struct elem
+{ /* linear form element a[j] x[j] */
+ double aj;
+ /* non-zero coefficient value */
+ NPPCOL *xj;
+ /* pointer to variable (column) */
+ struct elem *next;
+ /* pointer to another term */
+};
+
+static struct elem *copy_form(NPP *npp, NPPROW *row, double s)
+{ /* copy linear form */
+ NPPAIJ *aij;
+ struct elem *ptr, *e;
+ ptr = NULL;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { e = dmp_get_atom(npp->pool, sizeof(struct elem));
+ e->aj = s * aij->val;
+ e->xj = aij->col;
+ e->next = ptr;
+ ptr = e;
+ }
+ return ptr;
+}
+
+static void drop_form(NPP *npp, struct elem *ptr)
+{ /* drop linear form */
+ struct elem *e;
+ while (ptr != NULL)
+ { e = ptr;
+ ptr = e->next;
+ dmp_free_atom(npp->pool, e, sizeof(struct elem));
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_is_packing - test if constraint is packing inequality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_is_packing(NPP *npp, NPPROW *row);
+*
+* RETURNS
+*
+* If the specified row (constraint) is packing inequality (see below),
+* the routine npp_is_packing returns non-zero. Otherwise, it returns
+* zero.
+*
+* PACKING INEQUALITIES
+*
+* In canonical format the packing inequality is the following:
+*
+* sum x[j] <= 1, (1)
+* j in J
+*
+* where all variables x[j] are binary. This inequality expresses the
+* condition that in any integer feasible solution at most one variable
+* from set J can take non-zero (unity) value while other variables
+* must be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because
+* if J is empty or |J| = 1, the inequality (1) is redundant.
+*
+* In general case the packing inequality may include original variables
+* x[j] as well as their complements x~[j]:
+*
+* sum x[j] + sum x~[j] <= 1, (2)
+* j in Jp j in Jn
+*
+* where Jp and Jn are not intersected. Therefore, using substitution
+* x~[j] = 1 - x[j] gives the packing inequality in generalized format:
+*
+* sum x[j] - sum x[j] <= 1 - |Jn|. (3)
+* j in Jp j in Jn */
+
+int npp_is_packing(NPP *npp, NPPROW *row)
+{ /* test if constraint is packing inequality */
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int b;
+ xassert(npp == npp);
+ if (!(row->lb == -DBL_MAX && row->ub != +DBL_MAX))
+ return 0;
+ b = 1;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ return 0;
+ if (aij->val == +1.0)
+ ;
+ else if (aij->val == -1.0)
+ b--;
+ else
+ return 0;
+ }
+ if (row->ub != (double)b) return 0;
+ return 1;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_hidden_packing - identify hidden packing inequality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_hidden_packing(NPP *npp, NPPROW *row);
+*
+* DESCRIPTION
+*
+* The routine npp_hidden_packing processes specified inequality
+* constraint, which includes only binary variables, and the number of
+* the variables is not less than two. If the original inequality is
+* equivalent to a packing inequality, the routine replaces it by this
+* equivalent inequality. If the original constraint is double-sided
+* inequality, it is replaced by a pair of single-sided inequalities,
+* if necessary.
+*
+* RETURNS
+*
+* If the original inequality constraint was replaced by equivalent
+* packing inequality, the routine npp_hidden_packing returns non-zero.
+* Otherwise, it returns zero.
+*
+* PROBLEM TRANSFORMATION
+*
+* Consider an inequality constraint:
+*
+* sum a[j] x[j] <= b, (1)
+* j in J
+*
+* where all variables x[j] are binary, and |J| >= 2. (In case of '>='
+* inequality it can be transformed to '<=' format by multiplying both
+* its sides by -1.)
+*
+* Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
+* x[j] = 1 - x~[j] for all j in Jn, we have:
+*
+* sum a[j] x[j] <= b ==>
+* j in J
+*
+* sum a[j] x[j] + sum a[j] x[j] <= b ==>
+* j in Jp j in Jn
+*
+* sum a[j] x[j] + sum a[j] (1 - x~[j]) <= b ==>
+* j in Jp j in Jn
+*
+* sum a[j] x[j] - sum a[j] x~[j] <= b - sum a[j].
+* j in Jp j in Jn j in Jn
+*
+* Thus, meaning the transformation above, we can assume that in
+* inequality (1) all coefficients a[j] are positive. Moreover, we can
+* assume that a[j] <= b. In fact, let a[j] > b; then the following
+* three cases are possible:
+*
+* 1) b < 0. In this case inequality (1) is infeasible, so the problem
+* has no feasible solution (see the routine npp_analyze_row);
+*
+* 2) b = 0. In this case inequality (1) is a forcing inequality on its
+* upper bound (see the routine npp_forcing row), from which it
+* follows that all variables x[j] should be fixed at zero;
+*
+* 3) b > 0. In this case inequality (1) defines an implied zero upper
+* bound for variable x[j] (see the routine npp_implied_bounds), from
+* which it follows that x[j] should be fixed at zero.
+*
+* It is assumed that all three cases listed above have been recognized
+* by the routine npp_process_prob, which performs basic MIP processing
+* prior to a call the routine npp_hidden_packing. So, if one of these
+* cases occurs, we should just skip processing such constraint.
+*
+* Thus, let 0 < a[j] <= b. Then it is obvious that constraint (1) is
+* equivalent to packing inquality only if:
+*
+* a[j] + a[k] > b + eps (2)
+*
+* for all j, k in J, j != k, where eps is an absolute tolerance for
+* row (linear form) value. Checking the condition (2) for all j and k,
+* j != k, requires time O(|J|^2). However, this time can be reduced to
+* O(|J|), if use minimal a[j] and a[k], in which case it is sufficient
+* to check the condition (2) only once.
+*
+* Once the original inequality (1) is replaced by equivalent packing
+* inequality, we need to perform back substitution x~[j] = 1 - x[j] for
+* all j in Jn (see above).
+*
+* RECOVERING SOLUTION
+*
+* None needed. */
+
+static int hidden_packing(NPP *npp, struct elem *ptr, double *_b)
+{ /* process inequality constraint: sum a[j] x[j] <= b;
+ 0 - specified row is NOT hidden packing inequality;
+ 1 - specified row is packing inequality;
+ 2 - specified row is hidden packing inequality. */
+ struct elem *e, *ej, *ek;
+ int neg;
+ double b = *_b, eps;
+ xassert(npp == npp);
+ /* a[j] must be non-zero, x[j] must be binary, for all j in J */
+ for (e = ptr; e != NULL; e = e->next)
+ { xassert(e->aj != 0.0);
+ xassert(e->xj->is_int);
+ xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
+ }
+ /* check if the specified inequality constraint already has the
+ form of packing inequality */
+ neg = 0; /* neg is |Jn| */
+ for (e = ptr; e != NULL; e = e->next)
+ { if (e->aj == +1.0)
+ ;
+ else if (e->aj == -1.0)
+ neg++;
+ else
+ break;
+ }
+ if (e == NULL)
+ { /* all coefficients a[j] are +1 or -1; check rhs b */
+ if (b == (double)(1 - neg))
+ { /* it is packing inequality; no processing is needed */
+ return 1;
+ }
+ }
+ /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
+ positive; the result is a~[j] = |a[j]| and new rhs b */
+ for (e = ptr; e != NULL; e = e->next)
+ if (e->aj < 0) b -= e->aj;
+ /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
+ /* if a[j] > b, skip processing--this case must not appear */
+ for (e = ptr; e != NULL; e = e->next)
+ if (fabs(e->aj) > b) return 0;
+ /* now 0 < a[j] <= b for all j in J */
+ /* find two minimal coefficients a[j] and a[k], j != k */
+ ej = NULL;
+ for (e = ptr; e != NULL; e = e->next)
+ if (ej == NULL || fabs(ej->aj) > fabs(e->aj)) ej = e;
+ xassert(ej != NULL);
+ ek = NULL;
+ for (e = ptr; e != NULL; e = e->next)
+ if (e != ej)
+ if (ek == NULL || fabs(ek->aj) > fabs(e->aj)) ek = e;
+ xassert(ek != NULL);
+ /* the specified constraint is equivalent to packing inequality
+ iff a[j] + a[k] > b + eps */
+ eps = 1e-3 + 1e-6 * fabs(b);
+ if (fabs(ej->aj) + fabs(ek->aj) <= b + eps) return 0;
+ /* perform back substitution x~[j] = 1 - x[j] and construct the
+ final equivalent packing inequality in generalized format */
+ b = 1.0;
+ for (e = ptr; e != NULL; e = e->next)
+ { if (e->aj > 0.0)
+ e->aj = +1.0;
+ else /* e->aj < 0.0 */
+ e->aj = -1.0, b -= 1.0;
+ }
+ *_b = b;
+ return 2;
+}
+
+int npp_hidden_packing(NPP *npp, NPPROW *row)
+{ /* identify hidden packing inequality */
+ NPPROW *copy;
+ NPPAIJ *aij;
+ struct elem *ptr, *e;
+ int kase, ret, count = 0;
+ double b;
+ /* the row must be inequality constraint */
+ xassert(row->lb < row->ub);
+ for (kase = 0; kase <= 1; kase++)
+ { if (kase == 0)
+ { /* process row upper bound */
+ if (row->ub == +DBL_MAX) continue;
+ ptr = copy_form(npp, row, +1.0);
+ b = + row->ub;
+ }
+ else
+ { /* process row lower bound */
+ if (row->lb == -DBL_MAX) continue;
+ ptr = copy_form(npp, row, -1.0);
+ b = - row->lb;
+ }
+ /* now the inequality has the form "sum a[j] x[j] <= b" */
+ ret = hidden_packing(npp, ptr, &b);
+ xassert(0 <= ret && ret <= 2);
+ if (kase == 1 && ret == 1 || ret == 2)
+ { /* the original inequality has been identified as hidden
+ packing inequality */
+ count++;
+#ifdef GLP_DEBUG
+ xprintf("Original constraint:\n");
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ xprintf(" %+g x%d", aij->val, aij->col->j);
+ if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
+ if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
+ xprintf("\n");
+ xprintf("Equivalent packing inequality:\n");
+ for (e = ptr; e != NULL; e = e->next)
+ xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
+ xprintf(", <= %g\n", b);
+#endif
+ if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+ { /* the original row is single-sided inequality; no copy
+ is needed */
+ copy = NULL;
+ }
+ else
+ { /* the original row is double-sided inequality; we need
+ to create its copy for other bound before replacing it
+ with the equivalent inequality */
+ copy = npp_add_row(npp);
+ if (kase == 0)
+ { /* the copy is for lower bound */
+ copy->lb = row->lb, copy->ub = +DBL_MAX;
+ }
+ else
+ { /* the copy is for upper bound */
+ copy->lb = -DBL_MAX, copy->ub = row->ub;
+ }
+ /* copy original row coefficients */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_add_aij(npp, copy, aij->col, aij->val);
+ }
+ /* replace the original inequality by equivalent one */
+ npp_erase_row(npp, row);
+ row->lb = -DBL_MAX, row->ub = b;
+ for (e = ptr; e != NULL; e = e->next)
+ npp_add_aij(npp, row, e->xj, e->aj);
+ /* continue processing lower bound for the copy */
+ if (copy != NULL) row = copy;
+ }
+ drop_form(npp, ptr);
+ }
+ return count;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_implied_packing - identify implied packing inequality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+* NPPCOL *var[], char set[]);
+*
+* DESCRIPTION
+*
+* The routine npp_implied_packing processes specified row (constraint)
+* of general format:
+*
+* L <= sum a[j] x[j] <= U. (1)
+* j
+*
+* If which = 0, only lower bound L, which must exist, is considered,
+* while upper bound U is ignored. Similarly, if which = 1, only upper
+* bound U, which must exist, is considered, while lower bound L is
+* ignored. Thus, if the specified row is a double-sided inequality or
+* equality constraint, this routine should be called twice for both
+* lower and upper bounds.
+*
+* The routine npp_implied_packing attempts to find a non-trivial (i.e.
+* having not less than two binary variables) packing inequality:
+*
+* sum x[j] - sum x[j] <= 1 - |Jn|, (2)
+* j in Jp j in Jn
+*
+* which is relaxation of the constraint (1) in the sense that any
+* solution satisfying to that constraint also satisfies to the packing
+* inequality (2). If such relaxation exists, the routine stores
+* pointers to descriptors of corresponding binary variables and their
+* flags, resp., to locations var[1], var[2], ..., var[len] and set[1],
+* set[2], ..., set[len], where set[j] = 0 means that j in Jp and
+* set[j] = 1 means that j in Jn.
+*
+* RETURNS
+*
+* The routine npp_implied_packing returns len, which is the total
+* number of binary variables in the packing inequality found, len >= 2.
+* However, if the relaxation does not exist, the routine returns zero.
+*
+* ALGORITHM
+*
+* If which = 0, the constraint coefficients (1) are multiplied by -1
+* and b is assigned -L; if which = 1, the constraint coefficients (1)
+* are not changed and b is assigned +U. In both cases the specified
+* constraint gets the following format:
+*
+* sum a[j] x[j] <= b. (3)
+* j
+*
+* (Note that (3) is a relaxation of (1), because one of bounds L or U
+* is ignored.)
+*
+* Let J be set of binary variables, Kp be set of non-binary (integer
+* or continuous) variables with a[j] > 0, and Kn be set of non-binary
+* variables with a[j] < 0. Then the inequality (3) can be written as
+* follows:
+*
+* sum a[j] x[j] <= b - sum a[j] x[j] - sum a[j] x[j]. (4)
+* j in J j in Kp j in Kn
+*
+* To get rid of non-binary variables we can replace the inequality (4)
+* by the following relaxed inequality:
+*
+* sum a[j] x[j] <= b~, (5)
+* j in J
+*
+* where:
+*
+* b~ = sup(b - sum a[j] x[j] - sum a[j] x[j]) =
+* j in Kp j in Kn
+*
+* = b - inf sum a[j] x[j] - inf sum a[j] x[j] = (6)
+* j in Kp j in Kn
+*
+* = b - sum a[j] l[j] - sum a[j] u[j].
+* j in Kp j in Kn
+*
+* Note that if lower bound l[j] (if j in Kp) or upper bound u[j]
+* (if j in Kn) of some non-binary variable x[j] does not exist, then
+* formally b = +oo, in which case further analysis is not performed.
+*
+* Let Bp = {j in J: a[j] > 0}, Bn = {j in J: a[j] < 0}. To make all
+* the inequality coefficients in (5) positive, we replace all x[j] in
+* Bn by their complementaries, substituting x[j] = 1 - x~[j] for all
+* j in Bn, that gives:
+*
+* sum a[j] x[j] - sum a[j] x~[j] <= b~ - sum a[j]. (7)
+* j in Bp j in Bn j in Bn
+*
+* This inequality is a relaxation of the original constraint (1), and
+* it is a binary knapsack inequality. Writing it in the standard format
+* we have:
+*
+* sum alfa[j] z[j] <= beta, (8)
+* j in J
+*
+* where:
+* ( + a[j], if j in Bp,
+* alfa[j] = < (9)
+* ( - a[j], if j in Bn,
+*
+* ( x[j], if j in Bp,
+* z[j] = < (10)
+* ( 1 - x[j], if j in Bn,
+*
+* beta = b~ - sum a[j]. (11)
+* j in Bn
+*
+* In the inequality (8) all coefficients are positive, therefore, the
+* packing relaxation to be found for this inequality is the following:
+*
+* sum z[j] <= 1. (12)
+* j in P
+*
+* It is obvious that set P within J, which we would like to find, must
+* satisfy to the following condition:
+*
+* alfa[j] + alfa[k] > beta + eps for all j, k in P, j != k, (13)
+*
+* where eps is an absolute tolerance for value of the linear form.
+* Thus, it is natural to take P = {j: alpha[j] > (beta + eps) / 2}.
+* Moreover, if in the equality (8) there exist coefficients alfa[k],
+* for which alfa[k] <= (beta + eps) / 2, but which, nevertheless,
+* satisfies to the condition (13) for all j in P, *one* corresponding
+* variable z[k] (having, for example, maximal coefficient alfa[k]) can
+* be included in set P, that allows increasing the number of binary
+* variables in (12) by one.
+*
+* Once the set P has been built, for the inequality (12) we need to
+* perform back substitution according to (10) in order to express it
+* through the original binary variables. As the result of such back
+* substitution the relaxed packing inequality get its final format (2),
+* where Jp = J intersect Bp, and Jn = J intersect Bn. */
+
+int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+ NPPCOL *var[], char set[])
+{ struct elem *ptr, *e, *i, *k;
+ int len = 0;
+ double b, eps;
+ /* build inequality (3) */
+ if (which == 0)
+ { ptr = copy_form(npp, row, -1.0);
+ xassert(row->lb != -DBL_MAX);
+ b = - row->lb;
+ }
+ else if (which == 1)
+ { ptr = copy_form(npp, row, +1.0);
+ xassert(row->ub != +DBL_MAX);
+ b = + row->ub;
+ }
+ /* remove non-binary variables to build relaxed inequality (5);
+ compute its right-hand side b~ with formula (6) */
+ for (e = ptr; e != NULL; e = e->next)
+ { if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
+ { /* x[j] is non-binary variable */
+ if (e->aj > 0.0)
+ { if (e->xj->lb == -DBL_MAX) goto done;
+ b -= e->aj * e->xj->lb;
+ }
+ else /* e->aj < 0.0 */
+ { if (e->xj->ub == +DBL_MAX) goto done;
+ b -= e->aj * e->xj->ub;
+ }
+ /* a[j] = 0 means that variable x[j] is removed */
+ e->aj = 0.0;
+ }
+ }
+ /* substitute x[j] = 1 - x~[j] to build knapsack inequality (8);
+ compute its right-hand side beta with formula (11) */
+ for (e = ptr; e != NULL; e = e->next)
+ if (e->aj < 0.0) b -= e->aj;
+ /* if beta is close to zero, the knapsack inequality is either
+ infeasible or forcing inequality; this must never happen, so
+ we skip further analysis */
+ if (b < 1e-3) goto done;
+ /* build set P as well as sets Jp and Jn, and determine x[k] as
+ explained above in comments to the routine */
+ eps = 1e-3 + 1e-6 * b;
+ i = k = NULL;
+ for (e = ptr; e != NULL; e = e->next)
+ { /* note that alfa[j] = |a[j]| */
+ if (fabs(e->aj) > 0.5 * (b + eps))
+ { /* alfa[j] > (b + eps) / 2; include x[j] in set P, i.e. in
+ set Jp or Jn */
+ var[++len] = e->xj;
+ set[len] = (char)(e->aj > 0.0 ? 0 : 1);
+ /* alfa[i] = min alfa[j] over all j included in set P */
+ if (i == NULL || fabs(i->aj) > fabs(e->aj)) i = e;
+ }
+ else if (fabs(e->aj) >= 1e-3)
+ { /* alfa[k] = max alfa[j] over all j not included in set P;
+ we skip coefficient a[j] if it is close to zero to avoid
+ numerically unreliable results */
+ if (k == NULL || fabs(k->aj) < fabs(e->aj)) k = e;
+ }
+ }
+ /* if alfa[k] satisfies to condition (13) for all j in P, include
+ x[k] in P */
+ if (i != NULL && k != NULL && fabs(i->aj) + fabs(k->aj) > b + eps)
+ { var[++len] = k->xj;
+ set[len] = (char)(k->aj > 0.0 ? 0 : 1);
+ }
+ /* trivial packing inequality being redundant must never appear,
+ so we just ignore it */
+ if (len < 2) len = 0;
+done: drop_form(npp, ptr);
+ return len;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_is_covering - test if constraint is covering inequality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_is_covering(NPP *npp, NPPROW *row);
+*
+* RETURNS
+*
+* If the specified row (constraint) is covering inequality (see below),
+* the routine npp_is_covering returns non-zero. Otherwise, it returns
+* zero.
+*
+* COVERING INEQUALITIES
+*
+* In canonical format the covering inequality is the following:
+*
+* sum x[j] >= 1, (1)
+* j in J
+*
+* where all variables x[j] are binary. This inequality expresses the
+* condition that in any integer feasible solution variables in set J
+* cannot be all equal to zero at the same time, i.e. at least one
+* variable must take non-zero (unity) value. W.l.o.g. it is assumed
+* that |J| >= 2, because if J is empty, the inequality (1) is
+* infeasible, and if |J| = 1, the inequality (1) is a forcing row.
+*
+* In general case the covering inequality may include original
+* variables x[j] as well as their complements x~[j]:
+*
+* sum x[j] + sum x~[j] >= 1, (2)
+* j in Jp j in Jn
+*
+* where Jp and Jn are not intersected. Therefore, using substitution
+* x~[j] = 1 - x[j] gives the packing inequality in generalized format:
+*
+* sum x[j] - sum x[j] >= 1 - |Jn|. (3)
+* j in Jp j in Jn
+*
+* (May note that the inequality (3) cuts off infeasible solutions,
+* where x[j] = 0 for all j in Jp and x[j] = 1 for all j in Jn.)
+*
+* NOTE: If |J| = 2, the inequality (3) is equivalent to packing
+* inequality (see the routine npp_is_packing). */
+
+int npp_is_covering(NPP *npp, NPPROW *row)
+{ /* test if constraint is covering inequality */
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int b;
+ xassert(npp == npp);
+ if (!(row->lb != -DBL_MAX && row->ub == +DBL_MAX))
+ return 0;
+ b = 1;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ return 0;
+ if (aij->val == +1.0)
+ ;
+ else if (aij->val == -1.0)
+ b--;
+ else
+ return 0;
+ }
+ if (row->lb != (double)b) return 0;
+ return 1;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_hidden_covering - identify hidden covering inequality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_hidden_covering(NPP *npp, NPPROW *row);
+*
+* DESCRIPTION
+*
+* The routine npp_hidden_covering processes specified inequality
+* constraint, which includes only binary variables, and the number of
+* the variables is not less than three. If the original inequality is
+* equivalent to a covering inequality (see below), the routine
+* replaces it by the equivalent inequality. If the original constraint
+* is double-sided inequality, it is replaced by a pair of single-sided
+* inequalities, if necessary.
+*
+* RETURNS
+*
+* If the original inequality constraint was replaced by equivalent
+* covering inequality, the routine npp_hidden_covering returns
+* non-zero. Otherwise, it returns zero.
+*
+* PROBLEM TRANSFORMATION
+*
+* Consider an inequality constraint:
+*
+* sum a[j] x[j] >= b, (1)
+* j in J
+*
+* where all variables x[j] are binary, and |J| >= 3. (In case of '<='
+* inequality it can be transformed to '>=' format by multiplying both
+* its sides by -1.)
+*
+* Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
+* x[j] = 1 - x~[j] for all j in Jn, we have:
+*
+* sum a[j] x[j] >= b ==>
+* j in J
+*
+* sum a[j] x[j] + sum a[j] x[j] >= b ==>
+* j in Jp j in Jn
+*
+* sum a[j] x[j] + sum a[j] (1 - x~[j]) >= b ==>
+* j in Jp j in Jn
+*
+* sum m a[j] x[j] - sum a[j] x~[j] >= b - sum a[j].
+* j in Jp j in Jn j in Jn
+*
+* Thus, meaning the transformation above, we can assume that in
+* inequality (1) all coefficients a[j] are positive. Moreover, we can
+* assume that b > 0, because otherwise the inequality (1) would be
+* redundant (see the routine npp_analyze_row). It is then obvious that
+* constraint (1) is equivalent to covering inequality only if:
+*
+* a[j] >= b, (2)
+*
+* for all j in J.
+*
+* Once the original inequality (1) is replaced by equivalent covering
+* inequality, we need to perform back substitution x~[j] = 1 - x[j] for
+* all j in Jn (see above).
+*
+* RECOVERING SOLUTION
+*
+* None needed. */
+
+static int hidden_covering(NPP *npp, struct elem *ptr, double *_b)
+{ /* process inequality constraint: sum a[j] x[j] >= b;
+ 0 - specified row is NOT hidden covering inequality;
+ 1 - specified row is covering inequality;
+ 2 - specified row is hidden covering inequality. */
+ struct elem *e;
+ int neg;
+ double b = *_b, eps;
+ xassert(npp == npp);
+ /* a[j] must be non-zero, x[j] must be binary, for all j in J */
+ for (e = ptr; e != NULL; e = e->next)
+ { xassert(e->aj != 0.0);
+ xassert(e->xj->is_int);
+ xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
+ }
+ /* check if the specified inequality constraint already has the
+ form of covering inequality */
+ neg = 0; /* neg is |Jn| */
+ for (e = ptr; e != NULL; e = e->next)
+ { if (e->aj == +1.0)
+ ;
+ else if (e->aj == -1.0)
+ neg++;
+ else
+ break;
+ }
+ if (e == NULL)
+ { /* all coefficients a[j] are +1 or -1; check rhs b */
+ if (b == (double)(1 - neg))
+ { /* it is covering inequality; no processing is needed */
+ return 1;
+ }
+ }
+ /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
+ positive; the result is a~[j] = |a[j]| and new rhs b */
+ for (e = ptr; e != NULL; e = e->next)
+ if (e->aj < 0) b -= e->aj;
+ /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
+ /* if b <= 0, skip processing--this case must not appear */
+ if (b < 1e-3) return 0;
+ /* now a[j] > 0 for all j in J, and b > 0 */
+ /* the specified constraint is equivalent to covering inequality
+ iff a[j] >= b for all j in J */
+ eps = 1e-9 + 1e-12 * fabs(b);
+ for (e = ptr; e != NULL; e = e->next)
+ if (fabs(e->aj) < b - eps) return 0;
+ /* perform back substitution x~[j] = 1 - x[j] and construct the
+ final equivalent covering inequality in generalized format */
+ b = 1.0;
+ for (e = ptr; e != NULL; e = e->next)
+ { if (e->aj > 0.0)
+ e->aj = +1.0;
+ else /* e->aj < 0.0 */
+ e->aj = -1.0, b -= 1.0;
+ }
+ *_b = b;
+ return 2;
+}
+
+int npp_hidden_covering(NPP *npp, NPPROW *row)
+{ /* identify hidden covering inequality */
+ NPPROW *copy;
+ NPPAIJ *aij;
+ struct elem *ptr, *e;
+ int kase, ret, count = 0;
+ double b;
+ /* the row must be inequality constraint */
+ xassert(row->lb < row->ub);
+ for (kase = 0; kase <= 1; kase++)
+ { if (kase == 0)
+ { /* process row lower bound */
+ if (row->lb == -DBL_MAX) continue;
+ ptr = copy_form(npp, row, +1.0);
+ b = + row->lb;
+ }
+ else
+ { /* process row upper bound */
+ if (row->ub == +DBL_MAX) continue;
+ ptr = copy_form(npp, row, -1.0);
+ b = - row->ub;
+ }
+ /* now the inequality has the form "sum a[j] x[j] >= b" */
+ ret = hidden_covering(npp, ptr, &b);
+ xassert(0 <= ret && ret <= 2);
+ if (kase == 1 && ret == 1 || ret == 2)
+ { /* the original inequality has been identified as hidden
+ covering inequality */
+ count++;
+#ifdef GLP_DEBUG
+ xprintf("Original constraint:\n");
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ xprintf(" %+g x%d", aij->val, aij->col->j);
+ if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
+ if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
+ xprintf("\n");
+ xprintf("Equivalent covering inequality:\n");
+ for (e = ptr; e != NULL; e = e->next)
+ xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
+ xprintf(", >= %g\n", b);
+#endif
+ if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+ { /* the original row is single-sided inequality; no copy
+ is needed */
+ copy = NULL;
+ }
+ else
+ { /* the original row is double-sided inequality; we need
+ to create its copy for other bound before replacing it
+ with the equivalent inequality */
+ copy = npp_add_row(npp);
+ if (kase == 0)
+ { /* the copy is for upper bound */
+ copy->lb = -DBL_MAX, copy->ub = row->ub;
+ }
+ else
+ { /* the copy is for lower bound */
+ copy->lb = row->lb, copy->ub = +DBL_MAX;
+ }
+ /* copy original row coefficients */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_add_aij(npp, copy, aij->col, aij->val);
+ }
+ /* replace the original inequality by equivalent one */
+ npp_erase_row(npp, row);
+ row->lb = b, row->ub = +DBL_MAX;
+ for (e = ptr; e != NULL; e = e->next)
+ npp_add_aij(npp, row, e->xj, e->aj);
+ /* continue processing upper bound for the copy */
+ if (copy != NULL) row = copy;
+ }
+ drop_form(npp, ptr);
+ }
+ return count;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_is_partitioning - test if constraint is partitioning equality
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_is_partitioning(NPP *npp, NPPROW *row);
+*
+* RETURNS
+*
+* If the specified row (constraint) is partitioning equality (see
+* below), the routine npp_is_partitioning returns non-zero. Otherwise,
+* it returns zero.
+*
+* PARTITIONING EQUALITIES
+*
+* In canonical format the partitioning equality is the following:
+*
+* sum x[j] = 1, (1)
+* j in J
+*
+* where all variables x[j] are binary. This equality expresses the
+* condition that in any integer feasible solution exactly one variable
+* in set J must take non-zero (unity) value while other variables must
+* be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because if
+* J is empty, the inequality (1) is infeasible, and if |J| = 1, the
+* inequality (1) is a fixing row.
+*
+* In general case the partitioning equality may include original
+* variables x[j] as well as their complements x~[j]:
+*
+* sum x[j] + sum x~[j] = 1, (2)
+* j in Jp j in Jn
+*
+* where Jp and Jn are not intersected. Therefore, using substitution
+* x~[j] = 1 - x[j] leads to the partitioning equality in generalized
+* format:
+*
+* sum x[j] - sum x[j] = 1 - |Jn|. (3)
+* j in Jp j in Jn */
+
+int npp_is_partitioning(NPP *npp, NPPROW *row)
+{ /* test if constraint is partitioning equality */
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int b;
+ xassert(npp == npp);
+ if (row->lb != row->ub) return 0;
+ b = 1;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ return 0;
+ if (aij->val == +1.0)
+ ;
+ else if (aij->val == -1.0)
+ b--;
+ else
+ return 0;
+ }
+ if (row->lb != (double)b) return 0;
+ return 1;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_reduce_ineq_coef - reduce inequality constraint coefficients
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
+*
+* DESCRIPTION
+*
+* The routine npp_reduce_ineq_coef processes specified inequality
+* constraint attempting to replace it by an equivalent constraint,
+* where magnitude of coefficients at binary variables is smaller than
+* in the original constraint. If the inequality is double-sided, it is
+* replaced by a pair of single-sided inequalities, if necessary.
+*
+* RETURNS
+*
+* The routine npp_reduce_ineq_coef returns the number of coefficients
+* reduced.
+*
+* BACKGROUND
+*
+* Consider an inequality constraint:
+*
+* sum a[j] x[j] >= b. (1)
+* j in J
+*
+* (In case of '<=' inequality it can be transformed to '>=' format by
+* multiplying both its sides by -1.) Let x[k] be a binary variable;
+* other variables can be integer as well as continuous. We can write
+* constraint (1) as follows:
+*
+* a[k] x[k] + t[k] >= b, (2)
+*
+* where:
+*
+* t[k] = sum a[j] x[j]. (3)
+* j in J\{k}
+*
+* Since x[k] is binary, constraint (2) is equivalent to disjunction of
+* the following two constraints:
+*
+* x[k] = 0, t[k] >= b (4)
+*
+* OR
+*
+* x[k] = 1, t[k] >= b - a[k]. (5)
+*
+* Let also that for the partial sum t[k] be known some its implied
+* lower bound inf t[k].
+*
+* Case a[k] > 0. Let inf t[k] < b, since otherwise both constraints
+* (4) and (5) and therefore constraint (2) are redundant.
+* If inf t[k] > b - a[k], only constraint (5) is redundant, in which
+* case it can be replaced with the following redundant and therefore
+* equivalent constraint:
+*
+* t[k] >= b - a'[k] = inf t[k], (6)
+*
+* where:
+*
+* a'[k] = b - inf t[k]. (7)
+*
+* Thus, the original constraint (2) is equivalent to the following
+* constraint with coefficient at variable x[k] changed:
+*
+* a'[k] x[k] + t[k] >= b. (8)
+*
+* From inf t[k] < b it follows that a'[k] > 0, i.e. the coefficient
+* at x[k] keeps its sign. And from inf t[k] > b - a[k] it follows that
+* a'[k] < a[k], i.e. the coefficient reduces in magnitude.
+*
+* Case a[k] < 0. Let inf t[k] < b - a[k], since otherwise both
+* constraints (4) and (5) and therefore constraint (2) are redundant.
+* If inf t[k] > b, only constraint (4) is redundant, in which case it
+* can be replaced with the following redundant and therefore equivalent
+* constraint:
+*
+* t[k] >= b' = inf t[k]. (9)
+*
+* Rewriting constraint (5) as follows:
+*
+* t[k] >= b - a[k] = b' - a'[k], (10)
+*
+* where:
+*
+* a'[k] = a[k] + b' - b = a[k] + inf t[k] - b, (11)
+*
+* we can see that disjunction of constraint (9) and (10) is equivalent
+* to disjunction of constraint (4) and (5), from which it follows that
+* the original constraint (2) is equivalent to the following constraint
+* with both coefficient at variable x[k] and right-hand side changed:
+*
+* a'[k] x[k] + t[k] >= b'. (12)
+*
+* From inf t[k] < b - a[k] it follows that a'[k] < 0, i.e. the
+* coefficient at x[k] keeps its sign. And from inf t[k] > b it follows
+* that a'[k] > a[k], i.e. the coefficient reduces in magnitude.
+*
+* PROBLEM TRANSFORMATION
+*
+* In the routine npp_reduce_ineq_coef the following implied lower
+* bound of the partial sum (3) is used:
+*
+* inf t[k] = sum a[j] l[j] + sum a[j] u[j], (13)
+* j in Jp\{k} k in Jn\{k}
+*
+* where Jp = {j : a[j] > 0}, Jn = {j : a[j] < 0}, l[j] and u[j] are
+* lower and upper bounds, resp., of variable x[j].
+*
+* In order to compute inf t[k] more efficiently, the following formula,
+* which is equivalent to (13), is actually used:
+*
+* ( h - a[k] l[k] = h, if a[k] > 0,
+* inf t[k] = < (14)
+* ( h - a[k] u[k] = h - a[k], if a[k] < 0,
+*
+* where:
+*
+* h = sum a[j] l[j] + sum a[j] u[j] (15)
+* j in Jp j in Jn
+*
+* is the implied lower bound of row (1).
+*
+* Reduction of positive coefficient (a[k] > 0) does not change value
+* of h, since l[k] = 0. In case of reduction of negative coefficient
+* (a[k] < 0) from (11) it follows that:
+*
+* delta a[k] = a'[k] - a[k] = inf t[k] - b (> 0), (16)
+*
+* so new value of h (accounting that u[k] = 1) can be computed as
+* follows:
+*
+* h := h + delta a[k] = h + (inf t[k] - b). (17)
+*
+* RECOVERING SOLUTION
+*
+* None needed. */
+
+static int reduce_ineq_coef(NPP *npp, struct elem *ptr, double *_b)
+{ /* process inequality constraint: sum a[j] x[j] >= b */
+ /* returns: the number of coefficients reduced */
+ struct elem *e;
+ int count = 0;
+ double h, inf_t, new_a, b = *_b;
+ xassert(npp == npp);
+ /* compute h; see (15) */
+ h = 0.0;
+ for (e = ptr; e != NULL; e = e->next)
+ { if (e->aj > 0.0)
+ { if (e->xj->lb == -DBL_MAX) goto done;
+ h += e->aj * e->xj->lb;
+ }
+ else /* e->aj < 0.0 */
+ { if (e->xj->ub == +DBL_MAX) goto done;
+ h += e->aj * e->xj->ub;
+ }
+ }
+ /* perform reduction of coefficients at binary variables */
+ for (e = ptr; e != NULL; e = e->next)
+ { /* skip non-binary variable */
+ if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
+ continue;
+ if (e->aj > 0.0)
+ { /* compute inf t[k]; see (14) */
+ inf_t = h;
+ if (b - e->aj < inf_t && inf_t < b)
+ { /* compute reduced coefficient a'[k]; see (7) */
+ new_a = b - inf_t;
+ if (new_a >= +1e-3 &&
+ e->aj - new_a >= 0.01 * (1.0 + e->aj))
+ { /* accept a'[k] */
+#ifdef GLP_DEBUG
+ xprintf("+");
+#endif
+ e->aj = new_a;
+ count++;
+ }
+ }
+ }
+ else /* e->aj < 0.0 */
+ { /* compute inf t[k]; see (14) */
+ inf_t = h - e->aj;
+ if (b < inf_t && inf_t < b - e->aj)
+ { /* compute reduced coefficient a'[k]; see (11) */
+ new_a = e->aj + (inf_t - b);
+ if (new_a <= -1e-3 &&
+ new_a - e->aj >= 0.01 * (1.0 - e->aj))
+ { /* accept a'[k] */
+#ifdef GLP_DEBUG
+ xprintf("-");
+#endif
+ e->aj = new_a;
+ /* update h; see (17) */
+ h += (inf_t - b);
+ /* compute b'; see (9) */
+ b = inf_t;
+ count++;
+ }
+ }
+ }
+ }
+ *_b = b;
+done: return count;
+}
+
+int npp_reduce_ineq_coef(NPP *npp, NPPROW *row)
+{ /* reduce inequality constraint coefficients */
+ NPPROW *copy;
+ NPPAIJ *aij;
+ struct elem *ptr, *e;
+ int kase, count[2];
+ double b;
+ /* the row must be inequality constraint */
+ xassert(row->lb < row->ub);
+ count[0] = count[1] = 0;
+ for (kase = 0; kase <= 1; kase++)
+ { if (kase == 0)
+ { /* process row lower bound */
+ if (row->lb == -DBL_MAX) continue;
+#ifdef GLP_DEBUG
+ xprintf("L");
+#endif
+ ptr = copy_form(npp, row, +1.0);
+ b = + row->lb;
+ }
+ else
+ { /* process row upper bound */
+ if (row->ub == +DBL_MAX) continue;
+#ifdef GLP_DEBUG
+ xprintf("U");
+#endif
+ ptr = copy_form(npp, row, -1.0);
+ b = - row->ub;
+ }
+ /* now the inequality has the form "sum a[j] x[j] >= b" */
+ count[kase] = reduce_ineq_coef(npp, ptr, &b);
+ if (count[kase] > 0)
+ { /* the original inequality has been replaced by equivalent
+ one with coefficients reduced */
+ if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+ { /* the original row is single-sided inequality; no copy
+ is needed */
+ copy = NULL;
+ }
+ else
+ { /* the original row is double-sided inequality; we need
+ to create its copy for other bound before replacing it
+ with the equivalent inequality */
+#ifdef GLP_DEBUG
+ xprintf("*");
+#endif
+ copy = npp_add_row(npp);
+ if (kase == 0)
+ { /* the copy is for upper bound */
+ copy->lb = -DBL_MAX, copy->ub = row->ub;
+ }
+ else
+ { /* the copy is for lower bound */
+ copy->lb = row->lb, copy->ub = +DBL_MAX;
+ }
+ /* copy original row coefficients */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_add_aij(npp, copy, aij->col, aij->val);
+ }
+ /* replace the original inequality by equivalent one */
+ npp_erase_row(npp, row);
+ row->lb = b, row->ub = +DBL_MAX;
+ for (e = ptr; e != NULL; e = e->next)
+ npp_add_aij(npp, row, e->xj, e->aj);
+ /* continue processing upper bound for the copy */
+ if (copy != NULL) row = copy;
+ }
+ drop_form(npp, ptr);
+ }
+ return count[0] + count[1];
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp5.c b/test/monniaux/glpk-4.65/src/npp/npp5.c
new file mode 100644
index 00000000..2fad496d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp5.c
@@ -0,0 +1,809 @@
+/* npp5.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2009-2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+/***********************************************************************
+* NAME
+*
+* npp_clean_prob - perform initial LP/MIP processing
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* void npp_clean_prob(NPP *npp);
+*
+* DESCRIPTION
+*
+* The routine npp_clean_prob performs initial LP/MIP processing that
+* currently includes:
+*
+* 1) removing free rows;
+*
+* 2) replacing double-sided constraint rows with almost identical
+* bounds, by equality constraint rows;
+*
+* 3) removing fixed columns;
+*
+* 4) replacing double-bounded columns with almost identical bounds by
+* fixed columns and removing those columns;
+*
+* 5) initial processing constraint coefficients (not implemented);
+*
+* 6) initial processing objective coefficients (not implemented). */
+
+void npp_clean_prob(NPP *npp)
+{ /* perform initial LP/MIP processing */
+ NPPROW *row, *next_row;
+ NPPCOL *col, *next_col;
+ int ret;
+ xassert(npp == npp);
+ /* process rows which originally are free */
+ for (row = npp->r_head; row != NULL; row = next_row)
+ { next_row = row->next;
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ { /* process free row */
+#ifdef GLP_DEBUG
+ xprintf("1");
+#endif
+ npp_free_row(npp, row);
+ /* row was deleted */
+ }
+ }
+ /* process rows which originally are double-sided inequalities */
+ for (row = npp->r_head; row != NULL; row = next_row)
+ { next_row = row->next;
+ if (row->lb != -DBL_MAX && row->ub != +DBL_MAX &&
+ row->lb < row->ub)
+ { ret = npp_make_equality(npp, row);
+ if (ret == 0)
+ ;
+ else if (ret == 1)
+ { /* row was replaced by equality constraint */
+#ifdef GLP_DEBUG
+ xprintf("2");
+#endif
+ }
+ else
+ xassert(ret != ret);
+ }
+ }
+ /* process columns which are originally fixed */
+ for (col = npp->c_head; col != NULL; col = next_col)
+ { next_col = col->next;
+ if (col->lb == col->ub)
+ { /* process fixed column */
+#ifdef GLP_DEBUG
+ xprintf("3");
+#endif
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ }
+ }
+ /* process columns which are originally double-bounded */
+ for (col = npp->c_head; col != NULL; col = next_col)
+ { next_col = col->next;
+ if (col->lb != -DBL_MAX && col->ub != +DBL_MAX &&
+ col->lb < col->ub)
+ { ret = npp_make_fixed(npp, col);
+ if (ret == 0)
+ ;
+ else if (ret == 1)
+ { /* column was replaced by fixed column; process it */
+#ifdef GLP_DEBUG
+ xprintf("4");
+#endif
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_process_row - perform basic row processing
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_process_row(NPP *npp, NPPROW *row, int hard);
+*
+* DESCRIPTION
+*
+* The routine npp_process_row performs basic row processing that
+* currently includes:
+*
+* 1) removing empty row;
+*
+* 2) removing equality constraint row singleton and corresponding
+* column;
+*
+* 3) removing inequality constraint row singleton and corresponding
+* column if it was fixed;
+*
+* 4) performing general row analysis;
+*
+* 5) removing redundant row bounds;
+*
+* 6) removing forcing row and corresponding columns;
+*
+* 7) removing row which becomes free due to redundant bounds;
+*
+* 8) computing implied bounds for all columns in the row and using
+* them to strengthen current column bounds (MIP only, optional,
+* performed if the flag hard is on).
+*
+* Additionally the routine may activate affected rows and/or columns
+* for further processing.
+*
+* RETURNS
+*
+* 0 success;
+*
+* GLP_ENOPFS primal/integer infeasibility detected;
+*
+* GLP_ENODFS dual infeasibility detected. */
+
+int npp_process_row(NPP *npp, NPPROW *row, int hard)
+{ /* perform basic row processing */
+ NPPCOL *col;
+ NPPAIJ *aij, *next_aij, *aaa;
+ int ret;
+ /* row must not be free */
+ xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+ /* start processing row */
+ if (row->ptr == NULL)
+ { /* empty row */
+ ret = npp_empty_row(npp, row);
+ if (ret == 0)
+ { /* row was deleted */
+#ifdef GLP_DEBUG
+ xprintf("A");
+#endif
+ return 0;
+ }
+ else if (ret == 1)
+ { /* primal infeasibility */
+ return GLP_ENOPFS;
+ }
+ else
+ xassert(ret != ret);
+ }
+ if (row->ptr->r_next == NULL)
+ { /* row singleton */
+ col = row->ptr->col;
+ if (row->lb == row->ub)
+ { /* equality constraint */
+ ret = npp_eq_singlet(npp, row);
+ if (ret == 0)
+ { /* column was fixed, row was deleted */
+#ifdef GLP_DEBUG
+ xprintf("B");
+#endif
+ /* activate rows affected by column */
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ npp_activate_row(npp, aij->row);
+ /* process fixed column */
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ return 0;
+ }
+ else if (ret == 1 || ret == 2)
+ { /* primal/integer infeasibility */
+ return GLP_ENOPFS;
+ }
+ else
+ xassert(ret != ret);
+ }
+ else
+ { /* inequality constraint */
+ ret = npp_ineq_singlet(npp, row);
+ if (0 <= ret && ret <= 3)
+ { /* row was deleted */
+#ifdef GLP_DEBUG
+ xprintf("C");
+#endif
+ /* activate column, since its length was changed due to
+ row deletion */
+ npp_activate_col(npp, col);
+ if (ret >= 2)
+ { /* column bounds changed significantly or column was
+ fixed */
+ /* activate rows affected by column */
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ npp_activate_row(npp, aij->row);
+ }
+ if (ret == 3)
+ { /* column was fixed; process it */
+#ifdef GLP_DEBUG
+ xprintf("D");
+#endif
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ }
+ return 0;
+ }
+ else if (ret == 4)
+ { /* primal infeasibility */
+ return GLP_ENOPFS;
+ }
+ else
+ xassert(ret != ret);
+ }
+ }
+#if 0
+ /* sometimes this causes too large round-off errors; probably
+ pivot coefficient should be chosen more carefully */
+ if (row->ptr->r_next->r_next == NULL)
+ { /* row doubleton */
+ if (row->lb == row->ub)
+ { /* equality constraint */
+ if (!(row->ptr->col->is_int ||
+ row->ptr->r_next->col->is_int))
+ { /* both columns are continuous */
+ NPPCOL *q;
+ q = npp_eq_doublet(npp, row);
+ if (q != NULL)
+ { /* column q was eliminated */
+#ifdef GLP_DEBUG
+ xprintf("E");
+#endif
+ /* now column q is singleton of type "implied slack
+ variable"; we process it here to make sure that on
+ recovering basic solution the row is always active
+ equality constraint (as required by the routine
+ rcv_eq_doublet) */
+ xassert(npp_process_col(npp, q) == 0);
+ /* column q was deleted; note that row p also may be
+ deleted */
+ return 0;
+ }
+ }
+ }
+ }
+#endif
+ /* general row analysis */
+ ret = npp_analyze_row(npp, row);
+ xassert(0x00 <= ret && ret <= 0xFF);
+ if (ret == 0x33)
+ { /* row bounds are inconsistent with column bounds */
+ return GLP_ENOPFS;
+ }
+ if ((ret & 0x0F) == 0x00)
+ { /* row lower bound does not exist or redundant */
+ if (row->lb != -DBL_MAX)
+ { /* remove redundant row lower bound */
+#ifdef GLP_DEBUG
+ xprintf("F");
+#endif
+ npp_inactive_bound(npp, row, 0);
+ }
+ }
+ else if ((ret & 0x0F) == 0x01)
+ { /* row lower bound can be active */
+ /* see below */
+ }
+ else if ((ret & 0x0F) == 0x02)
+ { /* row lower bound is a forcing bound */
+#ifdef GLP_DEBUG
+ xprintf("G");
+#endif
+ /* process forcing row */
+ if (npp_forcing_row(npp, row, 0) == 0)
+fixup: { /* columns were fixed, row was made free */
+ for (aij = row->ptr; aij != NULL; aij = next_aij)
+ { /* process column fixed by forcing row */
+#ifdef GLP_DEBUG
+ xprintf("H");
+#endif
+ col = aij->col;
+ next_aij = aij->r_next;
+ /* activate rows affected by column */
+ for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
+ npp_activate_row(npp, aaa->row);
+ /* process fixed column */
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ }
+ /* process free row (which now is empty due to deletion of
+ all its columns) */
+ npp_free_row(npp, row);
+ /* row was deleted */
+ return 0;
+ }
+ }
+ else
+ xassert(ret != ret);
+ if ((ret & 0xF0) == 0x00)
+ { /* row upper bound does not exist or redundant */
+ if (row->ub != +DBL_MAX)
+ { /* remove redundant row upper bound */
+#ifdef GLP_DEBUG
+ xprintf("I");
+#endif
+ npp_inactive_bound(npp, row, 1);
+ }
+ }
+ else if ((ret & 0xF0) == 0x10)
+ { /* row upper bound can be active */
+ /* see below */
+ }
+ else if ((ret & 0xF0) == 0x20)
+ { /* row upper bound is a forcing bound */
+#ifdef GLP_DEBUG
+ xprintf("J");
+#endif
+ /* process forcing row */
+ if (npp_forcing_row(npp, row, 1) == 0) goto fixup;
+ }
+ else
+ xassert(ret != ret);
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ { /* row became free due to redundant bounds removal */
+#ifdef GLP_DEBUG
+ xprintf("K");
+#endif
+ /* activate its columns, since their length will change due
+ to row deletion */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_activate_col(npp, aij->col);
+ /* process free row */
+ npp_free_row(npp, row);
+ /* row was deleted */
+ return 0;
+ }
+#if 1 /* 23/XII-2009 */
+ /* row lower and/or upper bounds can be active */
+ if (npp->sol == GLP_MIP && hard)
+ { /* improve current column bounds (optional) */
+ if (npp_improve_bounds(npp, row, 1) < 0)
+ return GLP_ENOPFS;
+ }
+#endif
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_improve_bounds - improve current column bounds
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
+*
+* DESCRIPTION
+*
+* The routine npp_improve_bounds analyzes specified row (inequality
+* or equality constraint) to determine implied column bounds and then
+* uses these bounds to improve (strengthen) current column bounds.
+*
+* If the flag is on and current column bounds changed significantly
+* or the column was fixed, the routine activate rows affected by the
+* column for further processing. (This feature is intended to be used
+* in the main loop of the routine npp_process_row.)
+*
+* NOTE: This operation can be used for MIP problem only.
+*
+* RETURNS
+*
+* The routine npp_improve_bounds returns the number of significantly
+* changed bounds plus the number of column having been fixed due to
+* bound improvements. However, if the routine detects primal/integer
+* infeasibility, it returns a negative value. */
+
+int npp_improve_bounds(NPP *npp, NPPROW *row, int flag)
+{ /* improve current column bounds */
+ NPPCOL *col;
+ NPPAIJ *aij, *next_aij, *aaa;
+ int kase, ret, count = 0;
+ double lb, ub;
+ xassert(npp->sol == GLP_MIP);
+ /* row must not be free */
+ xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+ /* determine implied column bounds */
+ npp_implied_bounds(npp, row);
+ /* and use these bounds to strengthen current column bounds */
+ for (aij = row->ptr; aij != NULL; aij = next_aij)
+ { col = aij->col;
+ next_aij = aij->r_next;
+ for (kase = 0; kase <= 1; kase++)
+ { /* save current column bounds */
+ lb = col->lb, ub = col->ub;
+ if (kase == 0)
+ { /* process implied column lower bound */
+ if (col->ll.ll == -DBL_MAX) continue;
+ ret = npp_implied_lower(npp, col, col->ll.ll);
+ }
+ else
+ { /* process implied column upper bound */
+ if (col->uu.uu == +DBL_MAX) continue;
+ ret = npp_implied_upper(npp, col, col->uu.uu);
+ }
+ if (ret == 0 || ret == 1)
+ { /* current column bounds did not change or changed, but
+ not significantly; restore current column bounds */
+ col->lb = lb, col->ub = ub;
+ }
+ else if (ret == 2 || ret == 3)
+ { /* current column bounds changed significantly or column
+ was fixed */
+#ifdef GLP_DEBUG
+ xprintf("L");
+#endif
+ count++;
+ /* activate other rows affected by column, if required */
+ if (flag)
+ { for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
+ { if (aaa->row != row)
+ npp_activate_row(npp, aaa->row);
+ }
+ }
+ if (ret == 3)
+ { /* process fixed column */
+#ifdef GLP_DEBUG
+ xprintf("M");
+#endif
+ npp_fixed_col(npp, col);
+ /* column was deleted */
+ break; /* for kase */
+ }
+ }
+ else if (ret == 4)
+ { /* primal/integer infeasibility */
+ return -1;
+ }
+ else
+ xassert(ret != ret);
+ }
+ }
+ return count;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_process_col - perform basic column processing
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_process_col(NPP *npp, NPPCOL *col);
+*
+* DESCRIPTION
+*
+* The routine npp_process_col performs basic column processing that
+* currently includes:
+*
+* 1) fixing and removing empty column;
+*
+* 2) removing column singleton, which is implied slack variable, and
+* corresponding row if it becomes free;
+*
+* 3) removing bounds of column, which is implied free variable, and
+* replacing corresponding row by equality constraint.
+*
+* Additionally the routine may activate affected rows and/or columns
+* for further processing.
+*
+* RETURNS
+*
+* 0 success;
+*
+* GLP_ENOPFS primal/integer infeasibility detected;
+*
+* GLP_ENODFS dual infeasibility detected. */
+
+int npp_process_col(NPP *npp, NPPCOL *col)
+{ /* perform basic column processing */
+ NPPROW *row;
+ NPPAIJ *aij;
+ int ret;
+ /* column must not be fixed */
+ xassert(col->lb < col->ub);
+ /* start processing column */
+ if (col->ptr == NULL)
+ { /* empty column */
+ ret = npp_empty_col(npp, col);
+ if (ret == 0)
+ { /* column was fixed and deleted */
+#ifdef GLP_DEBUG
+ xprintf("N");
+#endif
+ return 0;
+ }
+ else if (ret == 1)
+ { /* dual infeasibility */
+ return GLP_ENODFS;
+ }
+ else
+ xassert(ret != ret);
+ }
+ if (col->ptr->c_next == NULL)
+ { /* column singleton */
+ row = col->ptr->row;
+ if (row->lb == row->ub)
+ { /* equality constraint */
+ if (!col->is_int)
+slack: { /* implied slack variable */
+#ifdef GLP_DEBUG
+ xprintf("O");
+#endif
+ npp_implied_slack(npp, col);
+ /* column was deleted */
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ { /* row became free due to implied slack variable */
+#ifdef GLP_DEBUG
+ xprintf("P");
+#endif
+ /* activate columns affected by row */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_activate_col(npp, aij->col);
+ /* process free row */
+ npp_free_row(npp, row);
+ /* row was deleted */
+ }
+ else
+ { /* row became inequality constraint; activate it
+ since its length changed due to column deletion */
+ npp_activate_row(npp, row);
+ }
+ return 0;
+ }
+ }
+ else
+ { /* inequality constraint */
+ if (!col->is_int)
+ { ret = npp_implied_free(npp, col);
+ if (ret == 0)
+ { /* implied free variable */
+#ifdef GLP_DEBUG
+ xprintf("Q");
+#endif
+ /* column bounds were removed, row was replaced by
+ equality constraint */
+ goto slack;
+ }
+ else if (ret == 1)
+ { /* column is not implied free variable, because its
+ lower and/or upper bounds can be active */
+ }
+ else if (ret == 2)
+ { /* dual infeasibility */
+ return GLP_ENODFS;
+ }
+ }
+ }
+ }
+ /* column still exists */
+ return 0;
+}
+
+/***********************************************************************
+* NAME
+*
+* npp_process_prob - perform basic LP/MIP processing
+*
+* SYNOPSIS
+*
+* #include "glpnpp.h"
+* int npp_process_prob(NPP *npp, int hard);
+*
+* DESCRIPTION
+*
+* The routine npp_process_prob performs basic LP/MIP processing that
+* currently includes:
+*
+* 1) initial LP/MIP processing (see the routine npp_clean_prob),
+*
+* 2) basic row processing (see the routine npp_process_row), and
+*
+* 3) basic column processing (see the routine npp_process_col).
+*
+* If the flag hard is on, the routine attempts to improve current
+* column bounds multiple times within the main processing loop, in
+* which case this feature may take a time. Otherwise, if the flag hard
+* is off, improving column bounds is performed only once at the end of
+* the main loop. (Note that this feature is used for MIP only.)
+*
+* The routine uses two sets: the set of active rows and the set of
+* active columns. Rows/columns are marked by a flag (the field temp in
+* NPPROW/NPPCOL). If the flag is non-zero, the row/column is active,
+* in which case it is placed in the beginning of the row/column list;
+* otherwise, if the flag is zero, the row/column is inactive, in which
+* case it is placed in the end of the row/column list. If a row/column
+* being currently processed may affect other rows/columns, the latters
+* are activated for further processing.
+*
+* RETURNS
+*
+* 0 success;
+*
+* GLP_ENOPFS primal/integer infeasibility detected;
+*
+* GLP_ENODFS dual infeasibility detected. */
+
+int npp_process_prob(NPP *npp, int hard)
+{ /* perform basic LP/MIP processing */
+ NPPROW *row;
+ NPPCOL *col;
+ int processing, ret;
+ /* perform initial LP/MIP processing */
+ npp_clean_prob(npp);
+ /* activate all remaining rows and columns */
+ for (row = npp->r_head; row != NULL; row = row->next)
+ row->temp = 1;
+ for (col = npp->c_head; col != NULL; col = col->next)
+ col->temp = 1;
+ /* main processing loop */
+ processing = 1;
+ while (processing)
+ { processing = 0;
+ /* process all active rows */
+ for (;;)
+ { row = npp->r_head;
+ if (row == NULL || !row->temp) break;
+ npp_deactivate_row(npp, row);
+ ret = npp_process_row(npp, row, hard);
+ if (ret != 0) goto done;
+ processing = 1;
+ }
+ /* process all active columns */
+ for (;;)
+ { col = npp->c_head;
+ if (col == NULL || !col->temp) break;
+ npp_deactivate_col(npp, col);
+ ret = npp_process_col(npp, col);
+ if (ret != 0) goto done;
+ processing = 1;
+ }
+ }
+#if 1 /* 23/XII-2009 */
+ if (npp->sol == GLP_MIP && !hard)
+ { /* improve current column bounds (optional) */
+ for (row = npp->r_head; row != NULL; row = row->next)
+ { if (npp_improve_bounds(npp, row, 0) < 0)
+ { ret = GLP_ENOPFS;
+ goto done;
+ }
+ }
+ }
+#endif
+ /* all seems ok */
+ ret = 0;
+done: xassert(ret == 0 || ret == GLP_ENOPFS || ret == GLP_ENODFS);
+#ifdef GLP_DEBUG
+ xprintf("\n");
+#endif
+ return ret;
+}
+
+/**********************************************************************/
+
+int npp_simplex(NPP *npp, const glp_smcp *parm)
+{ /* process LP prior to applying primal/dual simplex method */
+ int ret;
+ xassert(npp->sol == GLP_SOL);
+ xassert(parm == parm);
+ ret = npp_process_prob(npp, 0);
+ return ret;
+}
+
+/**********************************************************************/
+
+int npp_integer(NPP *npp, const glp_iocp *parm)
+{ /* process MIP prior to applying branch-and-bound method */
+ NPPROW *row, *prev_row;
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int count, ret;
+ xassert(npp->sol == GLP_MIP);
+ xassert(parm == parm);
+ /*==============================================================*/
+ /* perform basic MIP processing */
+ ret = npp_process_prob(npp, 1);
+ if (ret != 0) goto done;
+ /*==============================================================*/
+ /* binarize problem, if required */
+ if (parm->binarize)
+ npp_binarize_prob(npp);
+ /*==============================================================*/
+ /* identify hidden packing inequalities */
+ count = 0;
+ /* new rows will be added to the end of the row list, so we go
+ from the end to beginning of the row list */
+ for (row = npp->r_tail; row != NULL; row = prev_row)
+ { prev_row = row->prev;
+ /* skip free row */
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
+ /* skip equality constraint */
+ if (row->lb == row->ub) continue;
+ /* skip row having less than two variables */
+ if (row->ptr == NULL || row->ptr->r_next == NULL) continue;
+ /* skip row having non-binary variables */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ break;
+ }
+ if (aij != NULL) continue;
+ count += npp_hidden_packing(npp, row);
+ }
+ if (count > 0)
+ xprintf("%d hidden packing inequaliti(es) were detected\n",
+ count);
+ /*==============================================================*/
+ /* identify hidden covering inequalities */
+ count = 0;
+ /* new rows will be added to the end of the row list, so we go
+ from the end to beginning of the row list */
+ for (row = npp->r_tail; row != NULL; row = prev_row)
+ { prev_row = row->prev;
+ /* skip free row */
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
+ /* skip equality constraint */
+ if (row->lb == row->ub) continue;
+ /* skip row having less than three variables */
+ if (row->ptr == NULL || row->ptr->r_next == NULL ||
+ row->ptr->r_next->r_next == NULL) continue;
+ /* skip row having non-binary variables */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ break;
+ }
+ if (aij != NULL) continue;
+ count += npp_hidden_covering(npp, row);
+ }
+ if (count > 0)
+ xprintf("%d hidden covering inequaliti(es) were detected\n",
+ count);
+ /*==============================================================*/
+ /* reduce inequality constraint coefficients */
+ count = 0;
+ /* new rows will be added to the end of the row list, so we go
+ from the end to beginning of the row list */
+ for (row = npp->r_tail; row != NULL; row = prev_row)
+ { prev_row = row->prev;
+ /* skip equality constraint */
+ if (row->lb == row->ub) continue;
+ count += npp_reduce_ineq_coef(npp, row);
+ }
+ if (count > 0)
+ xprintf("%d constraint coefficient(s) were reduced\n", count);
+ /*==============================================================*/
+#ifdef GLP_DEBUG
+ routine(npp);
+#endif
+ /*==============================================================*/
+ /* all seems ok */
+ ret = 0;
+done: return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/npp/npp6.c b/test/monniaux/glpk-4.65/src/npp/npp6.c
new file mode 100644
index 00000000..b57f8615
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/npp/npp6.c
@@ -0,0 +1,1500 @@
+/* npp6.c (translate feasibility problem to CNF-SAT) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2011-2017 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "npp.h"
+
+/***********************************************************************
+* npp_sat_free_row - process free (unbounded) row
+*
+* This routine processes row p, which is free (i.e. has no finite
+* bounds):
+*
+* -inf < sum a[p,j] x[j] < +inf. (1)
+*
+* The constraint (1) cannot be active and therefore it is redundant,
+* so the routine simply removes it from the original problem. */
+
+void npp_sat_free_row(NPP *npp, NPPROW *p)
+{ /* the row should be free */
+ xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
+ /* remove the row from the problem */
+ npp_del_row(npp, p);
+ return;
+}
+
+/***********************************************************************
+* npp_sat_fixed_col - process fixed column
+*
+* This routine processes column q, which is fixed:
+*
+* x[q] = s[q], (1)
+*
+* where s[q] is a fixed column value.
+*
+* The routine substitutes fixed value s[q] into constraint rows and
+* then removes column x[q] from the original problem.
+*
+* Substitution of x[q] = s[q] into row i gives:
+*
+* L[i] <= sum a[i,j] x[j] <= U[i] ==>
+* j
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
+* j!=q
+*
+* L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==>
+* j!=q
+*
+* L~[i] <= sum a[i,j] x[j] <= U~[i],
+* j!=q
+*
+* where
+*
+* L~[i] = L[i] - a[i,q] s[q], (2)
+*
+* U~[i] = U[i] - a[i,q] s[q] (3)
+*
+* are, respectively, lower and upper bound of row i in the transformed
+* problem.
+*
+* On recovering solution x[q] is assigned the value of s[q]. */
+
+struct sat_fixed_col
+{ /* fixed column */
+ int q;
+ /* column reference number for variable x[q] */
+ int s;
+ /* value, at which x[q] is fixed */
+};
+
+static int rcv_sat_fixed_col(NPP *, void *);
+
+int npp_sat_fixed_col(NPP *npp, NPPCOL *q)
+{ struct sat_fixed_col *info;
+ NPPROW *i;
+ NPPAIJ *aij;
+ int temp;
+ /* the column should be fixed */
+ xassert(q->lb == q->ub);
+ /* create transformation stack entry */
+ info = npp_push_tse(npp,
+ rcv_sat_fixed_col, sizeof(struct sat_fixed_col));
+ info->q = q->j;
+ info->s = (int)q->lb;
+ xassert((double)info->s == q->lb);
+ /* substitute x[q] = s[q] into constraint rows */
+ if (info->s == 0)
+ goto skip;
+ for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+ { i = aij->row;
+ if (i->lb != -DBL_MAX)
+ { i->lb -= aij->val * (double)info->s;
+ temp = (int)i->lb;
+ if ((double)temp != i->lb)
+ return 1; /* integer arithmetic error */
+ }
+ if (i->ub != +DBL_MAX)
+ { i->ub -= aij->val * (double)info->s;
+ temp = (int)i->ub;
+ if ((double)temp != i->ub)
+ return 2; /* integer arithmetic error */
+ }
+ }
+skip: /* remove the column from the problem */
+ npp_del_col(npp, q);
+ return 0;
+}
+
+static int rcv_sat_fixed_col(NPP *npp, void *info_)
+{ struct sat_fixed_col *info = info_;
+ npp->c_value[info->q] = (double)info->s;
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_is_bin_comb - test if row is binary combination
+*
+* This routine tests if the specified row is a binary combination,
+* i.e. all its constraint coefficients are +1 and -1 and all variables
+* are binary. If the test was passed, the routine returns non-zero,
+* otherwise zero. */
+
+int npp_sat_is_bin_comb(NPP *npp, NPPROW *row)
+{ NPPCOL *col;
+ NPPAIJ *aij;
+ xassert(npp == npp);
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { if (!(aij->val == +1.0 || aij->val == -1.0))
+ return 0; /* non-unity coefficient */
+ col = aij->col;
+ if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+ return 0; /* non-binary column */
+ }
+ return 1; /* test was passed */
+}
+
+/***********************************************************************
+* npp_sat_num_pos_coef - determine number of positive coefficients
+*
+* This routine returns the number of positive coefficients in the
+* specified row. */
+
+int npp_sat_num_pos_coef(NPP *npp, NPPROW *row)
+{ NPPAIJ *aij;
+ int num = 0;
+ xassert(npp == npp);
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->val > 0.0)
+ num++;
+ }
+ return num;
+}
+
+/***********************************************************************
+* npp_sat_num_neg_coef - determine number of negative coefficients
+*
+* This routine returns the number of negative coefficients in the
+* specified row. */
+
+int npp_sat_num_neg_coef(NPP *npp, NPPROW *row)
+{ NPPAIJ *aij;
+ int num = 0;
+ xassert(npp == npp);
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->val < 0.0)
+ num++;
+ }
+ return num;
+}
+
+/***********************************************************************
+* npp_sat_is_cover_ineq - test if row is covering inequality
+*
+* The canonical form of a covering inequality is the following:
+*
+* sum x[j] >= 1, (1)
+* j in J
+*
+* where all x[j] are binary variables.
+*
+* In general case a covering inequality may have one of the following
+* two forms:
+*
+* sum x[j] - sum x[j] >= 1 - |J-|, (2)
+* j in J+ j in J-
+*
+*
+* sum x[j] - sum x[j] <= |J+| - 1. (3)
+* j in J+ j in J-
+*
+* Obviously, the inequality (2) can be transformed to the form (1) by
+* substitution x[j] = 1 - x'[j] for all j in J-, where x'[j] is the
+* negation of variable x[j]. And the inequality (3) can be transformed
+* to (2) by multiplying both left- and right-hand sides by -1.
+*
+* This routine returns one of the following codes:
+*
+* 0, if the specified row is not a covering inequality;
+*
+* 1, if the specified row has the form (2);
+*
+* 2, if the specified row has the form (3). */
+
+int npp_sat_is_cover_ineq(NPP *npp, NPPROW *row)
+{ xassert(npp == npp);
+ if (row->lb != -DBL_MAX && row->ub == +DBL_MAX)
+ { /* row is inequality of '>=' type */
+ if (npp_sat_is_bin_comb(npp, row))
+ { /* row is a binary combination */
+ if (row->lb == 1.0 - npp_sat_num_neg_coef(npp, row))
+ { /* row has the form (2) */
+ return 1;
+ }
+ }
+ }
+ else if (row->lb == -DBL_MAX && row->ub != +DBL_MAX)
+ { /* row is inequality of '<=' type */
+ if (npp_sat_is_bin_comb(npp, row))
+ { /* row is a binary combination */
+ if (row->ub == npp_sat_num_pos_coef(npp, row) - 1.0)
+ { /* row has the form (3) */
+ return 2;
+ }
+ }
+ }
+ /* row is not a covering inequality */
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_is_pack_ineq - test if row is packing inequality
+*
+* The canonical form of a packing inequality is the following:
+*
+* sum x[j] <= 1, (1)
+* j in J
+*
+* where all x[j] are binary variables.
+*
+* In general case a packing inequality may have one of the following
+* two forms:
+*
+* sum x[j] - sum x[j] <= 1 - |J-|, (2)
+* j in J+ j in J-
+*
+*
+* sum x[j] - sum x[j] >= |J+| - 1. (3)
+* j in J+ j in J-
+*
+* Obviously, the inequality (2) can be transformed to the form (1) by
+* substitution x[j] = 1 - x'[j] for all j in J-, where x'[j] is the
+* negation of variable x[j]. And the inequality (3) can be transformed
+* to (2) by multiplying both left- and right-hand sides by -1.
+*
+* This routine returns one of the following codes:
+*
+* 0, if the specified row is not a packing inequality;
+*
+* 1, if the specified row has the form (2);
+*
+* 2, if the specified row has the form (3). */
+
+int npp_sat_is_pack_ineq(NPP *npp, NPPROW *row)
+{ xassert(npp == npp);
+ if (row->lb == -DBL_MAX && row->ub != +DBL_MAX)
+ { /* row is inequality of '<=' type */
+ if (npp_sat_is_bin_comb(npp, row))
+ { /* row is a binary combination */
+ if (row->ub == 1.0 - npp_sat_num_neg_coef(npp, row))
+ { /* row has the form (2) */
+ return 1;
+ }
+ }
+ }
+ else if (row->lb != -DBL_MAX && row->ub == +DBL_MAX)
+ { /* row is inequality of '>=' type */
+ if (npp_sat_is_bin_comb(npp, row))
+ { /* row is a binary combination */
+ if (row->lb == npp_sat_num_pos_coef(npp, row) - 1.0)
+ { /* row has the form (3) */
+ return 2;
+ }
+ }
+ }
+ /* row is not a packing inequality */
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_is_partn_eq - test if row is partitioning equality
+*
+* The canonical form of a partitioning equality is the following:
+*
+* sum x[j] = 1, (1)
+* j in J
+*
+* where all x[j] are binary variables.
+*
+* In general case a partitioning equality may have one of the following
+* two forms:
+*
+* sum x[j] - sum x[j] = 1 - |J-|, (2)
+* j in J+ j in J-
+*
+*
+* sum x[j] - sum x[j] = |J+| - 1. (3)
+* j in J+ j in J-
+*
+* Obviously, the equality (2) can be transformed to the form (1) by
+* substitution x[j] = 1 - x'[j] for all j in J-, where x'[j] is the
+* negation of variable x[j]. And the equality (3) can be transformed
+* to (2) by multiplying both left- and right-hand sides by -1.
+*
+* This routine returns one of the following codes:
+*
+* 0, if the specified row is not a partitioning equality;
+*
+* 1, if the specified row has the form (2);
+*
+* 2, if the specified row has the form (3). */
+
+int npp_sat_is_partn_eq(NPP *npp, NPPROW *row)
+{ xassert(npp == npp);
+ if (row->lb == row->ub)
+ { /* row is equality constraint */
+ if (npp_sat_is_bin_comb(npp, row))
+ { /* row is a binary combination */
+ if (row->lb == 1.0 - npp_sat_num_neg_coef(npp, row))
+ { /* row has the form (2) */
+ return 1;
+ }
+ if (row->ub == npp_sat_num_pos_coef(npp, row) - 1.0)
+ { /* row has the form (3) */
+ return 2;
+ }
+ }
+ }
+ /* row is not a partitioning equality */
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_reverse_row - multiply both sides of row by -1
+*
+* This routines multiplies by -1 both left- and right-hand sides of
+* the specified row:
+*
+* L <= sum x[j] <= U,
+*
+* that results in the following row:
+*
+* -U <= sum (-x[j]) <= -L.
+*
+* If no integer overflow occured, the routine returns zero, otherwise
+* non-zero. */
+
+int npp_sat_reverse_row(NPP *npp, NPPROW *row)
+{ NPPAIJ *aij;
+ int temp, ret = 0;
+ double old_lb, old_ub;
+ xassert(npp == npp);
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { aij->val = -aij->val;
+ temp = (int)aij->val;
+ if ((double)temp != aij->val)
+ ret = 1;
+ }
+ old_lb = row->lb, old_ub = row->ub;
+ if (old_ub == +DBL_MAX)
+ row->lb = -DBL_MAX;
+ else
+ { row->lb = -old_ub;
+ temp = (int)row->lb;
+ if ((double)temp != row->lb)
+ ret = 2;
+ }
+ if (old_lb == -DBL_MAX)
+ row->ub = +DBL_MAX;
+ else
+ { row->ub = -old_lb;
+ temp = (int)row->ub;
+ if ((double)temp != row->ub)
+ ret = 3;
+ }
+ return ret;
+}
+
+/***********************************************************************
+* npp_sat_split_pack - split packing inequality
+*
+* Let there be given a packing inequality in canonical form:
+*
+* sum t[j] <= 1, (1)
+* j in J
+*
+* where t[j] = x[j] or t[j] = 1 - x[j], x[j] is a binary variable.
+* And let J = J1 U J2 is a partition of the set of literals. Then the
+* inequality (1) is obviously equivalent to the following two packing
+* inequalities:
+*
+* sum t[j] <= y <--> sum t[j] + (1 - y) <= 1, (2)
+* j in J1 j in J1
+*
+* sum t[j] <= 1 - y <--> sum t[j] + y <= 1, (3)
+* j in J2 j in J2
+*
+* where y is a new binary variable added to the transformed problem.
+*
+* Assuming that the specified row is a packing inequality (1), this
+* routine constructs the set J1 by including there first nlit literals
+* (terms) from the specified row, and the set J2 = J \ J1. Then the
+* routine creates a new row, which corresponds to inequality (2), and
+* replaces the specified row with inequality (3). */
+
+NPPROW *npp_sat_split_pack(NPP *npp, NPPROW *row, int nlit)
+{ NPPROW *rrr;
+ NPPCOL *col;
+ NPPAIJ *aij;
+ int k;
+ /* original row should be packing inequality (1) */
+ xassert(npp_sat_is_pack_ineq(npp, row) == 1);
+ /* and nlit should be less than the number of literals (terms)
+ in the original row */
+ xassert(0 < nlit && nlit < npp_row_nnz(npp, row));
+ /* create new row corresponding to inequality (2) */
+ rrr = npp_add_row(npp);
+ rrr->lb = -DBL_MAX, rrr->ub = 1.0;
+ /* move first nlit literals (terms) from the original row to the
+ new row; the original row becomes inequality (3) */
+ for (k = 1; k <= nlit; k++)
+ { aij = row->ptr;
+ xassert(aij != NULL);
+ /* add literal to the new row */
+ npp_add_aij(npp, rrr, aij->col, aij->val);
+ /* correct rhs */
+ if (aij->val < 0.0)
+ rrr->ub -= 1.0, row->ub += 1.0;
+ /* remove literal from the original row */
+ npp_del_aij(npp, aij);
+ }
+ /* create new binary variable y */
+ col = npp_add_col(npp);
+ col->is_int = 1, col->lb = 0.0, col->ub = 1.0;
+ /* include literal (1 - y) in the new row */
+ npp_add_aij(npp, rrr, col, -1.0);
+ rrr->ub -= 1.0;
+ /* include literal y in the original row */
+ npp_add_aij(npp, row, col, +1.0);
+ return rrr;
+}
+
+/***********************************************************************
+* npp_sat_encode_pack - encode packing inequality
+*
+* Given a packing inequality in canonical form:
+*
+* sum t[j] <= 1, (1)
+* j in J
+*
+* where t[j] = x[j] or t[j] = 1 - x[j], x[j] is a binary variable,
+* this routine translates it to CNF by replacing it with the following
+* equivalent set of edge packing inequalities:
+*
+* t[j] + t[k] <= 1 for all j, k in J, j != k. (2)
+*
+* Then the routine transforms each edge packing inequality (2) to
+* corresponding covering inequality (that encodes two-literal clause)
+* by multiplying both its part by -1:
+*
+* - t[j] - t[k] >= -1 <--> (1 - t[j]) + (1 - t[k]) >= 1. (3)
+*
+* On exit the routine removes the original row from the problem. */
+
+void npp_sat_encode_pack(NPP *npp, NPPROW *row)
+{ NPPROW *rrr;
+ NPPAIJ *aij, *aik;
+ /* original row should be packing inequality (1) */
+ xassert(npp_sat_is_pack_ineq(npp, row) == 1);
+ /* create equivalent system of covering inequalities (3) */
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { /* due to symmetry only one of inequalities t[j] + t[k] <= 1
+ and t[k] <= t[j] <= 1 can be considered */
+ for (aik = aij->r_next; aik != NULL; aik = aik->r_next)
+ { /* create edge packing inequality (2) */
+ rrr = npp_add_row(npp);
+ rrr->lb = -DBL_MAX, rrr->ub = 1.0;
+ npp_add_aij(npp, rrr, aij->col, aij->val);
+ if (aij->val < 0.0)
+ rrr->ub -= 1.0;
+ npp_add_aij(npp, rrr, aik->col, aik->val);
+ if (aik->val < 0.0)
+ rrr->ub -= 1.0;
+ /* and transform it to covering inequality (3) */
+ npp_sat_reverse_row(npp, rrr);
+ xassert(npp_sat_is_cover_ineq(npp, rrr) == 1);
+ }
+ }
+ /* remove the original row from the problem */
+ npp_del_row(npp, row);
+ return;
+}
+
+/***********************************************************************
+* npp_sat_encode_sum2 - encode 2-bit summation
+*
+* Given a set containing two literals x and y this routine encodes
+* the equality
+*
+* x + y = s + 2 * c, (1)
+*
+* where
+*
+* s = (x + y) % 2 (2)
+*
+* is a binary variable modeling the low sum bit, and
+*
+* c = (x + y) / 2 (3)
+*
+* is a binary variable modeling the high (carry) sum bit. */
+
+void npp_sat_encode_sum2(NPP *npp, NPPLSE *set, NPPSED *sed)
+{ NPPROW *row;
+ int x, y, s, c;
+ /* the set should contain exactly two literals */
+ xassert(set != NULL);
+ xassert(set->next != NULL);
+ xassert(set->next->next == NULL);
+ sed->x = set->lit;
+ xassert(sed->x.neg == 0 || sed->x.neg == 1);
+ sed->y = set->next->lit;
+ xassert(sed->y.neg == 0 || sed->y.neg == 1);
+ sed->z.col = NULL, sed->z.neg = 0;
+ /* perform encoding s = (x + y) % 2 */
+ sed->s = npp_add_col(npp);
+ sed->s->is_int = 1, sed->s->lb = 0.0, sed->s->ub = 1.0;
+ for (x = 0; x <= 1; x++)
+ { for (y = 0; y <= 1; y++)
+ { for (s = 0; s <= 1; s++)
+ { if ((x + y) % 2 != s)
+ { /* generate CNF clause to disable infeasible
+ combination */
+ row = npp_add_row(npp);
+ row->lb = 1.0, row->ub = +DBL_MAX;
+ if (x == sed->x.neg)
+ npp_add_aij(npp, row, sed->x.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->x.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (y == sed->y.neg)
+ npp_add_aij(npp, row, sed->y.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->y.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (s == 0)
+ npp_add_aij(npp, row, sed->s, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->s, -1.0);
+ row->lb -= 1.0;
+ }
+ }
+ }
+ }
+ }
+ /* perform encoding c = (x + y) / 2 */
+ sed->c = npp_add_col(npp);
+ sed->c->is_int = 1, sed->c->lb = 0.0, sed->c->ub = 1.0;
+ for (x = 0; x <= 1; x++)
+ { for (y = 0; y <= 1; y++)
+ { for (c = 0; c <= 1; c++)
+ { if ((x + y) / 2 != c)
+ { /* generate CNF clause to disable infeasible
+ combination */
+ row = npp_add_row(npp);
+ row->lb = 1.0, row->ub = +DBL_MAX;
+ if (x == sed->x.neg)
+ npp_add_aij(npp, row, sed->x.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->x.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (y == sed->y.neg)
+ npp_add_aij(npp, row, sed->y.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->y.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (c == 0)
+ npp_add_aij(npp, row, sed->c, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->c, -1.0);
+ row->lb -= 1.0;
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* npp_sat_encode_sum3 - encode 3-bit summation
+*
+* Given a set containing at least three literals this routine chooses
+* some literals x, y, z from that set and encodes the equality
+*
+* x + y + z = s + 2 * c, (1)
+*
+* where
+*
+* s = (x + y + z) % 2 (2)
+*
+* is a binary variable modeling the low sum bit, and
+*
+* c = (x + y + z) / 2 (3)
+*
+* is a binary variable modeling the high (carry) sum bit. */
+
+void npp_sat_encode_sum3(NPP *npp, NPPLSE *set, NPPSED *sed)
+{ NPPROW *row;
+ int x, y, z, s, c;
+ /* the set should contain at least three literals */
+ xassert(set != NULL);
+ xassert(set->next != NULL);
+ xassert(set->next->next != NULL);
+ sed->x = set->lit;
+ xassert(sed->x.neg == 0 || sed->x.neg == 1);
+ sed->y = set->next->lit;
+ xassert(sed->y.neg == 0 || sed->y.neg == 1);
+ sed->z = set->next->next->lit;
+ xassert(sed->z.neg == 0 || sed->z.neg == 1);
+ /* perform encoding s = (x + y + z) % 2 */
+ sed->s = npp_add_col(npp);
+ sed->s->is_int = 1, sed->s->lb = 0.0, sed->s->ub = 1.0;
+ for (x = 0; x <= 1; x++)
+ { for (y = 0; y <= 1; y++)
+ { for (z = 0; z <= 1; z++)
+ { for (s = 0; s <= 1; s++)
+ { if ((x + y + z) % 2 != s)
+ { /* generate CNF clause to disable infeasible
+ combination */
+ row = npp_add_row(npp);
+ row->lb = 1.0, row->ub = +DBL_MAX;
+ if (x == sed->x.neg)
+ npp_add_aij(npp, row, sed->x.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->x.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (y == sed->y.neg)
+ npp_add_aij(npp, row, sed->y.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->y.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (z == sed->z.neg)
+ npp_add_aij(npp, row, sed->z.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->z.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (s == 0)
+ npp_add_aij(npp, row, sed->s, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->s, -1.0);
+ row->lb -= 1.0;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* perform encoding c = (x + y + z) / 2 */
+ sed->c = npp_add_col(npp);
+ sed->c->is_int = 1, sed->c->lb = 0.0, sed->c->ub = 1.0;
+ for (x = 0; x <= 1; x++)
+ { for (y = 0; y <= 1; y++)
+ { for (z = 0; z <= 1; z++)
+ { for (c = 0; c <= 1; c++)
+ { if ((x + y + z) / 2 != c)
+ { /* generate CNF clause to disable infeasible
+ combination */
+ row = npp_add_row(npp);
+ row->lb = 1.0, row->ub = +DBL_MAX;
+ if (x == sed->x.neg)
+ npp_add_aij(npp, row, sed->x.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->x.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (y == sed->y.neg)
+ npp_add_aij(npp, row, sed->y.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->y.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (z == sed->z.neg)
+ npp_add_aij(npp, row, sed->z.col, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->z.col, -1.0);
+ row->lb -= 1.0;
+ }
+ if (c == 0)
+ npp_add_aij(npp, row, sed->c, +1.0);
+ else
+ { npp_add_aij(npp, row, sed->c, -1.0);
+ row->lb -= 1.0;
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* npp_sat_encode_sum_ax - encode linear combination of 0-1 variables
+*
+* PURPOSE
+*
+* Given a linear combination of binary variables:
+*
+* sum a[j] x[j], (1)
+* j
+*
+* which is the linear form of the specified row, this routine encodes
+* (i.e. translates to CNF) the following equality:
+*
+* n
+* sum |a[j]| t[j] = sum 2**(k-1) * y[k], (2)
+* j k=1
+*
+* where t[j] = x[j] (if a[j] > 0) or t[j] = 1 - x[j] (if a[j] < 0),
+* and y[k] is either t[j] or a new literal created by the routine or
+* a constant zero. Note that the sum in the right-hand side of (2) can
+* be thought as a n-bit representation of the sum in the left-hand
+* side, which is a non-negative integer number.
+*
+* ALGORITHM
+*
+* First, the number of bits, n, sufficient to represent any value in
+* the left-hand side of (2) is determined. Obviously, n is the number
+* of bits sufficient to represent the sum (sum |a[j]|).
+*
+* Let
+*
+* n
+* |a[j]| = sum 2**(k-1) b[j,k], (3)
+* k=1
+*
+* where b[j,k] is k-th bit in a n-bit representation of |a[j]|. Then
+*
+* m n
+* sum |a[j]| * t[j] = sum 2**(k-1) sum b[j,k] * t[j]. (4)
+* j k=1 j=1
+*
+* Introducing the set
+*
+* J[k] = { j : b[j,k] = 1 } (5)
+*
+* allows rewriting (4) as follows:
+*
+* n
+* sum |a[j]| * t[j] = sum 2**(k-1) sum t[j]. (6)
+* j k=1 j in J[k]
+*
+* Thus, our goal is to provide |J[k]| <= 1 for all k, in which case
+* we will have the representation (1).
+*
+* Let |J[k]| = 2, i.e. J[k] has exactly two literals u and v. In this
+* case we can apply the following transformation:
+*
+* u + v = s + 2 * c, (7)
+*
+* where s and c are, respectively, low (sum) and high (carry) bits of
+* the sum of two bits. This allows to replace two literals u and v in
+* J[k] by one literal s, and carry out literal c to J[k+1].
+*
+* If |J[k]| >= 3, i.e. J[k] has at least three literals u, v, and w,
+* we can apply the following transformation:
+*
+* u + v + w = s + 2 * c. (8)
+*
+* Again, literal s replaces literals u, v, and w in J[k], and literal
+* c goes into J[k+1].
+*
+* On exit the routine stores each literal from J[k] in element y[k],
+* 1 <= k <= n. If J[k] is empty, y[k] is set to constant false.
+*
+* RETURNS
+*
+* The routine returns n, the number of literals in the right-hand side
+* of (2), 0 <= n <= NBIT_MAX. If the sum (sum |a[j]|) is too large, so
+* more than NBIT_MAX (= 31) literals are needed to encode the original
+* linear combination, the routine returns a negative value. */
+
+#define NBIT_MAX 31
+/* maximal number of literals in the right hand-side of (2) */
+
+static NPPLSE *remove_lse(NPP *npp, NPPLSE *set, NPPCOL *col)
+{ /* remove specified literal from specified literal set */
+ NPPLSE *lse, *prev = NULL;
+ for (lse = set; lse != NULL; prev = lse, lse = lse->next)
+ if (lse->lit.col == col) break;
+ xassert(lse != NULL);
+ if (prev == NULL)
+ set = lse->next;
+ else
+ prev->next = lse->next;
+ dmp_free_atom(npp->pool, lse, sizeof(NPPLSE));
+ return set;
+}
+
+int npp_sat_encode_sum_ax(NPP *npp, NPPROW *row, NPPLIT y[])
+{ NPPAIJ *aij;
+ NPPLSE *set[1+NBIT_MAX], *lse;
+ NPPSED sed;
+ int k, n, temp;
+ double sum;
+ /* compute the sum (sum |a[j]|) */
+ sum = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ sum += fabs(aij->val);
+ /* determine n, the number of bits in the sum */
+ temp = (int)sum;
+ if ((double)temp != sum)
+ return -1; /* integer arithmetic error */
+ for (n = 0; temp > 0; n++, temp >>= 1);
+ xassert(0 <= n && n <= NBIT_MAX);
+ /* build initial sets J[k], 1 <= k <= n; see (5) */
+ /* set[k] is a pointer to the list of literals in J[k] */
+ for (k = 1; k <= n; k++)
+ set[k] = NULL;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { temp = (int)fabs(aij->val);
+ xassert((int)temp == fabs(aij->val));
+ for (k = 1; temp > 0; k++, temp >>= 1)
+ { if (temp & 1)
+ { xassert(k <= n);
+ lse = dmp_get_atom(npp->pool, sizeof(NPPLSE));
+ lse->lit.col = aij->col;
+ lse->lit.neg = (aij->val > 0.0 ? 0 : 1);
+ lse->next = set[k];
+ set[k] = lse;
+ }
+ }
+ }
+ /* main transformation loop */
+ for (k = 1; k <= n; k++)
+ { /* reduce J[k] and set y[k] */
+ for (;;)
+ { if (set[k] == NULL)
+ { /* J[k] is empty */
+ /* set y[k] to constant false */
+ y[k].col = NULL, y[k].neg = 0;
+ break;
+ }
+ if (set[k]->next == NULL)
+ { /* J[k] contains one literal */
+ /* set y[k] to that literal */
+ y[k] = set[k]->lit;
+ dmp_free_atom(npp->pool, set[k], sizeof(NPPLSE));
+ break;
+ }
+ if (set[k]->next->next == NULL)
+ { /* J[k] contains two literals */
+ /* apply transformation (7) */
+ npp_sat_encode_sum2(npp, set[k], &sed);
+ }
+ else
+ { /* J[k] contains at least three literals */
+ /* apply transformation (8) */
+ npp_sat_encode_sum3(npp, set[k], &sed);
+ /* remove third literal from set[k] */
+ set[k] = remove_lse(npp, set[k], sed.z.col);
+ }
+ /* remove second literal from set[k] */
+ set[k] = remove_lse(npp, set[k], sed.y.col);
+ /* remove first literal from set[k] */
+ set[k] = remove_lse(npp, set[k], sed.x.col);
+ /* include new literal s to set[k] */
+ lse = dmp_get_atom(npp->pool, sizeof(NPPLSE));
+ lse->lit.col = sed.s, lse->lit.neg = 0;
+ lse->next = set[k];
+ set[k] = lse;
+ /* include new literal c to set[k+1] */
+ xassert(k < n); /* FIXME: can "overflow" happen? */
+ lse = dmp_get_atom(npp->pool, sizeof(NPPLSE));
+ lse->lit.col = sed.c, lse->lit.neg = 0;
+ lse->next = set[k+1];
+ set[k+1] = lse;
+ }
+ }
+ return n;
+}
+
+/***********************************************************************
+* npp_sat_normalize_clause - normalize clause
+*
+* This routine normalizes the specified clause, which is a disjunction
+* of literals, by replacing multiple literals, which refer to the same
+* binary variable, with a single literal.
+*
+* On exit the routine returns the number of literals in the resulting
+* clause. However, if the specified clause includes both a literal and
+* its negation, the routine returns a negative value meaning that the
+* clause is equivalent to the value true. */
+
+int npp_sat_normalize_clause(NPP *npp, int size, NPPLIT lit[])
+{ int j, k, new_size;
+ xassert(npp == npp);
+ xassert(size >= 0);
+ new_size = 0;
+ for (k = 1; k <= size; k++)
+ { for (j = 1; j <= new_size; j++)
+ { if (lit[k].col == lit[j].col)
+ { /* lit[k] refers to the same variable as lit[j], which
+ is already included in the resulting clause */
+ if (lit[k].neg == lit[j].neg)
+ { /* ignore lit[k] due to the idempotent law */
+ goto skip;
+ }
+ else
+ { /* lit[k] is NOT lit[j]; the clause is equivalent to
+ the value true */
+ return -1;
+ }
+ }
+ }
+ /* include lit[k] in the resulting clause */
+ lit[++new_size] = lit[k];
+skip: ;
+ }
+ return new_size;
+}
+
+/***********************************************************************
+* npp_sat_encode_clause - translate clause to cover inequality
+*
+* Given a clause
+*
+* OR t[j], (1)
+* j in J
+*
+* where t[j] is a literal, i.e. t[j] = x[j] or t[j] = NOT x[j], this
+* routine translates it to the following equivalent cover inequality,
+* which is added to the transformed problem:
+*
+* sum t[j] >= 1, (2)
+* j in J
+*
+* where t[j] = x[j] or t[j] = 1 - x[j].
+*
+* If necessary, the clause should be normalized before a call to this
+* routine. */
+
+NPPROW *npp_sat_encode_clause(NPP *npp, int size, NPPLIT lit[])
+{ NPPROW *row;
+ int k;
+ xassert(size >= 1);
+ row = npp_add_row(npp);
+ row->lb = 1.0, row->ub = +DBL_MAX;
+ for (k = 1; k <= size; k++)
+ { xassert(lit[k].col != NULL);
+ if (lit[k].neg == 0)
+ npp_add_aij(npp, row, lit[k].col, +1.0);
+ else if (lit[k].neg == 1)
+ { npp_add_aij(npp, row, lit[k].col, -1.0);
+ row->lb -= 1.0;
+ }
+ else
+ xassert(lit != lit);
+ }
+ return row;
+}
+
+/***********************************************************************
+* npp_sat_encode_geq - encode "not less than" constraint
+*
+* PURPOSE
+*
+* This routine translates to CNF the following constraint:
+*
+* n
+* sum 2**(k-1) * y[k] >= b, (1)
+* k=1
+*
+* where y[k] is either a literal (i.e. y[k] = x[k] or y[k] = 1 - x[k])
+* or constant false (zero), b is a given lower bound.
+*
+* ALGORITHM
+*
+* If b < 0, the constraint is redundant, so assume that b >= 0. Let
+*
+* n
+* b = sum 2**(k-1) b[k], (2)
+* k=1
+*
+* where b[k] is k-th binary digit of b. (Note that if b >= 2**n and
+* therefore cannot be represented in the form (2), the constraint (1)
+* is infeasible.) In this case the condition (1) is equivalent to the
+* following condition:
+*
+* y[n] y[n-1] ... y[2] y[1] >= b[n] b[n-1] ... b[2] b[1], (3)
+*
+* where ">=" is understood lexicographically.
+*
+* Algorithmically the condition (3) can be tested as follows:
+*
+* for (k = n; k >= 1; k--)
+* { if (y[k] < b[k])
+* y is less than b;
+* if (y[k] > b[k])
+* y is greater than b;
+* }
+* y is equal to b;
+*
+* Thus, y is less than b iff there exists k, 1 <= k <= n, for which
+* the following condition is satisfied:
+*
+* y[n] = b[n] AND ... AND y[k+1] = b[k+1] AND y[k] < b[k]. (4)
+*
+* Negating the condition (4) we have that y is not less than b iff for
+* all k, 1 <= k <= n, the following condition is satisfied:
+*
+* y[n] != b[n] OR ... OR y[k+1] != b[k+1] OR y[k] >= b[k]. (5)
+*
+* Note that if b[k] = 0, the literal y[k] >= b[k] is always true, in
+* which case the entire clause (5) is true and can be omitted.
+*
+* RETURNS
+*
+* Normally the routine returns zero. However, if the constraint (1) is
+* infeasible, the routine returns non-zero. */
+
+int npp_sat_encode_geq(NPP *npp, int n, NPPLIT y[], int rhs)
+{ NPPLIT lit[1+NBIT_MAX];
+ int j, k, size, temp, b[1+NBIT_MAX];
+ xassert(0 <= n && n <= NBIT_MAX);
+ /* if the constraint (1) is redundant, do nothing */
+ if (rhs < 0)
+ return 0;
+ /* determine binary digits of b according to (2) */
+ for (k = 1, temp = rhs; k <= n; k++, temp >>= 1)
+ b[k] = temp & 1;
+ if (temp != 0)
+ { /* b >= 2**n; the constraint (1) is infeasible */
+ return 1;
+ }
+ /* main transformation loop */
+ for (k = 1; k <= n; k++)
+ { /* build the clause (5) for current k */
+ size = 0; /* clause size = number of literals */
+ /* add literal y[k] >= b[k] */
+ if (b[k] == 0)
+ { /* b[k] = 0 -> the literal is true */
+ goto skip;
+ }
+ else if (y[k].col == NULL)
+ { /* y[k] = 0, b[k] = 1 -> the literal is false */
+ xassert(y[k].neg == 0);
+ }
+ else
+ { /* add literal y[k] = 1 */
+ lit[++size] = y[k];
+ }
+ for (j = k+1; j <= n; j++)
+ { /* add literal y[j] != b[j] */
+ if (y[j].col == NULL)
+ { xassert(y[j].neg == 0);
+ if (b[j] == 0)
+ { /* y[j] = 0, b[j] = 0 -> the literal is false */
+ continue;
+ }
+ else
+ { /* y[j] = 0, b[j] = 1 -> the literal is true */
+ goto skip;
+ }
+ }
+ else
+ { lit[++size] = y[j];
+ if (b[j] != 0)
+ lit[size].neg = 1 - lit[size].neg;
+ }
+ }
+ /* normalize the clause */
+ size = npp_sat_normalize_clause(npp, size, lit);
+ if (size < 0)
+ { /* the clause is equivalent to the value true */
+ goto skip;
+ }
+ if (size == 0)
+ { /* the clause is equivalent to the value false; this means
+ that the constraint (1) is infeasible */
+ return 2;
+ }
+ /* translate the clause to corresponding cover inequality */
+ npp_sat_encode_clause(npp, size, lit);
+skip: ;
+ }
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_encode_leq - encode "not greater than" constraint
+*
+* PURPOSE
+*
+* This routine translates to CNF the following constraint:
+*
+* n
+* sum 2**(k-1) * y[k] <= b, (1)
+* k=1
+*
+* where y[k] is either a literal (i.e. y[k] = x[k] or y[k] = 1 - x[k])
+* or constant false (zero), b is a given upper bound.
+*
+* ALGORITHM
+*
+* If b < 0, the constraint is infeasible, so assume that b >= 0. Let
+*
+* n
+* b = sum 2**(k-1) b[k], (2)
+* k=1
+*
+* where b[k] is k-th binary digit of b. (Note that if b >= 2**n and
+* therefore cannot be represented in the form (2), the constraint (1)
+* is redundant.) In this case the condition (1) is equivalent to the
+* following condition:
+*
+* y[n] y[n-1] ... y[2] y[1] <= b[n] b[n-1] ... b[2] b[1], (3)
+*
+* where "<=" is understood lexicographically.
+*
+* Algorithmically the condition (3) can be tested as follows:
+*
+* for (k = n; k >= 1; k--)
+* { if (y[k] < b[k])
+* y is less than b;
+* if (y[k] > b[k])
+* y is greater than b;
+* }
+* y is equal to b;
+*
+* Thus, y is greater than b iff there exists k, 1 <= k <= n, for which
+* the following condition is satisfied:
+*
+* y[n] = b[n] AND ... AND y[k+1] = b[k+1] AND y[k] > b[k]. (4)
+*
+* Negating the condition (4) we have that y is not greater than b iff
+* for all k, 1 <= k <= n, the following condition is satisfied:
+*
+* y[n] != b[n] OR ... OR y[k+1] != b[k+1] OR y[k] <= b[k]. (5)
+*
+* Note that if b[k] = 1, the literal y[k] <= b[k] is always true, in
+* which case the entire clause (5) is true and can be omitted.
+*
+* RETURNS
+*
+* Normally the routine returns zero. However, if the constraint (1) is
+* infeasible, the routine returns non-zero. */
+
+int npp_sat_encode_leq(NPP *npp, int n, NPPLIT y[], int rhs)
+{ NPPLIT lit[1+NBIT_MAX];
+ int j, k, size, temp, b[1+NBIT_MAX];
+ xassert(0 <= n && n <= NBIT_MAX);
+ /* check if the constraint (1) is infeasible */
+ if (rhs < 0)
+ return 1;
+ /* determine binary digits of b according to (2) */
+ for (k = 1, temp = rhs; k <= n; k++, temp >>= 1)
+ b[k] = temp & 1;
+ if (temp != 0)
+ { /* b >= 2**n; the constraint (1) is redundant */
+ return 0;
+ }
+ /* main transformation loop */
+ for (k = 1; k <= n; k++)
+ { /* build the clause (5) for current k */
+ size = 0; /* clause size = number of literals */
+ /* add literal y[k] <= b[k] */
+ if (b[k] == 1)
+ { /* b[k] = 1 -> the literal is true */
+ goto skip;
+ }
+ else if (y[k].col == NULL)
+ { /* y[k] = 0, b[k] = 0 -> the literal is true */
+ xassert(y[k].neg == 0);
+ goto skip;
+ }
+ else
+ { /* add literal y[k] = 0 */
+ lit[++size] = y[k];
+ lit[size].neg = 1 - lit[size].neg;
+ }
+ for (j = k+1; j <= n; j++)
+ { /* add literal y[j] != b[j] */
+ if (y[j].col == NULL)
+ { xassert(y[j].neg == 0);
+ if (b[j] == 0)
+ { /* y[j] = 0, b[j] = 0 -> the literal is false */
+ continue;
+ }
+ else
+ { /* y[j] = 0, b[j] = 1 -> the literal is true */
+ goto skip;
+ }
+ }
+ else
+ { lit[++size] = y[j];
+ if (b[j] != 0)
+ lit[size].neg = 1 - lit[size].neg;
+ }
+ }
+ /* normalize the clause */
+ size = npp_sat_normalize_clause(npp, size, lit);
+ if (size < 0)
+ { /* the clause is equivalent to the value true */
+ goto skip;
+ }
+ if (size == 0)
+ { /* the clause is equivalent to the value false; this means
+ that the constraint (1) is infeasible */
+ return 2;
+ }
+ /* translate the clause to corresponding cover inequality */
+ npp_sat_encode_clause(npp, size, lit);
+skip: ;
+ }
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_encode_row - encode constraint (row) of general type
+*
+* PURPOSE
+*
+* This routine translates to CNF the following constraint (row):
+*
+* L <= sum a[j] x[j] <= U, (1)
+* j
+*
+* where all x[j] are binary variables.
+*
+* ALGORITHM
+*
+* First, the routine performs substitution x[j] = t[j] for j in J+
+* and x[j] = 1 - t[j] for j in J-, where J+ = { j : a[j] > 0 } and
+* J- = { j : a[j] < 0 }. This gives:
+*
+* L <= sum a[j] t[j] + sum a[j] (1 - t[j]) <= U ==>
+* j in J+ j in J-
+*
+* L' <= sum |a[j]| t[j] <= U', (2)
+* j
+*
+* where
+*
+* L' = L - sum a[j], U' = U - sum a[j]. (3)
+* j in J- j in J-
+*
+* (Actually only new bounds L' and U' are computed.)
+*
+* Then the routine translates to CNF the following equality:
+*
+* n
+* sum |a[j]| t[j] = sum 2**(k-1) * y[k], (4)
+* j k=1
+*
+* where y[k] is either some t[j] or a new literal or a constant zero
+* (see the routine npp_sat_encode_sum_ax).
+*
+* Finally, the routine translates to CNF the following conditions:
+*
+* n
+* sum 2**(k-1) * y[k] >= L' (5)
+* k=1
+*
+* and
+*
+* n
+* sum 2**(k-1) * y[k] <= U' (6)
+* k=1
+*
+* (see the routines npp_sat_encode_geq and npp_sat_encode_leq).
+*
+* All resulting clauses are encoded as cover inequalities and included
+* into the transformed problem.
+*
+* Note that on exit the routine removes the specified constraint (row)
+* from the original problem.
+*
+* RETURNS
+*
+* The routine returns one of the following codes:
+*
+* 0 - translation was successful;
+* 1 - constraint (1) was found infeasible;
+* 2 - integer arithmetic error occured. */
+
+int npp_sat_encode_row(NPP *npp, NPPROW *row)
+{ NPPAIJ *aij;
+ NPPLIT y[1+NBIT_MAX];
+ int n, rhs;
+ double lb, ub;
+ /* the row should not be free */
+ xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+ /* compute new bounds L' and U' (3) */
+ lb = row->lb;
+ ub = row->ub;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ { if (aij->val < 0.0)
+ { if (lb != -DBL_MAX)
+ lb -= aij->val;
+ if (ub != -DBL_MAX)
+ ub -= aij->val;
+ }
+ }
+ /* encode the equality (4) */
+ n = npp_sat_encode_sum_ax(npp, row, y);
+ if (n < 0)
+ return 2; /* integer arithmetic error */
+ /* encode the condition (5) */
+ if (lb != -DBL_MAX)
+ { rhs = (int)lb;
+ if ((double)rhs != lb)
+ return 2; /* integer arithmetic error */
+ if (npp_sat_encode_geq(npp, n, y, rhs) != 0)
+ return 1; /* original constraint is infeasible */
+ }
+ /* encode the condition (6) */
+ if (ub != +DBL_MAX)
+ { rhs = (int)ub;
+ if ((double)rhs != ub)
+ return 2; /* integer arithmetic error */
+ if (npp_sat_encode_leq(npp, n, y, rhs) != 0)
+ return 1; /* original constraint is infeasible */
+ }
+ /* remove the specified row from the problem */
+ npp_del_row(npp, row);
+ return 0;
+}
+
+/***********************************************************************
+* npp_sat_encode_prob - encode 0-1 feasibility problem
+*
+* This routine translates the specified 0-1 feasibility problem to an
+* equivalent SAT-CNF problem.
+*
+* N.B. Currently this is a very crude implementation.
+*
+* RETURNS
+*
+* 0 success;
+*
+* GLP_ENOPFS primal/integer infeasibility detected;
+*
+* GLP_ERANGE integer overflow occured. */
+
+int npp_sat_encode_prob(NPP *npp)
+{ NPPROW *row, *next_row, *prev_row;
+ NPPCOL *col, *next_col;
+ int cover = 0, pack = 0, partn = 0, ret;
+ /* process and remove free rows */
+ for (row = npp->r_head; row != NULL; row = next_row)
+ { next_row = row->next;
+ if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+ npp_sat_free_row(npp, row);
+ }
+ /* process and remove fixed columns */
+ for (col = npp->c_head; col != NULL; col = next_col)
+ { next_col = col->next;
+ if (col->lb == col->ub)
+ xassert(npp_sat_fixed_col(npp, col) == 0);
+ }
+ /* only binary variables should remain */
+ for (col = npp->c_head; col != NULL; col = col->next)
+ xassert(col->is_int && col->lb == 0.0 && col->ub == 1.0);
+ /* new rows may be added to the end of the row list, so we walk
+ from the end to beginning of the list */
+ for (row = npp->r_tail; row != NULL; row = prev_row)
+ { prev_row = row->prev;
+ /* process special cases */
+ ret = npp_sat_is_cover_ineq(npp, row);
+ if (ret != 0)
+ { /* row is covering inequality */
+ cover++;
+ /* since it already encodes a clause, just transform it to
+ canonical form */
+ if (ret == 2)
+ { xassert(npp_sat_reverse_row(npp, row) == 0);
+ ret = npp_sat_is_cover_ineq(npp, row);
+ }
+ xassert(ret == 1);
+ continue;
+ }
+ ret = npp_sat_is_partn_eq(npp, row);
+ if (ret != 0)
+ { /* row is partitioning equality */
+ NPPROW *cov;
+ NPPAIJ *aij;
+ partn++;
+ /* transform it to canonical form */
+ if (ret == 2)
+ { xassert(npp_sat_reverse_row(npp, row) == 0);
+ ret = npp_sat_is_partn_eq(npp, row);
+ }
+ xassert(ret == 1);
+ /* and split it into covering and packing inequalities,
+ both in canonical forms */
+ cov = npp_add_row(npp);
+ cov->lb = row->lb, cov->ub = +DBL_MAX;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ npp_add_aij(npp, cov, aij->col, aij->val);
+ xassert(npp_sat_is_cover_ineq(npp, cov) == 1);
+ /* the cover inequality already encodes a clause and do
+ not need any further processing */
+ row->lb = -DBL_MAX;
+ xassert(npp_sat_is_pack_ineq(npp, row) == 1);
+ /* the packing inequality will be processed below */
+ pack--;
+ }
+ ret = npp_sat_is_pack_ineq(npp, row);
+ if (ret != 0)
+ { /* row is packing inequality */
+ NPPROW *rrr;
+ int nlit, desired_nlit = 4;
+ pack++;
+ /* transform it to canonical form */
+ if (ret == 2)
+ { xassert(npp_sat_reverse_row(npp, row) == 0);
+ ret = npp_sat_is_pack_ineq(npp, row);
+ }
+ xassert(ret == 1);
+ /* process the packing inequality */
+ for (;;)
+ { /* determine the number of literals in the remaining
+ inequality */
+ nlit = npp_row_nnz(npp, row);
+ if (nlit <= desired_nlit)
+ break;
+ /* split the current inequality into one having not more
+ than desired_nlit literals and remaining one */
+ rrr = npp_sat_split_pack(npp, row, desired_nlit-1);
+ /* translate the former inequality to CNF and remove it
+ from the original problem */
+ npp_sat_encode_pack(npp, rrr);
+ }
+ /* translate the remaining inequality to CNF and remove it
+ from the original problem */
+ npp_sat_encode_pack(npp, row);
+ continue;
+ }
+ /* translate row of general type to CNF and remove it from the
+ original problem */
+ ret = npp_sat_encode_row(npp, row);
+ if (ret == 0)
+ ;
+ else if (ret == 1)
+ ret = GLP_ENOPFS;
+ else if (ret == 2)
+ ret = GLP_ERANGE;
+ else
+ xassert(ret != ret);
+ if (ret != 0)
+ goto done;
+ }
+ ret = 0;
+ if (cover != 0)
+ xprintf("%d covering inequalities\n", cover);
+ if (pack != 0)
+ xprintf("%d packing inequalities\n", pack);
+ if (partn != 0)
+ xprintf("%d partitioning equalities\n", partn);
+done: return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/proxy/main.c.disabled b/test/monniaux/glpk-4.65/src/proxy/main.c.disabled
new file mode 100644
index 00000000..a7d1e2b8
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/proxy/main.c.disabled
@@ -0,0 +1,87 @@
+/* Last update: 08-May-2013 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "glpk.h"
+#include "proxy.h"
+
+/**********************************************************************/
+int main(int argc, char **argv)
+/**********************************************************************/
+{
+ glp_prob *lp;
+ int ncols, status;
+ double *initsol, zstar, *xstar;
+
+ /* check arguments */
+ if ( (argc == 1) || (argc > 3) ) {
+ printf("ERROR: Usage: ts <instance> <(possibly) xml initsols>\n"
+ );
+ exit(1);
+ }
+
+ /* creating the problem */
+ lp = glp_create_prob();
+ glp_set_prob_name(lp, "Proxy");
+
+ /* reading the problem */
+ glp_term_out(GLP_OFF);
+#if 0 /* by mao */
+ status = glp_read_lp(lp, NULL, argv[1]);
+#else
+ status = glp_read_mps(lp, GLP_MPS_FILE, NULL, argv[1]);
+#endif
+ glp_term_out(GLP_ON);
+ if ( status ) {
+ printf("Problem %s does not exist!!!, status %d\n",
+ argv[1], status);
+ exit(1);
+ }
+
+ ncols = glp_get_num_cols(lp);
+
+ initsol = (double *) calloc(ncols+1, sizeof(double));
+
+ if (argc == 3) {
+ FILE *fp=fopen(argv[2],"r");
+ char tmp[256]={0x0};
+ int counter = 1;
+ while(fp!=NULL && fgets(tmp, sizeof(tmp),fp)!=NULL)
+ {
+ char *valini = strstr(tmp, "value");
+ if (valini!=NULL){
+ int num;
+ double dnum;
+ valini +=7;
+ sscanf(valini, "%d%*s",&num);
+ dnum = (double)num;
+ initsol[counter] = dnum;
+ counter++;
+ }
+ }
+ fclose(fp);
+ }
+
+ xstar = (double *) calloc(ncols+1, sizeof(double));
+
+ if (argc == 3) {
+ status = proxy(lp, &zstar, xstar, initsol, 0.0, 0, 1);
+ }
+ else {
+ status = proxy(lp, &zstar, xstar, NULL, 0.0, 0, 1);
+ }
+
+ printf("Status = %d; ZSTAR = %f\n",status,zstar);
+ /*
+ int i;
+ for (i=1; i< ncols+1; i++) {
+ printf("XSTAR[%d] = %f\n",i, xstar[i]);
+ }
+ */
+
+ glp_delete_prob(lp);
+
+ return 0;
+}
diff --git a/test/monniaux/glpk-4.65/src/proxy/proxy.c b/test/monniaux/glpk-4.65/src/proxy/proxy.c
new file mode 100644
index 00000000..7d890003
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/proxy/proxy.c
@@ -0,0 +1,1073 @@
+/* proxy.c (proximity search heuristic algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Author: Giorgio Sartor <0gioker0@gmail.com>.
+*
+* Copyright (C) 2013, 2016 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/>.
+*
+************************************************************************
+*
+* THIS CODE IS AN IMPLEMENTATION OF THE ALGORITHM PROPOSED IN
+*
+* M. Fischetti, M. Monaci,
+* "Proximity Search for 0-1 Mixed-Integer Convex Programming"
+* Technical Report DEI, University of Padua, March 2013.
+*
+* AVAILABLE AT
+* http://www.dei.unipd.it/~fisch/papers/proximity_search.pdf
+*
+* THE CODE HAS BEEN WRITTEN BY GIORGIO SARTOR, " 0gioker0@gmail.com "
+*
+* BASIC IDEA:
+*
+* The initial feasible solution x_tilde is defined. This initial
+* solution can be found by an ad-hoc heuristic and proxy can be used to
+* refine it by exploiting an underlying MIP model whose solution from
+* scratch turned out to be problematic. Otherwise, x_tilde can be found
+* by running the GLPK mip solver until a first feasible solution is
+* found, setting a conservative time limit of 10 minutes (by default).
+* Time limit can be modified passing variable tlim [ms].
+*
+* Then the cutoff tolerance "delta" is defined. The default tolerance
+* is 1% of the last feasible solution obj value--rounded to integer if
+* all the variables and obj coefficients are integer.
+*
+* Next, the objective function c' x is replaced by the Hamming distance
+* between x (the actual obj coefficients) and x_tilde (the given
+* solution). Distance is only computed wrt the binary variables.
+*
+* The GLPK solver is then invoked to hopefully find a new incumbent
+* x_star with cost c' x_star <= c' x_tilde - delta. A crucial property
+* here is that the root-node solution of the LP relaxation is expected
+* to be not too different from x_tilde, as this latter solution would
+* be optimal without the cutoff constraint, that for a small delta can
+* typically be fulfilled with just local adjustments.
+*
+* If no new solution x_star is found within the time limit the
+* algorithm stops. Of course, if the MIP solver proved infeasibility
+* for the given delta, we have that c' x_tilde - delta is a valid lower
+* bound (in case of minimazation) on the optimal value of the original
+* MIP.
+*
+* The new solution x_star, if any, is possibly improved by solving a
+* simplified problem (refinement) where all binary variables have been
+* fixed to their value in x_star so as to find the best solution within
+* the neighborhood.
+*
+* Finally, the approach is reapplied on x_star (that replaces x_tilde)
+* so as to recenter the distance Hamming function and by modifying the
+* cutoff tolerance delta.
+*
+* In this way, there will be a series of hopefully not-too-difficult
+* sub-MIPs to solve, each leading to an improvement of the incumbent.
+* More aggressive policies on the definition of tolerance delta can
+* lead to a better performance, but would require an ad-hoc tuning.
+*
+************************************************************************
+*
+* int proxy(glp_prob *lp, double *zstar, double *xstar,
+* const double[] initsol, double rel_impr, int tlim,
+* int verbose)
+*
+* lp : GLPK problem pointer to a MIP with binary variables
+*
+* zstar : the value of objective function of the best solution found
+*
+* xstar : best solution with components xstar[1],...,xstar[ncols]
+*
+* initsol : pointer to a initial feasible solution, see
+* glp_ios_heur_sol
+* If initsol = NULL, the procedure finds the first solution
+* by itself.
+*
+* rel_impr : minimum relative obj improvement to be achieved at each
+* internal step; if <= 0.0 a default value of 0.01 (1%) is
+* used; for some problems (e.g., set covering with small
+* integer costs) a more-conservative choice of 0.001 (0.1%)
+* can lead to a better final solution; values larger than
+* 0.05 (5%) are typically too aggressive and do not work
+* well.
+*
+* tlim : time limit to find a new solution, in ms.
+* If tlim = 0, it is set to its default value, 600000 ms
+*
+* verbose : if 1 the output is activated. If 0 only errors are
+* displayed
+*
+* The procedure returns -1 if an error occurred, 0 otherwise (possibly,
+* time limit)
+*
+***********************************************************************/
+
+/**********************************************************************/
+/* 1. INCLUDE */
+/**********************************************************************/
+
+#include "glpk.h"
+#include "env.h"
+#include "proxy.h"
+
+/**********************************************************************/
+/* 2. PARAMETERS AND CONSTANTS */
+/**********************************************************************/
+
+#define TDAY 86400.0
+#define TRUE 1
+#define FALSE 0
+#define EPS 1e-6
+#define RINF 1e38
+#define MAXVAL 1e20
+#define MINVAL -1e20
+#if 0 /* by gioker */
+ #define PROXY_DEBUG
+#endif
+
+/**********************************************************************/
+/* 3. GLOBAL VARIABLES */
+/**********************************************************************/
+
+struct csa {
+
+int integer_obj; /* TRUE if each feasible solution has an
+ integral cost */
+int b_vars_exist; /* TRUE if there is at least one binary
+ variable in the problem */
+int i_vars_exist; /* TRUE if there is at least one general
+ integer variable in the problem */
+const double *startsol; /* Pointer to the initial solution */
+
+int *ckind; /* Store the kind of the structural variables
+ of the problem */
+double *clb; /* Store the lower bound on the structural
+ variables of the problem */
+double *cub; /* Store the upper bound on the structural
+ variables of the problem */
+double *true_obj; /* Store the obj coefficients of the problem */
+
+int dir; /* Minimization or maximization problem */
+int ncols; /* Number of structural variables of the
+ problem */
+
+time_t GLOtstart; /* starting time of the algorithm */
+
+glp_prob *lp_ref; /* glp problem for refining only*/
+
+};
+
+/**********************************************************************/
+/* 4. FUNCTIONS PROTOTYPES */
+/**********************************************************************/
+
+static void callback(glp_tree *tree, void *info);
+static void get_info(struct csa *csa, glp_prob *lp);
+static int is_integer(struct csa *csa);
+static void check_integrality(struct csa *csa);
+static int check_ref(struct csa *csa, glp_prob *lp, double *xref);
+static double second(void);
+static int add_cutoff(struct csa *csa, glp_prob *lp);
+static void get_sol(struct csa *csa, glp_prob *lp, double *xstar);
+static double elapsed_time(struct csa *csa);
+static void redefine_obj(glp_prob *lp, double *xtilde, int ncols,
+ int *ckind, double *clb, double *cub);
+static double update_cutoff(struct csa *csa, glp_prob *lp,
+ double zstar, int index, double rel_impr);
+static double compute_delta(struct csa *csa, double z,
+ double rel_impr);
+static double objval(int ncols, double *x, double *true_obj);
+static void array_copy(int begin, int end, double *source,
+ double *destination);
+static int do_refine(struct csa *csa, glp_prob *lp_ref, int ncols,
+ int *ckind, double *xref, int *tlim, int tref_lim,
+ int verbose);
+static void deallocate(struct csa *csa, int refine);
+
+/**********************************************************************/
+/* 5. FUNCTIONS */
+/**********************************************************************/
+
+int proxy(glp_prob *lp, double *zfinal, double *xfinal,
+ const double initsol[], double rel_impr, int tlim,
+ int verbose)
+
+{ struct csa csa_, *csa = &csa_;
+ glp_iocp parm;
+ glp_smcp parm_lp;
+ size_t tpeak;
+ int refine, tref_lim, err, cutoff_row, niter, status, i, tout;
+ double *xref, *xstar, zstar, tela, cutoff, zz;
+
+ memset(csa, 0, sizeof(struct csa));
+
+
+ /********** **********/
+ /********** RETRIEVING PROBLEM INFO **********/
+ /********** **********/
+
+ /* getting problem direction (min or max) */
+ csa->dir = glp_get_obj_dir(lp);
+
+ /* getting number of variables */
+ csa->ncols = glp_get_num_cols(lp);
+
+ /* getting kind, bounds and obj coefficient of each variable
+ information is stored in ckind, cub, clb, true_obj */
+ get_info(csa, lp);
+
+ /* checking if the objective function is always integral */
+ check_integrality(csa);
+
+ /* Proximity search cannot be used if there are no binary
+ variables */
+ if (csa->b_vars_exist == FALSE) {
+ if (verbose) {
+ xprintf("The problem has not binary variables. Proximity se"
+ "arch cannot be used.\n");
+ }
+ tfree(csa->ckind);
+ tfree(csa->clb);
+ tfree(csa->cub);
+ tfree(csa->true_obj);
+ return -1;
+ }
+
+ /* checking if the problem needs refinement, i.e., not all
+ variables are binary. If so, the routine creates a copy of the
+ lp problem named lp_ref and initializes the solution xref to
+ zero. */
+ xref = talloc(csa->ncols+1, double);
+#if 0 /* by mao */
+ memset(xref, 0, sizeof(double)*(csa->ncols+1));
+#endif
+ refine = check_ref(csa, lp, xref);
+#ifdef PROXY_DEBUG
+ xprintf("REFINE = %d\n",refine);
+#endif
+
+ /* Initializing the solution */
+ xstar = talloc(csa->ncols+1, double);
+#if 0 /* by mao */
+ memset(xstar, 0, sizeof(double)*(csa->ncols+1));
+#endif
+
+ /********** **********/
+ /********** FINDING FIRST SOLUTION **********/
+ /********** **********/
+
+ if (verbose) {
+ xprintf("Applying PROXY heuristic...\n");
+ }
+
+ /* get the initial time */
+ csa->GLOtstart = second();
+
+ /* setting the optimization parameters */
+ glp_init_iocp(&parm);
+ glp_init_smcp(&parm_lp);
+#if 0 /* by gioker */
+ /* Preprocessing should be disabled because the mip passed
+ to proxy is already preprocessed */
+ parm.presolve = GLP_ON;
+#endif
+#if 1 /* by mao */
+ /* best projection backtracking seems to be more efficient to find
+ any integer feasible solution */
+ parm.bt_tech = GLP_BT_BPH;
+#endif
+
+ /* Setting the default value of the minimum relative improvement
+ to 1% */
+ if ( rel_impr <= 0.0 ) {
+ rel_impr = 0.01;
+ }
+
+ /* Setting the default value of time limit to 10 minutes */
+ if (tlim <= 0) {
+ tlim = INT_MAX;
+ }
+ if (verbose) {
+ xprintf("Proxy's time limit set to %d seconds.\n",tlim/1000);
+ xprintf("Proxy's relative improvement "
+ "set to %2.2lf %c.\n",rel_impr*100,37);
+ }
+
+ parm_lp.tm_lim = tlim;
+
+ parm.mip_gap = 9999999.9; /* to stop the optimization at the first
+ feasible solution found */
+
+ /* finding the first solution */
+ if (verbose) {
+ xprintf("Searching for a feasible solution...\n");
+ }
+
+ /* verifying the existence of an input starting solution */
+ if (initsol != NULL) {
+ csa->startsol = initsol;
+ parm.cb_func = callback;
+ parm.cb_info = csa;
+ if (verbose) {
+ xprintf("Input solution found.\n");
+ }
+ }
+
+ tout = glp_term_out(GLP_OFF);
+ err = glp_simplex(lp,&parm_lp);
+ glp_term_out(tout);
+
+ status = glp_get_status(lp);
+
+ if (status != GLP_OPT) {
+ if (verbose) {
+ xprintf("Proxy heuristic terminated.\n");
+ }
+#ifdef PROXY_DEBUG
+ /* For debug only */
+ xprintf("GLP_SIMPLEX status = %d\n",status);
+ xprintf("GLP_SIMPLEX error code = %d\n",err);
+#endif
+ tfree(xref);
+ tfree(xstar);
+ deallocate(csa, refine);
+ return -1;
+ }
+
+ tela = elapsed_time(csa);
+ if (tlim-tela*1000 <= 0) {
+ if (verbose) {
+ xprintf("Time limit exceeded. Proxy could not "
+ "find optimal solution to LP relaxation.\n");
+ xprintf("Proxy heuristic aborted.\n");
+ }
+ tfree(xref);
+ tfree(xstar);
+ deallocate(csa, refine);
+ return -1;
+ }
+
+ parm.tm_lim = tlim - tela*1000;
+ tref_lim = (tlim - tela *1000) / 20;
+
+ tout = glp_term_out(GLP_OFF);
+ err = glp_intopt(lp, &parm);
+ glp_term_out(tout);
+
+ status = glp_mip_status(lp);
+
+ /***** If no solution was found *****/
+
+ if (status == GLP_NOFEAS || status == GLP_UNDEF) {
+ if (err == GLP_ETMLIM) {
+ if (verbose) {
+ xprintf("Time limit exceeded. Proxy could not "
+ "find an initial integer feasible solution.\n");
+ xprintf("Proxy heuristic aborted.\n");
+ }
+ }
+ else {
+ if (verbose) {
+ xprintf("Proxy could not "
+ "find an initial integer feasible solution.\n");
+ xprintf("Proxy heuristic aborted.\n");
+ }
+ }
+ tfree(xref);
+ tfree(xstar);
+ deallocate(csa, refine);
+ return -1;
+ }
+
+ /* getting the first solution and its value */
+ get_sol(csa, lp,xstar);
+ zstar = glp_mip_obj_val(lp);
+
+ if (verbose) {
+ xprintf(">>>>> first solution = %e;\n", zstar);
+ }
+
+ /* If a feasible solution was found but the time limit is
+ exceeded */
+ if (err == GLP_ETMLIM) {
+ if (verbose) {
+ xprintf("Time limit exceeded. Proxy heuristic terminated.\n");
+ }
+ goto done;
+ }
+
+ tela = elapsed_time(csa);
+ tpeak = 0;
+ glp_mem_usage(NULL, NULL, NULL, &tpeak);
+ if (verbose) {
+ xprintf("Time used: %3.1lf secs. Memory used: %2.1lf Mb\n",
+ tela,(double)tpeak/1048576);
+ xprintf("Starting proximity search...\n");
+ }
+
+ /********** **********/
+ /********** PREPARING THE PROBLEM FOR PROXY **********/
+ /********** **********/
+
+ /* adding a dummy cutoff constraint */
+ cutoff_row = add_cutoff(csa, lp);
+
+ /* proximity search needs minimization direction
+ even if the problem is a maximization one */
+ if (csa->dir == GLP_MAX) {
+ glp_set_obj_dir(lp, GLP_MIN);
+ }
+
+ /********** **********/
+ /********** STARTING PROXIMITY SEARCH **********/
+ /********** **********/
+
+
+ niter = 0;
+
+ while (TRUE) {
+ niter++;
+
+ /********** CHANGING THE OBJ FUNCTION **********/
+
+ redefine_obj(lp,xstar, csa->ncols, csa->ckind, csa->clb,
+ csa->cub);
+
+ /********** UPDATING THE CUTOFF CONSTRAINT **********/
+
+ cutoff = update_cutoff(csa, lp,zstar, cutoff_row, rel_impr);
+
+#ifdef PROXY_DEBUG
+ xprintf("TRUE_OBJ[0] = %f\n",csa->true_obj[0]);
+ xprintf("ZSTAR = %f\n",zstar);
+ xprintf("CUTOFF = %f\n",cutoff);
+#endif
+
+ /********** SEARCHING FOR A BETTER SOLUTION **********/
+
+ tela = elapsed_time(csa);
+ if (tlim-tela*1000 <= 0) {
+ if (verbose) {
+ xprintf("Time limit exceeded. Proxy heuristic "
+ "terminated.\n");
+ }
+ goto done;
+ }
+#ifdef PROXY_DEBUG
+ xprintf("TELA = %3.1lf\n",tela*1000);
+ xprintf("TLIM = %3.1lf\n",tlim - tela*1000);
+#endif
+ parm_lp.tm_lim = tlim -tela*1000;
+
+ tout = glp_term_out(GLP_OFF);
+ err = glp_simplex(lp,&parm_lp);
+ glp_term_out(tout);
+
+ status = glp_get_status(lp);
+
+ if (status != GLP_OPT) {
+ if (status == GLP_NOFEAS) {
+ if (verbose) {
+ xprintf("Bound exceeded = %f. ",cutoff);
+ }
+ }
+ if (verbose) {
+ xprintf("Proxy heuristic terminated.\n");
+ }
+#ifdef PROXY_DEBUG
+ xprintf("GLP_SIMPLEX status = %d\n",status);
+ xprintf("GLP_SIMPLEX error code = %d\n",err);
+#endif
+ goto done;
+ }
+
+ tela = elapsed_time(csa);
+ if (tlim-tela*1000 <= 0) {
+ if (verbose) {
+ xprintf("Time limit exceeded. Proxy heuristic "
+ "terminated.\n");
+ }
+ goto done;
+ }
+ parm.tm_lim = tlim - tela*1000;
+ parm.cb_func = NULL;
+#if 0 /* by gioker */
+ /* Preprocessing should be disabled because the mip passed
+ to proxy is already preprocessed */
+ parm.presolve = GLP_ON;
+#endif
+ tout = glp_term_out(GLP_OFF);
+ err = glp_intopt(lp, &parm);
+ glp_term_out(tout);
+
+ /********** MANAGEMENT OF THE SOLUTION **********/
+
+ status = glp_mip_status(lp);
+
+ /***** No feasible solutions *****/
+
+ if (status == GLP_NOFEAS) {
+ if (verbose) {
+ xprintf("Bound exceeded = %f. Proxy heuristic "
+ "terminated.\n",cutoff);
+ }
+ goto done;
+ }
+
+ /***** Undefined solution *****/
+
+ if (status == GLP_UNDEF) {
+ if (err == GLP_ETMLIM) {
+ if (verbose) {
+ xprintf("Time limit exceeded. Proxy heuristic "
+ "terminated.\n");
+ }
+ }
+ else {
+ if (verbose) {
+ xprintf("Proxy terminated unexpectedly.\n");
+#ifdef PROXY_DEBUG
+ xprintf("GLP_INTOPT error code = %d\n",err);
+#endif
+ }
+ }
+ goto done;
+ }
+
+ /***** Feasible solution *****/
+
+ if ((status == GLP_FEAS) || (status == GLP_OPT)) {
+
+ /* getting the solution and computing its value */
+ get_sol(csa, lp,xstar);
+ zz = objval(csa->ncols, xstar, csa->true_obj);
+
+ /* Comparing the incumbent solution with the current best
+ one */
+#ifdef PROXY_DEBUG
+ xprintf("ZZ = %f\n",zz);
+ xprintf("ZSTAR = %f\n",zstar);
+ xprintf("REFINE = %d\n",refine);
+#endif
+ if (((zz<zstar) && (csa->dir == GLP_MIN)) ||
+ ((zz>zstar) && (csa->dir == GLP_MAX))) {
+
+ /* refining (possibly) the solution */
+ if (refine) {
+
+ /* copying the incumbent solution in the refinement
+ one */
+ array_copy(1, csa->ncols +1, xstar, xref);
+ err = do_refine(csa, csa->lp_ref, csa->ncols,
+ csa->ckind, xref, &tlim, tref_lim, verbose);
+ if (!err) {
+ double zref = objval(csa->ncols, xref,
+ csa->true_obj);
+ if (((zref<zz) && (csa->dir == GLP_MIN)) ||
+ ((zref>zz) && (csa->dir == GLP_MAX))) {
+ zz = zref;
+ /* copying the refinement solution in the
+ incumbent one */
+ array_copy(1, csa->ncols +1, xref, xstar);
+ }
+ }
+ }
+ zstar = zz;
+ tela = elapsed_time(csa);
+ if (verbose) {
+ xprintf(">>>>> it: %3d: mip = %e; elapsed time "
+ "%3.1lf sec.s\n", niter,zstar,tela);
+ }
+ }
+ }
+ }
+
+done:
+ tela = elapsed_time(csa);
+ glp_mem_usage(NULL, NULL, NULL, &tpeak);
+ if (verbose) {
+ xprintf("Time used: %3.1lf. Memory used: %2.1lf Mb\n",
+ tela,(double)tpeak/1048576);
+ }
+
+
+ /* Exporting solution and obj val */
+ *zfinal = zstar;
+
+ for (i=1; i < (csa->ncols + 1); i++) {
+ xfinal[i]=xstar[i];
+ }
+
+ /* Freeing allocated memory */
+ tfree(xref);
+ tfree(xstar);
+ deallocate(csa, refine);
+
+ return 0;
+}
+
+/**********************************************************************/
+static void callback(glp_tree *tree, void *info){
+/**********************************************************************/
+ struct csa *csa = info;
+ switch(glp_ios_reason(tree)) {
+ case GLP_IHEUR:
+ glp_ios_heur_sol(tree, csa->startsol);
+ break;
+ default: break;
+ }
+}
+
+/**********************************************************************/
+static void get_info(struct csa *csa, glp_prob *lp)
+/**********************************************************************/
+{
+ int i;
+
+ /* Storing helpful info of the problem */
+
+ csa->ckind = talloc(csa->ncols+1, int);
+#if 0 /* by mao */
+ memset(csa->ckind, 0, sizeof(int)*(csa->ncols+1));
+#endif
+ csa->clb = talloc(csa->ncols+1, double);
+#if 0 /* by mao */
+ memset(csa->clb, 0, sizeof(double)*(csa->ncols+1));
+#endif
+ csa->cub = talloc(csa->ncols+1, double);
+#if 0 /* by mao */
+ memset(csa->cub, 0, sizeof(double)*(csa->ncols+1));
+#endif
+ csa->true_obj = talloc(csa->ncols+1, double);
+#if 0 /* by mao */
+ memset(csa->true_obj, 0, sizeof(double)*(csa->ncols+1));
+#endif
+ for( i = 1 ; i < (csa->ncols + 1); i++ ) {
+ csa->ckind[i] = glp_get_col_kind(lp, i);
+ csa->clb[i] = glp_get_col_lb(lp, i);
+ csa->cub[i] = glp_get_col_ub(lp, i);
+ csa->true_obj[i] = glp_get_obj_coef(lp, i);
+ }
+ csa->true_obj[0] = glp_get_obj_coef(lp, 0);
+}
+
+/**********************************************************************/
+static int is_integer(struct csa *csa)
+/**********************************************************************/
+{
+ int i;
+ csa->integer_obj = TRUE;
+ for ( i = 1; i < (csa->ncols + 1); i++ ) {
+ if (fabs(csa->true_obj[i]) > INT_MAX ) {
+ csa->integer_obj = FALSE;
+ }
+ if (fabs(csa->true_obj[i]) <= INT_MAX) {
+ double tmp, rem;
+ if (fabs(csa->true_obj[i]) - floor(fabs(csa->true_obj[i]))
+ < 0.5) {
+ tmp = floor(fabs(csa->true_obj[i]));
+ }
+ else {
+ tmp = ceil(fabs(csa->true_obj[i]));
+ }
+ rem = fabs(csa->true_obj[i]) - tmp;
+ rem = fabs(rem);
+ if (rem > EPS) {
+ csa->integer_obj = FALSE;
+ }
+
+ }
+ }
+ return csa->integer_obj;
+}
+
+/**********************************************************************/
+static void check_integrality(struct csa *csa)
+/**********************************************************************/
+{
+ /*
+ Checking if the problem has binary, integer or continuos variables.
+ integer_obj is TRUE if the problem has no continuous variables
+ and all the obj coefficients are integer (and < INT_MAX).
+ */
+
+ int i;
+ csa->integer_obj = is_integer(csa);
+ csa->b_vars_exist = FALSE;
+ csa->i_vars_exist = FALSE;
+ for ( i = 1; i < (csa->ncols + 1); i++ ) {
+ if ( csa->ckind[i] == GLP_IV ){
+ csa->i_vars_exist = TRUE;
+ continue;
+ }
+ if ( csa->ckind[i] == GLP_BV ){
+ csa->b_vars_exist =TRUE;
+ continue;
+ }
+ csa->integer_obj = FALSE;
+ }
+}
+
+/**********************************************************************/
+static int check_ref(struct csa *csa, glp_prob *lp, double *xref)
+/**********************************************************************/
+{
+ /*
+ checking if the problem has continuos or integer variables. If so,
+ refinement is prepared.
+ */
+ int refine = FALSE;
+ int i;
+ for ( i = 1; i < (csa->ncols + 1); i++ ) {
+ if ( csa->ckind[i] != GLP_BV) {
+ refine = TRUE;
+ break;
+ }
+ }
+
+ /* possibly creating a mip clone for refinement only */
+ if ( refine ) {
+ csa->lp_ref = glp_create_prob();
+ glp_copy_prob(csa->lp_ref, lp, GLP_ON);
+ }
+
+ return refine;
+}
+
+/**********************************************************************/
+static double second(void)
+/**********************************************************************/
+{
+#if 0 /* by mao */
+ return ((double)clock()/(double)CLOCKS_PER_SEC);
+#else
+ return xtime() / 1000.0;
+#endif
+}
+
+/**********************************************************************/
+static int add_cutoff(struct csa *csa, glp_prob *lp)
+/**********************************************************************/
+{
+ /*
+ Adding a cutoff constraint to set an upper bound (in case of
+ minimaztion) on the obj value of the next solution, i.e., the next
+ value of the true obj function that we would like to find
+ */
+
+ /* store non-zero coefficients in the objective function */
+ int *obj_index = talloc(csa->ncols+1, int);
+#if 0 /* by mao */
+ memset(obj_index, 0, sizeof(int)*(csa->ncols+1));
+#endif
+ double *obj_value = talloc(csa->ncols+1, double);
+#if 0 /* by mao */
+ memset(obj_value, 0, sizeof(double)*(csa->ncols+1));
+#endif
+ int obj_nzcnt = 0;
+ int i, irow;
+ const char *rowname;
+ for ( i = 1; i < (csa->ncols + 1); i++ ) {
+ if ( fabs(csa->true_obj[i]) > EPS ) {
+ obj_nzcnt++;
+ obj_index[obj_nzcnt] = i;
+ obj_value[obj_nzcnt] = csa->true_obj[i];
+ }
+ }
+
+ irow = glp_add_rows(lp, 1);
+ rowname = "Cutoff";
+ glp_set_row_name(lp, irow, rowname);
+ if (csa->dir == GLP_MIN) {
+ /* minimization problem */
+ glp_set_row_bnds(lp, irow, GLP_UP, MAXVAL, MAXVAL);
+ }
+ else {
+ /* maximization problem */
+ glp_set_row_bnds(lp, irow, GLP_LO, MINVAL, MINVAL);
+ }
+
+ glp_set_mat_row(lp, irow, obj_nzcnt, obj_index, obj_value);
+
+ tfree(obj_index);
+ tfree(obj_value);
+
+ return irow;
+}
+
+/**********************************************************************/
+static void get_sol(struct csa *csa, glp_prob *lp, double *xstar)
+/**********************************************************************/
+{
+ /* Retrieving and storing the coefficients of the solution */
+
+ int i;
+ for (i = 1; i < (csa->ncols +1); i++) {
+ xstar[i] = glp_mip_col_val(lp, i);
+ }
+}
+
+/**********************************************************************/
+static double elapsed_time(struct csa *csa)
+/**********************************************************************/
+{
+ double tela = second() - csa->GLOtstart;
+ if ( tela < 0 ) tela += TDAY;
+ return(tela);
+}
+
+/**********************************************************************/
+static void redefine_obj(glp_prob *lp, double *xtilde, int ncols,
+ int *ckind, double *clb, double *cub)
+/**********************************************************************/
+
+/*
+ Redefine the lp objective function obj as the distance-to-integrality
+ (Hamming distance) from xtilde (the incumbent feasible solution), wrt
+ to binary vars only
+ */
+
+{
+ int j;
+ double *delta = talloc(ncols+1, double);
+#if 0 /* by mao */
+ memset(delta, 0, sizeof(double)*(ncols+1));
+#endif
+
+ for ( j = 1; j < (ncols +1); j++ ) {
+ delta[j] = 0.0;
+ /* skip continuous variables */
+ if ( ckind[j] == GLP_CV ) continue;
+
+ /* skip integer variables that have been fixed */
+ if ( cub[j]-clb[j] < 0.5 ) continue;
+
+ /* binary variable */
+ if ( ckind[j] == GLP_BV ) {
+ if ( xtilde[j] > 0.5 ) {
+ delta[j] = -1.0;
+ }
+ else {
+ delta[j] = 1.0;
+ }
+ }
+ }
+
+ /* changing the obj coeff. for all variables, including continuous
+ ones */
+ for ( j = 1; j < (ncols +1); j++ ) {
+ glp_set_obj_coef(lp, j, delta[j]);
+ }
+ glp_set_obj_coef(lp, 0, 0.0);
+
+ tfree(delta);
+}
+
+/**********************************************************************/
+static double update_cutoff(struct csa *csa, glp_prob *lp,
+ double zstar, int cutoff_row,
+ double rel_impr)
+/**********************************************************************/
+{
+ /*
+ Updating the cutoff constraint with the value we would like to
+ find during the next optimization
+ */
+ double cutoff;
+ zstar -= csa->true_obj[0];
+ if (csa->dir == GLP_MIN) {
+ cutoff = zstar - compute_delta(csa, zstar, rel_impr);
+ glp_set_row_bnds(lp, cutoff_row, GLP_UP, cutoff, cutoff);
+ }
+ else {
+ cutoff = zstar + compute_delta(csa, zstar, rel_impr);
+ glp_set_row_bnds(lp, cutoff_row, GLP_LO, cutoff, cutoff);
+ }
+
+ return cutoff;
+}
+
+/**********************************************************************/
+static double compute_delta(struct csa *csa, double z, double rel_impr)
+/**********************************************************************/
+{
+ /* Computing the offset for the next best solution */
+
+ double delta = rel_impr * fabs(z);
+ if ( csa->integer_obj ) delta = ceil(delta);
+
+ return(delta);
+}
+
+/**********************************************************************/
+static double objval(int ncols, double *x, double *true_obj)
+/**********************************************************************/
+{
+ /* Computing the true cost of x (using the original obj coeff.s) */
+
+ int j;
+ double z = 0.0;
+ for ( j = 1; j < (ncols +1); j++ ) {
+ z += x[j] * true_obj[j];
+ }
+ return z + true_obj[0];
+}
+
+/**********************************************************************/
+static void array_copy(int begin, int end, double *source,
+ double *destination)
+/**********************************************************************/
+{
+ int i;
+ for (i = begin; i < end; i++) {
+ destination[i] = source[i];
+ }
+}
+/**********************************************************************/
+static int do_refine(struct csa *csa, glp_prob *lp_ref, int ncols,
+ int *ckind, double *xref, int *tlim, int tref_lim,
+ int verbose)
+/**********************************************************************/
+{
+ /*
+ Refinement is applied when the variables of the problem are not
+ all binary. Binary variables are fixed to their value and
+ remaining ones are optimized. If there are only continuos
+ variables (in addition to those binary) the problem becomes just
+ an LP. Otherwise, it remains a MIP but of smaller size.
+ */
+
+ int j, tout;
+ double refineStart = second();
+ double val, tela, tlimit;
+
+ if ( glp_get_num_cols(lp_ref) != ncols ) {
+ if (verbose) {
+ xprintf("Error in Proxy refinement: ");
+ xprintf("wrong number of columns (%d vs %d).\n",
+ ncols, glp_get_num_cols(lp_ref));
+ }
+ return 1;
+ }
+
+ val = -1.0;
+
+ /* fixing all binary variables to their current value in xref */
+ for ( j = 1; j < (ncols + 1); j++ ) {
+ if ( ckind[j] == GLP_BV ) {
+ val = 0.0;
+ if ( xref[j] > 0.5 ) val = 1.0;
+ glp_set_col_bnds(lp_ref, j, GLP_FX, val, val);
+ }
+ }
+
+ /* re-optimizing (refining) if some bound has been changed */
+ if ( val > -1.0 ) {
+ glp_iocp parm_ref;
+ glp_smcp parm_ref_lp;
+ int err, status;
+
+ glp_init_iocp(&parm_ref);
+ parm_ref.presolve = GLP_ON;
+ glp_init_smcp(&parm_ref_lp);
+ /*
+ If there are no general integer variable the problem becomes
+ an LP (after fixing the binary variables) and can be solved
+ quickly. Otherwise the problem is still a MIP problem and a
+ timelimit has to be set.
+ */
+ parm_ref.tm_lim = tref_lim;
+ if (parm_ref.tm_lim > *tlim) {
+ parm_ref.tm_lim = *tlim;
+ }
+ parm_ref_lp.tm_lim = parm_ref.tm_lim;
+#ifdef PROXY_DEBUG
+ xprintf("***** REFINING *****\n");
+#endif
+ tout = glp_term_out(GLP_OFF);
+ if (csa->i_vars_exist == TRUE) {
+ err = glp_intopt(lp_ref, &parm_ref);
+ }
+ else {
+ err = glp_simplex(lp_ref, &parm_ref_lp);
+ }
+ glp_term_out(tout);
+
+ if (csa->i_vars_exist == TRUE) {
+ status = glp_mip_status(lp_ref);
+ }
+ else {
+ status = glp_get_status(lp_ref);
+ }
+
+#if 1 /* 29/II-2016 by mao as reported by Chris */
+ switch (status)
+ { case GLP_OPT:
+ case GLP_FEAS:
+ break;
+ default:
+ status = GLP_UNDEF;
+ break;
+ }
+#endif
+
+#ifdef PROXY_DEBUG
+ xprintf("STATUS REFINING = %d\n",status);
+#endif
+ if (status == GLP_UNDEF) {
+ if (err == GLP_ETMLIM) {
+#ifdef PROXY_DEBUG
+ xprintf("Time limit exceeded on Proxy refining.\n");
+#endif
+ return 1;
+ }
+ }
+ for( j = 1 ; j < (ncols + 1); j++ ){
+ if (ckind[j] != GLP_BV) {
+ if (csa->i_vars_exist == TRUE) {
+ xref[j] = glp_mip_col_val(lp_ref, j);
+ }
+ else{
+ xref[j] = glp_get_col_prim(lp_ref, j);
+ }
+ }
+ }
+ }
+ tela = second() - refineStart;
+#ifdef PROXY_DEBUG
+ xprintf("REFINE TELA = %3.1lf\n",tela*1000);
+#endif
+ return 0;
+}
+/**********************************************************************/
+static void deallocate(struct csa *csa, int refine)
+/**********************************************************************/
+{
+ /* Deallocating routine */
+
+ if (refine) {
+ glp_delete_prob(csa->lp_ref);
+ }
+
+ tfree(csa->ckind);
+ tfree(csa->clb);
+ tfree(csa->cub);
+ tfree(csa->true_obj);
+
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/proxy/proxy.h b/test/monniaux/glpk-4.65/src/proxy/proxy.h
new file mode 100644
index 00000000..a91e36f2
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/proxy/proxy.h
@@ -0,0 +1,36 @@
+/* proxy.h (proximity search heuristic algorithm) */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Author: Giorgio Sartor <0gioker0@gmail.com>.
+*
+* Copyright (C) 2013 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/>.
+***********************************************************************/
+
+#ifndef PROXY_H
+#define PROXY_H
+
+#define proxy _glp_proxy
+int proxy(glp_prob *lp, double *zstar, double *xstar,
+ const double initsol[], double rel_impr, int tlim,
+ int verbose);
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/proxy/proxy1.c b/test/monniaux/glpk-4.65/src/proxy/proxy1.c
new file mode 100644
index 00000000..5f9850d4
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/proxy/proxy1.c
@@ -0,0 +1,88 @@
+/* proxy1.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2013, 2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "ios.h"
+#include "proxy.h"
+
+void ios_proxy_heur(glp_tree *T)
+{ glp_prob *prob;
+ int j, status;
+ double *xstar, zstar;
+ /* this heuristic is applied only once on the root level */
+ if (!(T->curr->level == 0 && T->curr->solved == 1))
+ goto done;
+ prob = glp_create_prob();
+ glp_copy_prob(prob, T->mip, 0);
+ xstar = xcalloc(1+prob->n, sizeof(double));
+ for (j = 1; j <= prob->n; j++)
+ xstar[j] = 0.0;
+ if (T->mip->mip_stat != GLP_FEAS)
+ status = proxy(prob, &zstar, xstar, NULL, 0.0,
+ T->parm->ps_tm_lim, 1);
+ else
+ { double *xinit = xcalloc(1+prob->n, sizeof(double));
+ for (j = 1; j <= prob->n; j++)
+ xinit[j] = T->mip->col[j]->mipx;
+ status = proxy(prob, &zstar, xstar, xinit, 0.0,
+ T->parm->ps_tm_lim, 1);
+ xfree(xinit);
+ }
+ if (status == 0)
+#if 0 /* 17/III-2016 */
+ glp_ios_heur_sol(T, xstar);
+#else
+ { /* sometimes the proxy heuristic reports a wrong solution, so
+ * make sure that the solution is really integer feasible */
+ int i, feas1, feas2, ae_ind, re_ind;
+ double ae_max, re_max;
+ glp_copy_prob(prob, T->mip, 0);
+ for (j = 1; j <= prob->n; j++)
+ prob->col[j]->mipx = xstar[j];
+ for (i = 1; i <= prob->m; i++)
+ { GLPROW *row;
+ GLPAIJ *aij;
+ row = prob->row[i];
+ row->mipx = 0.0;
+ for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+ row->mipx += aij->val * aij->col->mipx;
+ }
+ glp_check_kkt(prob, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind,
+ &re_max, &re_ind);
+ feas1 = (re_max <= 1e-6);
+ glp_check_kkt(prob, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind,
+ &re_max, &re_ind);
+ feas2 = (re_max <= 1e-6);
+ if (feas1 && feas2)
+ glp_ios_heur_sol(T, xstar);
+ else
+ xprintf("WARNING: PROXY HEURISTIC REPORTED WRONG SOLUTION; "
+ "SOLUTION REJECTED\n");
+ }
+#endif
+ xfree(xstar);
+ glp_delete_prob(prob);
+done: return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/simplex.h b/test/monniaux/glpk-4.65/src/simplex/simplex.h
new file mode 100644
index 00000000..9a5acdb2
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/simplex.h
@@ -0,0 +1,39 @@
+/* simplex.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#ifndef SIMPLEX_H
+#define SIMPLEX_H
+
+#include "prob.h"
+
+#define spx_primal _glp_spx_primal
+int spx_primal(glp_prob *P, const glp_smcp *parm);
+/* driver to the primal simplex method */
+
+#define spy_dual _glp_spy_dual
+int spy_dual(glp_prob *P, const glp_smcp *parm);
+/* driver to the dual simplex method */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxat.c b/test/monniaux/glpk-4.65/src/simplex/spxat.c
new file mode 100644
index 00000000..3570a18c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxat.c
@@ -0,0 +1,265 @@
+/* spxat.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "spxat.h"
+
+/***********************************************************************
+* spx_alloc_at - allocate constraint matrix in sparse row-wise format
+*
+* This routine allocates the memory for arrays needed to represent the
+* constraint matrix in sparse row-wise format. */
+
+void spx_alloc_at(SPXLP *lp, SPXAT *at)
+{ int m = lp->m;
+ int n = lp->n;
+ int nnz = lp->nnz;
+ at->ptr = talloc(1+m+1, int);
+ at->ind = talloc(1+nnz, int);
+ at->val = talloc(1+nnz, double);
+ at->work = talloc(1+n, double);
+ return;
+}
+
+/***********************************************************************
+* spx_build_at - build constraint matrix in sparse row-wise format
+*
+* This routine builds sparse row-wise representation of the constraint
+* matrix A using its sparse column-wise representation stored in the
+* lp object, and stores the result in the at object. */
+
+void spx_build_at(SPXLP *lp, SPXAT *at)
+{ int m = lp->m;
+ int n = lp->n;
+ int nnz = lp->nnz;
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ double *A_val = lp->A_val;
+ int *AT_ptr = at->ptr;
+ int *AT_ind = at->ind;
+ double *AT_val = at->val;
+ int i, k, ptr, end, pos;
+ /* calculate AT_ptr[i] = number of non-zeros in i-th row */
+ memset(&AT_ptr[1], 0, m * sizeof(int));
+ for (k = 1; k <= n; k++)
+ { ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ AT_ptr[A_ind[ptr]]++;
+ }
+ /* set AT_ptr[i] to position after last element in i-th row */
+ AT_ptr[1]++;
+ for (i = 2; i <= m; i++)
+ AT_ptr[i] += AT_ptr[i-1];
+ xassert(AT_ptr[m] == nnz+1);
+ AT_ptr[m+1] = nnz+1;
+ /* build row-wise representation and re-arrange AT_ptr[i] */
+ for (k = n; k >= 1; k--)
+ { /* copy elements from k-th column to corresponding rows */
+ ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ { pos = --AT_ptr[A_ind[ptr]];
+ AT_ind[pos] = k;
+ AT_val[pos] = A_val[ptr];
+ }
+ }
+ xassert(AT_ptr[1] == 1);
+ return;
+}
+
+/***********************************************************************
+* spx_at_prod - compute product y := y + s * A'* x
+*
+* This routine computes the product:
+*
+* y := y + s * A'* x,
+*
+* where A' is a matrix transposed to the mxn-matrix A of constraint
+* coefficients, x is a m-vector, s is a scalar, y is a n-vector.
+*
+* The routine uses the row-wise representation of the matrix A and
+* computes the product as a linear combination:
+*
+* y := y + s * (A'[1] * x[1] + ... + A'[m] * x[m]),
+*
+* where A'[i] is i-th row of A, 1 <= i <= m. */
+
+void spx_at_prod(SPXLP *lp, SPXAT *at, double y[/*1+n*/], double s,
+ const double x[/*1+m*/])
+{ int m = lp->m;
+ int *AT_ptr = at->ptr;
+ int *AT_ind = at->ind;
+ double *AT_val = at->val;
+ int i, ptr, end;
+ double t;
+ for (i = 1; i <= m; i++)
+ { if (x[i] != 0.0)
+ { /* y := y + s * (i-th row of A) * x[i] */
+ t = s * x[i];
+ ptr = AT_ptr[i];
+ end = AT_ptr[i+1];
+ for (; ptr < end; ptr++)
+ y[AT_ind[ptr]] += AT_val[ptr] * t;
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* spx_nt_prod1 - compute product y := y + s * N'* x
+*
+* This routine computes the product:
+*
+* y := y + s * N'* x,
+*
+* where N' is a matrix transposed to the mx(n-m)-matrix N composed
+* from non-basic columns of the constraint matrix A, x is a m-vector,
+* s is a scalar, y is (n-m)-vector.
+*
+* If the flag ign is non-zero, the routine ignores the input content
+* of the array y assuming that y = 0. */
+
+void spx_nt_prod1(SPXLP *lp, SPXAT *at, double y[/*1+n-m*/], int ign,
+ double s, const double x[/*1+m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ double *work = at->work;
+ int j, k;
+ for (k = 1; k <= n; k++)
+ work[k] = 0.0;
+ if (!ign)
+ { for (j = 1; j <= n-m; j++)
+ work[head[m+j]] = y[j];
+ }
+ spx_at_prod(lp, at, work, s, x);
+ for (j = 1; j <= n-m; j++)
+ y[j] = work[head[m+j]];
+ return;
+}
+
+/***********************************************************************
+* spx_eval_trow1 - compute i-th row of simplex table
+*
+* This routine computes i-th row of the current simplex table
+* T = (T[i,j]) = - inv(B) * N, 1 <= i <= m, using representation of
+* the constraint matrix A in row-wise format.
+*
+* The vector rho = (rho[j]), which is i-th row of the basis inverse
+* inv(B), should be previously computed with the routine spx_eval_rho.
+* It is assumed that elements of this vector are stored in the array
+* locations rho[1], ..., rho[m].
+*
+* There exist two ways to compute the simplex table row.
+*
+* 1. T[i,j], j = 1,...,n-m, is computed as inner product:
+*
+* m
+* T[i,j] = - sum a[i,k] * rho[i],
+* i=1
+*
+* where N[j] = A[k] is a column of the constraint matrix corresponding
+* to non-basic variable xN[j]. The estimated number of operations in
+* this case is:
+*
+* n1 = (n - m) * (nnz(A) / n),
+*
+* (n - m) is the number of columns of N, nnz(A) / n is the average
+* number of non-zeros in one column of A and, therefore, of N.
+*
+* 2. The simplex table row is computed as part of a linear combination
+* of rows of A with coefficients rho[i] != 0. The estimated number
+* of operations in this case is:
+*
+* n2 = nnz(rho) * (nnz(A) / m),
+*
+* where nnz(rho) is the number of non-zeros in the vector rho,
+* nnz(A) / m is the average number of non-zeros in one row of A.
+*
+* If n1 < n2, the routine computes the simples table row using the
+* first way (like the routine spx_eval_trow). Otherwise, the routine
+* uses the second way calling the routine spx_nt_prod1.
+*
+* On exit components of the simplex table row are stored in the array
+* locations trow[1], ... trow[n-m]. */
+
+void spx_eval_trow1(SPXLP *lp, SPXAT *at, const double rho[/*1+m*/],
+ double trow[/*1+n-m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ int nnz = lp->nnz;
+ int i, j, nnz_rho;
+ double cnt1, cnt2;
+ /* determine nnz(rho) */
+ nnz_rho = 0;
+ for (i = 1; i <= m; i++)
+ { if (rho[i] != 0.0)
+ nnz_rho++;
+ }
+ /* estimate the number of operations for both ways */
+ cnt1 = (double)(n - m) * ((double)nnz / (double)n);
+ cnt2 = (double)nnz_rho * ((double)nnz / (double)m);
+ /* compute i-th row of simplex table */
+ if (cnt1 < cnt2)
+ { /* as inner products */
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ double *A_val = lp->A_val;
+ int *head = lp->head;
+ int k, ptr, end;
+ double tij;
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ /* compute t[i,j] = - N'[j] * pi */
+ tij = 0.0;
+ ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ tij -= A_val[ptr] * rho[A_ind[ptr]];
+ trow[j] = tij;
+ }
+ }
+ else
+ { /* as linear combination */
+ spx_nt_prod1(lp, at, trow, 1, -1.0, rho);
+ }
+ return;
+}
+
+/***********************************************************************
+* spx_free_at - deallocate constraint matrix in sparse row-wise format
+*
+* This routine deallocates the memory used for arrays of the program
+* object at. */
+
+void spx_free_at(SPXLP *lp, SPXAT *at)
+{ xassert(lp == lp);
+ tfree(at->ptr);
+ tfree(at->ind);
+ tfree(at->val);
+ tfree(at->work);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxat.h b/test/monniaux/glpk-4.65/src/simplex/spxat.h
new file mode 100644
index 00000000..98d5b003
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxat.h
@@ -0,0 +1,80 @@
+/* spxat.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#ifndef SPXAT_H
+#define SPXAT_H
+
+#include "spxlp.h"
+
+typedef struct SPXAT SPXAT;
+
+struct SPXAT
+{ /* mxn-matrix A of constraint coefficients in sparse row-wise
+ * format */
+ int *ptr; /* int ptr[1+m+1]; */
+ /* ptr[0] is not used;
+ * ptr[i], 1 <= i <= m, is starting position of i-th row in
+ * arrays ind and val; note that ptr[1] is always 1;
+ * ptr[m+1] indicates the position after the last element in
+ * arrays ind and val, i.e. ptr[m+1] = nnz+1, where nnz is the
+ * number of non-zero elements in matrix A;
+ * the length of i-th row (the number of non-zero elements in
+ * that row) can be calculated as ptr[i+1] - ptr[i] */
+ int *ind; /* int ind[1+nnz]; */
+ /* column indices */
+ double *val; /* double val[1+nnz]; */
+ /* non-zero element values */
+ double *work; /* double work[1+n]; */
+ /* working array */
+};
+
+#define spx_alloc_at _glp_spx_alloc_at
+void spx_alloc_at(SPXLP *lp, SPXAT *at);
+/* allocate constraint matrix in sparse row-wise format */
+
+#define spx_build_at _glp_spx_build_at
+void spx_build_at(SPXLP *lp, SPXAT *at);
+/* build constraint matrix in sparse row-wise format */
+
+#define spx_at_prod _glp_spx_at_prod
+void spx_at_prod(SPXLP *lp, SPXAT *at, double y[/*1+n*/], double s,
+ const double x[/*1+m*/]);
+/* compute product y := y + s * A'* x */
+
+#define spx_nt_prod1 _glp_spx_nt_prod1
+void spx_nt_prod1(SPXLP *lp, SPXAT *at, double y[/*1+n-m*/], int ign,
+ double s, const double x[/*1+m*/]);
+/* compute product y := y + s * N'* x */
+
+#define spx_eval_trow1 _glp_spx_eval_trow1
+void spx_eval_trow1(SPXLP *lp, SPXAT *at, const double rho[/*1+m*/],
+ double trow[/*1+n-m*/]);
+/* compute i-th row of simplex table */
+
+#define spx_free_at _glp_spx_free_at
+void spx_free_at(SPXLP *lp, SPXAT *at);
+/* deallocate constraint matrix in sparse row-wise format */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxchuzc.c b/test/monniaux/glpk-4.65/src/simplex/spxchuzc.c
new file mode 100644
index 00000000..c60ccabc
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxchuzc.c
@@ -0,0 +1,381 @@
+/* spxchuzc.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "spxchuzc.h"
+
+/***********************************************************************
+* spx_chuzc_sel - select eligible non-basic variables
+*
+* This routine selects eligible non-basic variables xN[j], whose
+* reduced costs d[j] have "wrong" sign, i.e. changing such xN[j] in
+* feasible direction improves (decreases) the objective function.
+*
+* Reduced costs of non-basic variables should be placed in the array
+* locations d[1], ..., d[n-m].
+*
+* Non-basic variable xN[j] is considered eligible if:
+*
+* d[j] <= -eps[j] and xN[j] can increase
+*
+* d[j] >= +eps[j] and xN[j] can decrease
+*
+* for
+*
+* eps[j] = tol + tol1 * |cN[j]|,
+*
+* where cN[j] is the objective coefficient at xN[j], tol and tol1 are
+* specified tolerances.
+*
+* On exit the routine stores indices j of eligible non-basic variables
+* xN[j] to the array locations list[1], ..., list[num] and returns the
+* number of such variables 0 <= num <= n-m. (If the parameter list is
+* specified as NULL, no indices are stored.) */
+
+int spx_chuzc_sel(SPXLP *lp, const double d[/*1+n-m*/], double tol,
+ double tol1, int list[/*1+n-m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int j, k, num;
+ double ck, eps;
+ num = 0;
+ /* walk thru list of non-basic variables */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ if (l[k] == u[k])
+ { /* xN[j] is fixed variable; skip it */
+ continue;
+ }
+ /* determine absolute tolerance eps[j] */
+ ck = c[k];
+ eps = tol + tol1 * (ck >= 0.0 ? +ck : -ck);
+ /* check if xN[j] is eligible */
+ if (d[j] <= -eps)
+ { /* xN[j] should be able to increase */
+ if (flag[j])
+ { /* but its upper bound is active */
+ continue;
+ }
+ }
+ else if (d[j] >= +eps)
+ { /* xN[j] should be able to decrease */
+ if (!flag[j] && l[k] != -DBL_MAX)
+ { /* but its lower bound is active */
+ continue;
+ }
+ }
+ else /* -eps < d[j] < +eps */
+ { /* xN[j] does not affect the objective function within the
+ * specified tolerance */
+ continue;
+ }
+ /* xN[j] is eligible non-basic variable */
+ num++;
+ if (list != NULL)
+ list[num] = j;
+ }
+ return num;
+}
+
+/***********************************************************************
+* spx_chuzc_std - choose non-basic variable (Dantzig's rule)
+*
+* This routine chooses most eligible non-basic variable xN[q]
+* according to Dantzig's ("standard") rule:
+*
+* d[q] = max |d[j]|,
+* j in J
+*
+* where J <= {1, ..., n-m} is the set of indices of eligible non-basic
+* variables, d[j] is the reduced cost of non-basic variable xN[j] in
+* the current basis.
+*
+* Reduced costs of non-basic variables should be placed in the array
+* locations d[1], ..., d[n-m].
+*
+* Indices of eligible non-basic variables j in J should be placed in
+* the array locations list[1], ..., list[num], where num = |J| > 0 is
+* the total number of such variables.
+*
+* On exit the routine returns q, the index of the non-basic variable
+* xN[q] chosen. */
+
+int spx_chuzc_std(SPXLP *lp, const double d[/*1+n-m*/], int num,
+ const int list[])
+{ int m = lp->m;
+ int n = lp->n;
+ int j, q, t;
+ double abs_dj, abs_dq;
+ xassert(0 < num && num <= n-m);
+ q = 0, abs_dq = -1.0;
+ for (t = 1; t <= num; t++)
+ { j = list[t];
+ abs_dj = (d[j] >= 0.0 ? +d[j] : -d[j]);
+ if (abs_dq < abs_dj)
+ q = j, abs_dq = abs_dj;
+ }
+ xassert(q != 0);
+ return q;
+}
+
+/***********************************************************************
+* spx_alloc_se - allocate pricing data block
+*
+* This routine allocates the memory for arrays used in the pricing
+* data block. */
+
+void spx_alloc_se(SPXLP *lp, SPXSE *se)
+{ int m = lp->m;
+ int n = lp->n;
+ se->valid = 0;
+ se->refsp = talloc(1+n, char);
+ se->gamma = talloc(1+n-m, double);
+ se->work = talloc(1+m, double);
+ return;
+}
+
+/***********************************************************************
+* spx_reset_refsp - reset reference space
+*
+* This routine resets (re-initializes) the reference space composing
+* it from variables which are non-basic in the current basis, and sets
+* all weights gamma[j] to 1. */
+
+void spx_reset_refsp(SPXLP *lp, SPXSE *se)
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ char *refsp = se->refsp;
+ double *gamma = se->gamma;
+ int j, k;
+ se->valid = 1;
+ memset(&refsp[1], 0, n * sizeof(char));
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ refsp[k] = 1;
+ gamma[j] = 1.0;
+ }
+ return;
+}
+
+/***********************************************************************
+* spx_eval_gamma_j - compute projected steepest edge weight directly
+*
+* This routine computes projected steepest edge weight gamma[j],
+* 1 <= j <= n-m, for the current basis directly with the formula:
+*
+* m
+* gamma[j] = delta[j] + sum eta[i] * T[i,j]**2,
+* i=1
+*
+* where T[i,j] is element of the current simplex table, and
+*
+* ( 1, if xB[i] is in the reference space
+* eta[i] = {
+* ( 0, otherwise
+*
+* ( 1, if xN[j] is in the reference space
+* delta[j] = {
+* ( 0, otherwise
+*
+* NOTE: For testing/debugging only. */
+
+double spx_eval_gamma_j(SPXLP *lp, SPXSE *se, int j)
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ char *refsp = se->refsp;
+ double *tcol = se->work;
+ int i, k;
+ double gamma_j;
+ xassert(se->valid);
+ xassert(1 <= j && j <= n-m);
+ k = head[m+j]; /* x[k] = xN[j] */
+ gamma_j = (refsp[k] ? 1.0 : 0.0);
+ spx_eval_tcol(lp, j, tcol);
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ if (refsp[k])
+ gamma_j += tcol[i] * tcol[i];
+ }
+ return gamma_j;
+}
+
+/***********************************************************************
+* spx_chuzc_pse - choose non-basic variable (projected steepest edge)
+*
+* This routine chooses most eligible non-basic variable xN[q]
+* according to the projected steepest edge method:
+*
+* d[q]**2 d[j]**2
+* -------- = max -------- ,
+* gamma[q] j in J gamma[j]
+*
+* where J <= {1, ..., n-m} is the set of indices of eligible non-basic
+* variable, d[j] is the reduced cost of non-basic variable xN[j] in
+* the current basis, gamma[j] is the projected steepest edge weight.
+*
+* Reduced costs of non-basic variables should be placed in the array
+* locations d[1], ..., d[n-m].
+*
+* Indices of eligible non-basic variables j in J should be placed in
+* the array locations list[1], ..., list[num], where num = |J| > 0 is
+* the total number of such variables.
+*
+* On exit the routine returns q, the index of the non-basic variable
+* xN[q] chosen. */
+
+int spx_chuzc_pse(SPXLP *lp, SPXSE *se, const double d[/*1+n-m*/],
+ int num, const int list[])
+{ int m = lp->m;
+ int n = lp->n;
+ double *gamma = se->gamma;
+ int j, q, t;
+ double best, temp;
+ xassert(se->valid);
+ xassert(0 < num && num <= n-m);
+ q = 0, best = -1.0;
+ for (t = 1; t <= num; t++)
+ { j = list[t];
+ /* FIXME */
+ if (gamma[j] < DBL_EPSILON)
+ temp = 0.0;
+ else
+ temp = (d[j] * d[j]) / gamma[j];
+ if (best < temp)
+ q = j, best = temp;
+ }
+ xassert(q != 0);
+ return q;
+}
+
+/***********************************************************************
+* spx_update_gamma - update projected steepest edge weights exactly
+*
+* This routine updates the vector gamma = (gamma[j]) of projected
+* steepest edge weights exactly, for the adjacent basis.
+*
+* On entry to the routine the content of the se object should be valid
+* and should correspond to the current basis.
+*
+* The parameter 1 <= p <= m specifies basic variable xB[p] which
+* becomes non-basic variable xN[q] in the adjacent basis.
+*
+* The parameter 1 <= q <= n-m specified non-basic variable xN[q] which
+* becomes basic variable xB[p] in the adjacent basis.
+*
+* It is assumed that the array trow contains elements of p-th (pivot)
+* row T'[p] of the simplex table in locations trow[1], ..., trow[n-m].
+* It is also assumed that the array tcol contains elements of q-th
+* (pivot) column T[q] of the simple table in locations tcol[1], ...,
+* tcol[m]. (These row and column should be computed for the current
+* basis.)
+*
+* For details about the formulae used see the program documentation.
+*
+* The routine also computes the relative error:
+*
+* e = |gamma[q] - gamma'[q]| / (1 + |gamma[q]|),
+*
+* where gamma'[q] is the weight for xN[q] on entry to the routine,
+* and returns e on exit. (If e happens to be large enough, the calling
+* program may reset the reference space, since other weights also may
+* be inaccurate.) */
+
+double spx_update_gamma(SPXLP *lp, SPXSE *se, int p, int q,
+ const double trow[/*1+n-m*/], const double tcol[/*1+m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ char *refsp = se->refsp;
+ double *gamma = se->gamma;
+ double *u = se->work;
+ int i, j, k, ptr, end;
+ double gamma_q, delta_q, e, r, s, t1, t2;
+ xassert(se->valid);
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n-m);
+ /* compute gamma[q] in current basis more accurately; also
+ * compute auxiliary vector u */
+ k = head[m+q]; /* x[k] = xN[q] */
+ gamma_q = delta_q = (refsp[k] ? 1.0 : 0.0);
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ if (refsp[k])
+ { gamma_q += tcol[i] * tcol[i];
+ u[i] = tcol[i];
+ }
+ else
+ u[i] = 0.0;
+ }
+ bfd_btran(lp->bfd, u);
+ /* compute relative error in gamma[q] */
+ e = fabs(gamma_q - gamma[q]) / (1.0 + gamma_q);
+ /* compute new gamma[q] */
+ gamma[q] = gamma_q / (tcol[p] * tcol[p]);
+ /* compute new gamma[j] for all j != q */
+ for (j = 1; j <= n-m; j++)
+ { if (j == q)
+ continue;
+ if (-1e-9 < trow[j] && trow[j] < +1e-9)
+ { /* T[p,j] is close to zero; gamma[j] is not changed */
+ continue;
+ }
+ /* compute r[j] = T[p,j] / T[p,q] */
+ r = trow[j] / tcol[p];
+ /* compute inner product s[j] = N'[j] * u, where N[j] = A[k]
+ * is constraint matrix column corresponding to xN[j] */
+ s = 0.0;
+ k = head[m+j]; /* x[k] = xN[j] */
+ ptr = lp->A_ptr[k];
+ end = lp->A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ s += lp->A_val[ptr] * u[lp->A_ind[ptr]];
+ /* compute new gamma[j] */
+ t1 = gamma[j] + r * (r * gamma_q + s + s);
+ t2 = (refsp[k] ? 1.0 : 0.0) + delta_q * r * r;
+ gamma[j] = (t1 >= t2 ? t1 : t2);
+ }
+ return e;
+}
+
+/***********************************************************************
+* spx_free_se - deallocate pricing data block
+*
+* This routine deallocates the memory used for arrays in the pricing
+* data block. */
+
+void spx_free_se(SPXLP *lp, SPXSE *se)
+{ xassert(lp == lp);
+ tfree(se->refsp);
+ tfree(se->gamma);
+ tfree(se->work);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxchuzc.h b/test/monniaux/glpk-4.65/src/simplex/spxchuzc.h
new file mode 100644
index 00000000..c09cca9a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxchuzc.h
@@ -0,0 +1,85 @@
+/* spxchuzc.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#ifndef SPXCHUZC_H
+#define SPXCHUZC_H
+
+#include "spxlp.h"
+
+#define spx_chuzc_sel _glp_spx_chuzc_sel
+int spx_chuzc_sel(SPXLP *lp, const double d[/*1+n-m*/], double tol,
+ double tol1, int list[/*1+n-m*/]);
+/* select eligible non-basic variables */
+
+#define spx_chuzc_std _glp_spx_chuzc_std
+int spx_chuzc_std(SPXLP *lp, const double d[/*1+n-m*/], int num,
+ const int list[]);
+/* choose non-basic variable (Dantzig's rule) */
+
+typedef struct SPXSE SPXSE;
+
+struct SPXSE
+{ /* projected steepest edge and Devex pricing data block */
+ int valid;
+ /* content validity flag */
+ char *refsp; /* char refsp[1+n]; */
+ /* refsp[0] is not used;
+ * refsp[k], 1 <= k <= n, is the flag meaning that variable x[k]
+ * is in the reference space */
+ double *gamma; /* double gamma[1+n-m]; */
+ /* gamma[0] is not used;
+ * gamma[j], 1 <= j <= n-m, is the weight for reduced cost d[j]
+ * of non-basic variable xN[j] in the current basis */
+ double *work; /* double work[1+m]; */
+ /* working array */
+};
+
+#define spx_alloc_se _glp_spx_alloc_se
+void spx_alloc_se(SPXLP *lp, SPXSE *se);
+/* allocate pricing data block */
+
+#define spx_reset_refsp _glp_spx_reset_refsp
+void spx_reset_refsp(SPXLP *lp, SPXSE *se);
+/* reset reference space */
+
+#define spx_eval_gamma_j _glp_spx_eval_gamma_j
+double spx_eval_gamma_j(SPXLP *lp, SPXSE *se, int j);
+/* compute projeted steepest edge weight directly */
+
+#define spx_chuzc_pse _glp_spx_chuzc_pse
+int spx_chuzc_pse(SPXLP *lp, SPXSE *se, const double d[/*1+n-m*/],
+ int num, const int list[]);
+/* choose non-basic variable (projected steepest edge) */
+
+#define spx_update_gamma _glp_spx_update_gamma
+double spx_update_gamma(SPXLP *lp, SPXSE *se, int p, int q,
+ const double trow[/*1+n-m*/], const double tcol[/*1+m*/]);
+/* update projected steepest edge weights exactly */
+
+#define spx_free_se _glp_spx_free_se
+void spx_free_se(SPXLP *lp, SPXSE *se);
+/* deallocate pricing data block */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxchuzr.c b/test/monniaux/glpk-4.65/src/simplex/spxchuzr.c
new file mode 100644
index 00000000..8bef77ba
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxchuzr.c
@@ -0,0 +1,594 @@
+/* spxchuzr.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015-2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "spxchuzr.h"
+
+/***********************************************************************
+* spx_chuzr_std - choose basic variable (textbook ratio test)
+*
+* This routine implements an improved textbook ratio test to choose
+* basic variable xB[p].
+*
+* The parameter phase specifies the search phase:
+*
+* 1 - searching for feasible basic solution. In this case the routine
+* uses artificial bounds of basic variables that correspond to
+* breakpoints of the penalty function:
+*
+* ( lB[i], if cB[i] = 0
+* (
+* lB'[i] = { uB[i], if cB[i] > 0
+* (
+* ( -inf, if cB[i] < 0
+*
+* ( uB[i], if cB[i] = 0
+* (
+* uB'[i] = { +inf, if cB[i] > 0
+* (
+* ( lB[i], if cB[i] < 0
+*
+* where lB[i] and uB[i] are original bounds of variable xB[i],
+* cB[i] is the penalty (objective) coefficient of that variable.
+*
+* 2 - searching for optimal basic solution. In this case the routine
+* uses original bounds of basic variables.
+*
+* Current values of basic variables should be placed in the array
+* locations beta[1], ..., beta[m].
+*
+* The parameter 1 <= q <= n-m specifies the index of non-basic
+* variable xN[q] chosen.
+*
+* The parameter s specifies the direction in which xN[q] changes:
+* s = +1.0 means xN[q] increases, and s = -1.0 means xN[q] decreases.
+* (Thus, the corresponding ray parameter is theta = s (xN[q] - f[q]),
+* where f[q] is the active bound of xN[q] in the current basis.)
+*
+* Elements of q-th simplex table column T[q] = (t[i,q]) corresponding
+* to non-basic variable xN[q] should be placed in the array locations
+* tcol[1], ..., tcol[m].
+*
+* The parameter tol_piv specifies a tolerance for elements of the
+* simplex table column T[q]. If |t[i,q]| < tol_piv, basic variable
+* xB[i] is skipped, i.e. it is assumed that it does not depend on the
+* ray parameter theta.
+*
+* The parameters tol and tol1 specify tolerances used to increase the
+* choice freedom by simulating an artificial degeneracy as follows.
+* If beta[i] <= lB[i] + delta[i], where delta[i] = tol + tol1 |lB[i]|,
+* it is assumed that beta[i] is exactly the same as lB[i]. Similarly,
+* if beta[i] >= uB[i] - delta[i], where delta[i] = tol + tol1 |uB[i]|,
+* it is assumed that beta[i] is exactly the same as uB[i].
+*
+* The routine determines the index 1 <= p <= m of basic variable xB[p]
+* that reaches its (lower or upper) bound first on increasing the ray
+* parameter theta, stores the bound flag (0 - lower bound or fixed
+* value, 1 - upper bound) to the location pointed to by the pointer
+* p_flag, and returns the index p. If non-basic variable xN[q] is
+* double-bounded and reaches its opposite bound first, the routine
+* returns (-1). And if the ray parameter may increase unlimitedly, the
+* routine returns zero.
+*
+* Should note that the bound flag stored to the location pointed to by
+* p_flag corresponds to the original (not artficial) bound of variable
+* xB[p] and defines the active bound flag lp->flag[q] to be set in the
+* adjacent basis for that basic variable. */
+
+int spx_chuzr_std(SPXLP *lp, int phase, const double beta[/*1+m*/],
+ int q, double s, const double tcol[/*1+m*/], int *p_flag,
+ double tol_piv, double tol, double tol1)
+{ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ int i, i_flag, k, p;
+ double alfa, biga, delta, lk, uk, teta, teta_min;
+ xassert(phase == 1 || phase == 2);
+ xassert(1 <= q && q <= n-m);
+ xassert(s == +1.0 || s == -1.0);
+ /* determine initial teta_min */
+ k = head[m+q]; /* x[k] = xN[q] */
+ if (l[k] == -DBL_MAX || u[k] == +DBL_MAX)
+ { /* xN[q] has no opposite bound */
+ p = 0, *p_flag = 0, teta_min = DBL_MAX, biga = 0.0;
+ }
+ else
+ { /* xN[q] have both lower and upper bounds */
+ p = -1, *p_flag = 0, teta_min = fabs(l[k] - u[k]), biga = 1.0;
+ }
+ /* walk thru the list of basic variables */
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ /* determine alfa such that delta xB[i] = alfa * teta */
+ alfa = s * tcol[i];
+ if (alfa <= -tol_piv)
+ { /* xB[i] decreases */
+ /* determine actual lower bound of xB[i] */
+ if (phase == 1 && c[k] < 0.0)
+ { /* xB[i] has no actual lower bound */
+ continue;
+ }
+ else if (phase == 1 && c[k] > 0.0)
+ { /* actual lower bound of xB[i] is its upper bound */
+ lk = u[k];
+ xassert(lk != +DBL_MAX);
+ i_flag = 1;
+ }
+ else
+ { /* actual lower bound of xB[i] is its original bound */
+ lk = l[k];
+ if (lk == -DBL_MAX)
+ continue;
+ i_flag = 0;
+ }
+ /* determine teta on which xB[i] reaches its lower bound */
+ delta = tol + tol1 * (lk >= 0.0 ? +lk : -lk);
+ if (beta[i] <= lk + delta)
+ teta = 0.0;
+ else
+ teta = (lk - beta[i]) / alfa;
+ }
+ else if (alfa >= +tol_piv)
+ { /* xB[i] increases */
+ /* determine actual upper bound of xB[i] */
+ if (phase == 1 && c[k] < 0.0)
+ { /* actual upper bound of xB[i] is its lower bound */
+ uk = l[k];
+ xassert(uk != -DBL_MAX);
+ i_flag = 0;
+ }
+ else if (phase == 1 && c[k] > 0.0)
+ { /* xB[i] has no actual upper bound */
+ continue;
+ }
+ else
+ { /* actual upper bound of xB[i] is its original bound */
+ uk = u[k];
+ if (uk == +DBL_MAX)
+ continue;
+ i_flag = 1;
+ }
+ /* determine teta on which xB[i] reaches its upper bound */
+ delta = tol + tol1 * (uk >= 0.0 ? +uk : -uk);
+ if (beta[i] >= uk - delta)
+ teta = 0.0;
+ else
+ teta = (uk - beta[i]) / alfa;
+ }
+ else
+ { /* xB[i] does not depend on teta */
+ continue;
+ }
+ /* choose basic variable xB[p] for which teta is minimal */
+ xassert(teta >= 0.0);
+ alfa = (alfa >= 0.0 ? +alfa : -alfa);
+ if (teta_min > teta || (teta_min == teta && biga < alfa))
+ p = i, *p_flag = i_flag, teta_min = teta, biga = alfa;
+ }
+ /* if xB[p] is fixed variable, adjust its bound flag */
+ if (p > 0)
+ { k = head[p];
+ if (l[k] == u[k])
+ *p_flag = 0;
+ }
+ return p;
+}
+
+/***********************************************************************
+* spx_chuzr_harris - choose basic variable (Harris' ratio test)
+*
+* This routine implements Harris' ratio test to choose basic variable
+* xB[p].
+*
+* All the parameters, except tol and tol1, as well as the returned
+* value have the same meaning as for the routine spx_chuzr_std (see
+* above).
+*
+* The parameters tol and tol1 specify tolerances on bound violations
+* for basic variables. For the lower bound of basic variable xB[i] the
+* tolerance is delta[i] = tol + tol1 |lB[i]|, and for the upper bound
+* the tolerance is delta[i] = tol + tol1 |uB[i]|. */
+
+int spx_chuzr_harris(SPXLP *lp, int phase, const double beta[/*1+m*/],
+ int q, double s, const double tcol[/*1+m*/], int *p_flag,
+ double tol_piv, double tol, double tol1)
+{ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ int i, i_flag, k, p;
+ double alfa, biga, delta, lk, uk, teta, teta_min;
+ xassert(phase == 1 || phase == 2);
+ xassert(1 <= q && q <= n-m);
+ xassert(s == +1.0 || s == -1.0);
+ /*--------------------------------------------------------------*/
+ /* first pass: determine teta_min for relaxed bounds */
+ /*--------------------------------------------------------------*/
+ teta_min = DBL_MAX;
+ /* walk thru the list of basic variables */
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ /* determine alfa such that delta xB[i] = alfa * teta */
+ alfa = s * tcol[i];
+ if (alfa <= -tol_piv)
+ { /* xB[i] decreases */
+ /* determine actual lower bound of xB[i] */
+ if (phase == 1 && c[k] < 0.0)
+ { /* xB[i] has no actual lower bound */
+ continue;
+ }
+ else if (phase == 1 && c[k] > 0.0)
+ { /* actual lower bound of xB[i] is its upper bound */
+ lk = u[k];
+ xassert(lk != +DBL_MAX);
+ }
+ else
+ { /* actual lower bound of xB[i] is its original bound */
+ lk = l[k];
+ if (lk == -DBL_MAX)
+ continue;
+ }
+ /* determine teta on which xB[i] reaches its relaxed lower
+ * bound */
+ delta = tol + tol1 * (lk >= 0.0 ? +lk : -lk);
+ if (beta[i] < lk)
+ teta = - delta / alfa;
+ else
+ teta = ((lk - delta) - beta[i]) / alfa;
+ }
+ else if (alfa >= +tol_piv)
+ { /* xB[i] increases */
+ /* determine actual upper bound of xB[i] */
+ if (phase == 1 && c[k] < 0.0)
+ { /* actual upper bound of xB[i] is its lower bound */
+ uk = l[k];
+ xassert(uk != -DBL_MAX);
+ }
+ else if (phase == 1 && c[k] > 0.0)
+ { /* xB[i] has no actual upper bound */
+ continue;
+ }
+ else
+ { /* actual upper bound of xB[i] is its original bound */
+ uk = u[k];
+ if (uk == +DBL_MAX)
+ continue;
+ }
+ /* determine teta on which xB[i] reaches its relaxed upper
+ * bound */
+ delta = tol + tol1 * (uk >= 0.0 ? +uk : -uk);
+ if (beta[i] > uk)
+ teta = + delta / alfa;
+ else
+ teta = ((uk + delta) - beta[i]) / alfa;
+ }
+ else
+ { /* xB[i] does not depend on teta */
+ continue;
+ }
+ xassert(teta >= 0.0);
+ if (teta_min > teta)
+ teta_min = teta;
+ }
+ /*--------------------------------------------------------------*/
+ /* second pass: choose basic variable xB[p] */
+ /*--------------------------------------------------------------*/
+ k = head[m+q]; /* x[k] = xN[q] */
+ if (l[k] != -DBL_MAX && u[k] != +DBL_MAX)
+ { /* xN[q] has both lower and upper bounds */
+ if (fabs(l[k] - u[k]) <= teta_min)
+ { /* and reaches its opposite bound */
+ p = -1, *p_flag = 0;
+ goto done;
+ }
+ }
+ if (teta_min == DBL_MAX)
+ { /* teta may increase unlimitedly */
+ p = 0, *p_flag = 0;
+ goto done;
+ }
+ /* nothing is chosen so far */
+ p = 0, *p_flag = 0, biga = 0.0;
+ /* walk thru the list of basic variables */
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ /* determine alfa such that delta xB[i] = alfa * teta */
+ alfa = s * tcol[i];
+ if (alfa <= -tol_piv)
+ { /* xB[i] decreases */
+ /* determine actual lower bound of xB[i] */
+ if (phase == 1 && c[k] < 0.0)
+ { /* xB[i] has no actual lower bound */
+ continue;
+ }
+ else if (phase == 1 && c[k] > 0.0)
+ { /* actual lower bound of xB[i] is its upper bound */
+ lk = u[k];
+ xassert(lk != +DBL_MAX);
+ i_flag = 1;
+ }
+ else
+ { /* actual lower bound of xB[i] is its original bound */
+ lk = l[k];
+ if (lk == -DBL_MAX)
+ continue;
+ i_flag = 0;
+ }
+ /* determine teta on which xB[i] reaches its lower bound */
+ teta = (lk - beta[i]) / alfa;
+ }
+ else if (alfa >= +tol_piv)
+ { /* xB[i] increases */
+ /* determine actual upper bound of xB[i] */
+ if (phase == 1 && c[k] < 0.0)
+ { /* actual upper bound of xB[i] is its lower bound */
+ uk = l[k];
+ xassert(uk != -DBL_MAX);
+ i_flag = 0;
+ }
+ else if (phase == 1 && c[k] > 0.0)
+ { /* xB[i] has no actual upper bound */
+ continue;
+ }
+ else
+ { /* actual upper bound of xB[i] is its original bound */
+ uk = u[k];
+ if (uk == +DBL_MAX)
+ continue;
+ i_flag = 1;
+ }
+ /* determine teta on which xB[i] reaches its upper bound */
+ teta = (uk - beta[i]) / alfa;
+ }
+ else
+ { /* xB[i] does not depend on teta */
+ continue;
+ }
+ /* choose basic variable for which teta is not greater than
+ * teta_min determined for relaxed bounds and which has best
+ * (largest in magnitude) pivot */
+ alfa = (alfa >= 0.0 ? +alfa : -alfa);
+ if (teta <= teta_min && biga < alfa)
+ p = i, *p_flag = i_flag, biga = alfa;
+ }
+ /* something must be chosen */
+ xassert(1 <= p && p <= m);
+ /* if xB[p] is fixed variable, adjust its bound flag */
+ k = head[p];
+ if (l[k] == u[k])
+ *p_flag = 0;
+done: return p;
+}
+
+#if 1 /* 22/VI-2017 */
+/***********************************************************************
+* spx_ls_eval_bp - determine penalty function break points
+*
+* This routine determines break points of the penalty function (which
+* is the sum of primal infeasibilities).
+*
+* The parameters lp, beta, q, dq, tcol, and tol_piv have the same
+* meaning as for the routine spx_chuzr_std (see above).
+*
+* The routine stores the break-points determined to the array elements
+* bp[1], ..., bp[nbp] in *arbitrary* order, where 0 <= nbp <= 2*m+1 is
+* the number of break-points returned by the routine on exit. */
+
+int spx_ls_eval_bp(SPXLP *lp, const double beta[/*1+m*/],
+ int q, double dq, const double tcol[/*1+m*/], double tol_piv,
+ SPXBP bp[/*1+2*m+1*/])
+{ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ int i, k, nbp;
+ double s, alfa;
+ xassert(1 <= q && q <= n-m);
+ xassert(dq != 0.0);
+ s = (dq < 0.0 ? +1.0 : -1.0);
+ nbp = 0;
+ /* if chosen non-basic variable xN[q] is double-bounded, include
+ * it in the list, because it can cross its opposite bound */
+ k = head[m+q]; /* x[k] = xN[q] */
+ if (l[k] != -DBL_MAX && u[k] != +DBL_MAX)
+ { nbp++;
+ bp[nbp].i = 0;
+ xassert(l[k] < u[k]); /* xN[q] cannot be fixed */
+ bp[nbp].teta = u[k] - l[k];
+ bp[nbp].dc = s;
+ }
+ /* build the list of all basic variables xB[i] that can cross
+ * their bound(s) for the ray parameter 0 <= teta < teta_max */
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ xassert(l[k] <= u[k]);
+ /* determine alfa such that (delta xB[i]) = alfa * teta */
+ alfa = s * tcol[i];
+ if (alfa >= +tol_piv)
+ { /* xB[i] increases on increasing teta */
+ if (l[k] == u[k])
+ { /* xB[i] is fixed at lB[i] = uB[i] */
+ if (c[k] <= 0.0)
+ { /* increasing xB[i] can cross its fixed value lB[i],
+ * because currently xB[i] <= lB[i] */
+ nbp++;
+ bp[nbp].i = +i;
+ bp[nbp].teta = (l[k] - beta[i]) / alfa;
+ /* if xB[i] > lB[i] then cB[i] = +1 */
+ bp[nbp].dc = +1.0 - c[k];
+ }
+ }
+ else
+ { if (l[k] != -DBL_MAX && c[k] < 0.0)
+ { /* increasing xB[i] can cross its lower bound lB[i],
+ * because currently xB[i] < lB[i] */
+ nbp++;
+ bp[nbp].i = +i;
+ bp[nbp].teta = (l[k] - beta[i]) / alfa;
+ bp[nbp].dc = +1.0;
+ }
+ if (u[k] != +DBL_MAX && c[k] <= 0.0)
+ { /* increasing xB[i] can cross its upper bound uB[i],
+ * because currently xB[i] does not violate it */
+ nbp++;
+ bp[nbp].i = -i;
+ bp[nbp].teta = (u[k] - beta[i]) / alfa;
+ bp[nbp].dc = +1.0;
+ }
+ }
+ }
+ else if (alfa <= -tol_piv)
+ { /* xB[i] decreases on increasing teta */
+ if (l[k] == u[k])
+ { /* xB[i] is fixed at lB[i] = uB[i] */
+ if (c[k] >= 0.0)
+ { /* decreasing xB[i] can cross its fixed value lB[i],
+ * because currently xB[i] >= lB[i] */
+ nbp++;
+ bp[nbp].i = +i;
+ bp[nbp].teta = (l[k] - beta[i]) / alfa;
+ /* if xB[i] < lB[i] then cB[i] = -1 */
+ bp[nbp].dc = -1.0 - c[k];
+ }
+ }
+ else
+ { if (l[k] != -DBL_MAX && c[k] >= 0.0)
+ { /* decreasing xB[i] can cross its lower bound lB[i],
+ * because currently xB[i] does not violate it */
+ nbp++;
+ bp[nbp].i = +i;
+ bp[nbp].teta = (l[k] - beta[i]) / alfa;
+ bp[nbp].dc = -1.0;
+ }
+ if (u[k] != +DBL_MAX && c[k] > 0.0)
+ { /* decreasing xB[i] can cross its upper bound uB[i],
+ * because currently xB[i] > uB[i] */
+ nbp++;
+ bp[nbp].i = -i;
+ bp[nbp].teta = (u[k] - beta[i]) / alfa;
+ bp[nbp].dc = -1.0;
+ }
+ }
+ }
+ else
+ { /* xB[i] does not depend on teta within a tolerance */
+ continue;
+ }
+ /* teta < 0 may happen only due to round-off errors when the
+ * current value of xB[i] is *close* to its (lower or upper)
+ * bound; in this case we replace teta by exact zero */
+ if (bp[nbp].teta < 0.0)
+ bp[nbp].teta = 0.0;
+ }
+ xassert(nbp <= 2*m+1);
+ return nbp;
+}
+#endif
+
+#if 1 /* 22/VI-2017 */
+/***********************************************************************
+* spx_ls_select_bp - select and process penalty function break points
+*
+* This routine selects a next portion of the penalty function break
+* points and processes them.
+*
+* On entry to the routine it is assumed that break points bp[1], ...,
+* bp[num] are already processed, and slope is the penalty function
+* slope to the right of the last processed break point bp[num].
+* (Initially, when num = 0, slope should be specified as -fabs(d[q]),
+* where d[q] is the reduced cost of chosen non-basic variable xN[q].)
+*
+* The routine selects break points among bp[num+1], ..., bp[nbp], for
+* which teta <= teta_lim, and moves these break points to the array
+* elements bp[num+1], ..., bp[num1], where num <= num1 <= 2*m+1 is the
+* new number of processed break points returned by the routine on
+* exit. Then the routine sorts the break points by ascending teta and
+* computes the change of the penalty function relative to its value at
+* teta = 0.
+*
+* On exit the routine also replaces the parameter slope with a new
+* value that corresponds to the new last break-point bp[num1]. */
+
+static int CDECL fcmp(const void *v1, const void *v2)
+{ const SPXBP *p1 = v1, *p2 = v2;
+ if (p1->teta < p2->teta)
+ return -1;
+ else if (p1->teta > p2->teta)
+ return +1;
+ else
+ return 0;
+}
+
+int spx_ls_select_bp(SPXLP *lp, const double tcol[/*1+m*/],
+ int nbp, SPXBP bp[/*1+m+m+1*/], int num, double *slope, double
+ teta_lim)
+{ int m = lp->m;
+ int i, t, num1;
+ double teta, dz;
+ xassert(0 <= num && num <= nbp && nbp <= m+m+1);
+ /* select a new portion of break points */
+ num1 = num;
+ for (t = num+1; t <= nbp; t++)
+ { if (bp[t].teta <= teta_lim)
+ { /* move break point to the beginning of the new portion */
+ num1++;
+ i = bp[num1].i, teta = bp[num1].teta, dz = bp[num1].dc;
+ bp[num1].i = bp[t].i, bp[num1].teta = bp[t].teta,
+ bp[num1].dc = bp[t].dc;
+ bp[t].i = i, bp[t].teta = teta, bp[t].dc = dz;
+ }
+ }
+ /* sort new break points bp[num+1], ..., bp[num1] by ascending
+ * the ray parameter teta */
+ if (num1 - num > 1)
+ qsort(&bp[num+1], num1 - num, sizeof(SPXBP), fcmp);
+ /* calculate the penalty function change at the new break points
+ * selected */
+ for (t = num+1; t <= num1; t++)
+ { /* calculate the penalty function change relative to its value
+ * at break point bp[t-1] */
+ dz = (*slope) * (bp[t].teta - (t == 1 ? 0.0 : bp[t-1].teta));
+ /* calculate the penalty function change relative to its value
+ * at teta = 0 */
+ bp[t].dz = (t == 1 ? 0.0 : bp[t-1].dz) + dz;
+ /* calculate a new slope of the penalty function to the right
+ * of the current break point bp[t] */
+ i = (bp[t].i >= 0 ? bp[t].i : -bp[t].i);
+ xassert(0 <= i && i <= m);
+ if (i == 0)
+ *slope += fabs(1.0 * bp[t].dc);
+ else
+ *slope += fabs(tcol[i] * bp[t].dc);
+ }
+ return num1;
+}
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxchuzr.h b/test/monniaux/glpk-4.65/src/simplex/spxchuzr.h
new file mode 100644
index 00000000..3ec90050
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxchuzr.h
@@ -0,0 +1,77 @@
+/* spxchuzr.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015-2017 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/>.
+***********************************************************************/
+
+#ifndef SPXCHUZR_H
+#define SPXCHUZR_H
+
+#include "spxlp.h"
+
+#define spx_chuzr_std _glp_spx_chuzr_std
+int spx_chuzr_std(SPXLP *lp, int phase, const double beta[/*1+m*/],
+ int q, double s, const double tcol[/*1+m*/], int *p_flag,
+ double tol_piv, double tol, double tol1);
+/* choose basic variable (textbook ratio test) */
+
+#define spx_chuzr_harris _glp_spx_chuzr_harris
+int spx_chuzr_harris(SPXLP *lp, int phase, const double beta[/*1+m*/],
+ int q, double s, const double tcol[/*1+m*/], int *p_flag,
+ double tol_piv, double tol, double tol1);
+/* choose basic variable (Harris' ratio test) */
+
+#if 1 /* 22/VI-2017 */
+typedef struct SPXBP SPXBP;
+
+struct SPXBP
+{ /* penalty function (sum of infeasibilities) break point */
+ int i;
+ /* basic variable xB[i], 1 <= i <= m, that intersects its bound
+ * at this break point
+ * i > 0 if xB[i] intersects its lower bound (or fixed value)
+ * i < 0 if xB[i] intersects its upper bound
+ * i = 0 if xN[q] intersects its opposite bound */
+ double teta;
+ /* ray parameter value, teta >= 0, at this break point */
+ double dc;
+ /* increment of the penalty function coefficient cB[i] at this
+ * break point */
+ double dz;
+ /* increment, z[t] - z[0], of the penalty function at this break
+ * point */
+};
+
+#define spx_ls_eval_bp _glp_spx_ls_eval_bp
+int spx_ls_eval_bp(SPXLP *lp, const double beta[/*1+m*/],
+ int q, double dq, const double tcol[/*1+m*/], double tol_piv,
+ SPXBP bp[/*1+2*m+1*/]);
+/* determine penalty function break points */
+
+#define spx_ls_select_bp _glp_spx_ls_select_bp
+int spx_ls_select_bp(SPXLP *lp, const double tcol[/*1+m*/],
+ int nbp, SPXBP bp[/*1+m+m+1*/], int num, double *slope, double
+ teta_lim);
+/* select and process penalty function break points */
+#endif
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxlp.c b/test/monniaux/glpk-4.65/src/simplex/spxlp.c
new file mode 100644
index 00000000..90ce2636
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxlp.c
@@ -0,0 +1,819 @@
+/* spxlp.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "spxlp.h"
+
+/***********************************************************************
+* spx_factorize - compute factorization of current basis matrix
+*
+* This routine computes factorization of the current basis matrix B.
+*
+* If the factorization has been successfully computed, the routine
+* validates it and returns zero. Otherwise, the routine invalidates
+* the factorization and returns the code provided by the factorization
+* driver (bfd_factorize). */
+
+static int jth_col(void *info, int j, int ind[], double val[])
+{ /* provide column B[j] */
+ SPXLP *lp = info;
+ int m = lp->m;
+ int *A_ptr = lp->A_ptr;
+ int *head = lp->head;
+ int k, ptr, len;
+ xassert(1 <= j && j <= m);
+ k = head[j]; /* x[k] = xB[j] */
+ ptr = A_ptr[k];
+ len = A_ptr[k+1] - ptr;
+ memcpy(&ind[1], &lp->A_ind[ptr], len * sizeof(int));
+ memcpy(&val[1], &lp->A_val[ptr], len * sizeof(double));
+ return len;
+}
+
+int spx_factorize(SPXLP *lp)
+{ int ret;
+ ret = bfd_factorize(lp->bfd, lp->m, jth_col, lp);
+ lp->valid = (ret == 0);
+ return ret;
+}
+
+/***********************************************************************
+* spx_eval_beta - compute current values of basic variables
+*
+* This routine computes vector beta = (beta[i]) of current values of
+* basic variables xB = (xB[i]). (Factorization of the current basis
+* matrix should be valid.)
+*
+* First the routine computes a modified vector of right-hand sides:
+*
+* n-m
+* y = b - N * f = b - sum N[j] * f[j],
+* j=1
+*
+* where b = (b[i]) is the original vector of right-hand sides, N is
+* a matrix composed from columns of the original constraint matrix A,
+* which (columns) correspond to non-basic variables, f = (f[j]) is the
+* vector of active bounds of non-basic variables xN = (xN[j]),
+* N[j] = A[k] is a column of matrix A corresponding to non-basic
+* variable xN[j] = x[k], f[j] is current active bound lN[j] = l[k] or
+* uN[j] = u[k] of non-basic variable xN[j] = x[k]. The matrix-vector
+* product N * f is computed as a linear combination of columns of N,
+* so if f[j] = 0, column N[j] can be skipped.
+*
+* Then the routine performs FTRAN to compute the vector beta:
+*
+* beta = inv(B) * y.
+*
+* On exit the routine stores components of the vector beta to array
+* locations beta[1], ..., beta[m]. */
+
+void spx_eval_beta(SPXLP *lp, double beta[/*1+m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ double *A_val = lp->A_val;
+ double *b = lp->b;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int j, k, ptr, end;
+ double fj, *y;
+ /* compute y = b - N * xN */
+ /* y := b */
+ y = beta;
+ memcpy(&y[1], &b[1], m * sizeof(double));
+ /* y := y - N * f */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ /* f[j] := active bound of xN[j] */
+ fj = flag[j] ? u[k] : l[k];
+ if (fj == 0.0 || fj == -DBL_MAX)
+ { /* either xN[j] has zero active bound or it is unbounded;
+ * in the latter case its value is assumed to be zero */
+ continue;
+ }
+ /* y := y - N[j] * f[j] */
+ ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ y[A_ind[ptr]] -= A_val[ptr] * fj;
+ }
+ /* compute beta = inv(B) * y */
+ xassert(lp->valid);
+ bfd_ftran(lp->bfd, beta);
+ return;
+}
+
+/***********************************************************************
+* spx_eval_obj - compute current value of objective function
+*
+* This routine computes the value of the objective function in the
+* current basic solution:
+*
+* z = cB'* beta + cN'* f + c[0] =
+*
+* m n-m
+* = sum cB[i] * beta[i] + sum cN[j] * f[j] + c[0],
+* i=1 j=1
+*
+* where cB = (cB[i]) is the vector of objective coefficients at basic
+* variables, beta = (beta[i]) is the vector of current values of basic
+* variables, cN = (cN[j]) is the vector of objective coefficients at
+* non-basic variables, f = (f[j]) is the vector of current active
+* bounds of non-basic variables, c[0] is the constant term of the
+* objective function.
+*
+* It as assumed that components of the vector beta are stored in the
+* array locations beta[1], ..., beta[m]. */
+
+double spx_eval_obj(SPXLP *lp, const double beta[/*1+m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int i, j, k;
+ double fj, z;
+ /* compute z = cB'* beta + cN'* f + c0 */
+ /* z := c0 */
+ z = c[0];
+ /* z := z + cB'* beta */
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ z += c[k] * beta[i];
+ }
+ /* z := z + cN'* f */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ /* f[j] := active bound of xN[j] */
+ fj = flag[j] ? u[k] : l[k];
+ if (fj == 0.0 || fj == -DBL_MAX)
+ { /* either xN[j] has zero active bound or it is unbounded;
+ * in the latter case its value is assumed to be zero */
+ continue;
+ }
+ z += c[k] * fj;
+ }
+ return z;
+}
+
+/***********************************************************************
+* spx_eval_pi - compute simplex multipliers in current basis
+*
+* This routine computes vector pi = (pi[i]) of simplex multipliers in
+* the current basis. (Factorization of the current basis matrix should
+* be valid.)
+*
+* The vector pi is computed by performing BTRAN:
+*
+* pi = inv(B') * cB,
+*
+* where cB = (cB[i]) is the vector of objective coefficients at basic
+* variables xB = (xB[i]).
+*
+* On exit components of vector pi are stored in the array locations
+* pi[1], ..., pi[m]. */
+
+void spx_eval_pi(SPXLP *lp, double pi[/*1+m*/])
+{ int m = lp->m;
+ double *c = lp->c;
+ int *head = lp->head;
+ int i;
+ double *cB;
+ /* construct cB */
+ cB = pi;
+ for (i = 1; i <= m; i++)
+ cB[i] = c[head[i]];
+ /* compute pi = inv(B) * cB */
+ bfd_btran(lp->bfd, pi);
+ return;
+}
+
+/***********************************************************************
+* spx_eval_dj - compute reduced cost of j-th non-basic variable
+*
+* This routine computes reduced cost d[j] of non-basic variable
+* xN[j] = x[k], 1 <= j <= n-m, in the current basic solution:
+*
+* d[j] = c[k] - A'[k] * pi,
+*
+* where c[k] is the objective coefficient at x[k], A[k] is k-th column
+* of the constraint matrix, pi is the vector of simplex multipliers in
+* the current basis.
+*
+* It as assumed that components of the vector pi are stored in the
+* array locations pi[1], ..., pi[m]. */
+
+double spx_eval_dj(SPXLP *lp, const double pi[/*1+m*/], int j)
+{ int m = lp->m;
+ int n = lp->n;
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ double *A_val = lp->A_val;
+ int k, ptr, end;
+ double dj;
+ xassert(1 <= j && j <= n-m);
+ k = lp->head[m+j]; /* x[k] = xN[j] */
+ /* dj := c[k] */
+ dj = lp->c[k];
+ /* dj := dj - A'[k] * pi */
+ ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ dj -= A_val[ptr] * pi[A_ind[ptr]];
+ return dj;
+}
+
+/***********************************************************************
+* spx_eval_tcol - compute j-th column of simplex table
+*
+* This routine computes j-th column of the current simplex table
+* T = (T[i,j]) = - inv(B) * N, 1 <= j <= n-m. (Factorization of the
+* current basis matrix should be valid.)
+*
+* The simplex table column is computed by performing FTRAN:
+*
+* tcol = - inv(B) * N[j],
+*
+* where B is the current basis matrix, N[j] = A[k] is a column of the
+* constraint matrix corresponding to non-basic variable xN[j] = x[k].
+*
+* On exit components of the simplex table column are stored in the
+* array locations tcol[1], ... tcol[m]. */
+
+void spx_eval_tcol(SPXLP *lp, int j, double tcol[/*1+m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ double *A_val = lp->A_val;
+ int *head = lp->head;
+ int i, k, ptr, end;
+ xassert(1 <= j && j <= n-m);
+ k = head[m+j]; /* x[k] = xN[j] */
+ /* compute tcol = - inv(B) * N[j] */
+ for (i = 1; i <= m; i++)
+ tcol[i] = 0.0;
+ ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ tcol[A_ind[ptr]] = -A_val[ptr];
+ bfd_ftran(lp->bfd, tcol);
+ return;
+}
+
+/***********************************************************************
+* spx_eval_rho - compute i-th row of basis matrix inverse
+*
+* This routine computes i-th row of the matrix inv(B), where B is
+* the current basis matrix, 1 <= i <= m. (Factorization of the current
+* basis matrix should be valid.)
+*
+* The inverse row is computed by performing BTRAN:
+*
+* rho = inv(B') * e[i],
+*
+* where e[i] is i-th column of unity matrix.
+*
+* On exit components of the row are stored in the array locations
+* row[1], ..., row[m]. */
+
+void spx_eval_rho(SPXLP *lp, int i, double rho[/*1+m*/])
+{ int m = lp->m;
+ int j;
+ xassert(1 <= i && i <= m);
+ /* compute rho = inv(B') * e[i] */
+ for (j = 1; j <= m; j++)
+ rho[j] = 0.0;
+ rho[i] = 1.0;
+ bfd_btran(lp->bfd, rho);
+ return;
+}
+
+#if 1 /* 31/III-2016 */
+void spx_eval_rho_s(SPXLP *lp, int i, FVS *rho)
+{ /* sparse version of spx_eval_rho */
+ int m = lp->m;
+ xassert(1 <= i && i <= m);
+ /* compute rho = inv(B') * e[i] */
+ xassert(rho->n == m);
+ fvs_clear_vec(rho);
+ rho->nnz = 1;
+ rho->ind[1] = i;
+ rho->vec[i] = 1.0;
+ bfd_btran_s(lp->bfd, rho);
+ return;
+}
+#endif
+
+/***********************************************************************
+* spx_eval_tij - compute element T[i,j] of simplex table
+*
+* This routine computes element T[i,j] of the current simplex table
+* T = - inv(B) * N, 1 <= i <= m, 1 <= j <= n-m, with the following
+* formula:
+*
+* T[i,j] = - N'[j] * rho, (1)
+*
+* where N[j] = A[k] is a column of the constraint matrix corresponding
+* to non-basic variable xN[j] = x[k], rho is i-th row of the inverse
+* matrix inv(B).
+*
+* It as assumed that components of the inverse row rho = (rho[j]) are
+* stored in the array locations rho[1], ..., rho[m]. */
+
+double spx_eval_tij(SPXLP *lp, const double rho[/*1+m*/], int j)
+{ int m = lp->m;
+ int n = lp->n;
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ double *A_val = lp->A_val;
+ int k, ptr, end;
+ double tij;
+ xassert(1 <= j && j <= n-m);
+ k = lp->head[m+j]; /* x[k] = xN[j] */
+ /* compute t[i,j] = - N'[j] * pi */
+ tij = 0.0;
+ ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ tij -= A_val[ptr] * rho[A_ind[ptr]];
+ return tij;
+}
+
+/***********************************************************************
+* spx_eval_trow - compute i-th row of simplex table
+*
+* This routine computes i-th row of the current simplex table
+* T = (T[i,j]) = - inv(B) * N, 1 <= i <= m.
+*
+* Elements of the row T[i] = (T[i,j]), j = 1, ..., n-m, are computed
+* directly with the routine spx_eval_tij.
+*
+* The vector rho = (rho[j]), which is i-th row of the basis inverse
+* inv(B), should be previously computed with the routine spx_eval_rho.
+* It is assumed that elements of this vector are stored in the array
+* locations rho[1], ..., rho[m].
+*
+* On exit components of the simplex table row are stored in the array
+* locations trow[1], ... trow[n-m].
+*
+* NOTE: For testing/debugging only. */
+
+void spx_eval_trow(SPXLP *lp, const double rho[/*1+m*/], double
+ trow[/*1+n-m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ int j;
+ for (j = 1; j <= n-m; j++)
+ trow[j] = spx_eval_tij(lp, rho, j);
+ return;
+}
+
+/***********************************************************************
+* spx_update_beta - update values of basic variables
+*
+* This routine updates the vector beta = (beta[i]) of values of basic
+* variables xB = (xB[i]) for the adjacent basis.
+*
+* On entry to the routine components of the vector beta in the current
+* basis should be placed in array locations beta[1], ..., beta[m].
+*
+* The parameter 1 <= p <= m specifies basic variable xB[p] which
+* becomes non-basic variable xN[q] in the adjacent basis. The special
+* case p < 0 means that non-basic variable xN[q] goes from its current
+* active bound to opposite one in the adjacent basis.
+*
+* If the flag p_flag is set, the active bound of xB[p] in the adjacent
+* basis is set to its upper bound. (In this case xB[p] should have its
+* upper bound and should not be fixed.)
+*
+* The parameter 1 <= q <= n-m specifies non-basic variable xN[q] which
+* becomes basic variable xB[p] in the adjacent basis (if 1 <= p <= m),
+* or goes to its opposite bound (if p < 0). (In the latter case xN[q]
+* should have both lower and upper bounds and should not be fixed.)
+*
+* It is assumed that the array tcol contains elements of q-th (pivot)
+* column T[q] of the simple table in locations tcol[1], ..., tcol[m].
+* (This column should be computed for the current basis.)
+*
+* First, the routine determines the increment of basic variable xB[p]
+* in the adjacent basis (but only if 1 <= p <= m):
+*
+* ( - beta[p], if -inf < xB[p] < +inf
+* (
+* delta xB[p] = { lB[p] - beta[p], if p_flag = 0
+* (
+* ( uB[p] - beta[p], if p_flag = 1
+*
+* where beta[p] is the value of xB[p] in the current basis, lB[p] and
+* uB[p] are its lower and upper bounds. Then, the routine determines
+* the increment of non-basic variable xN[q] in the adjacent basis:
+*
+* ( delta xB[p] / T[p,q], if 1 <= p <= m
+* (
+* delta xN[q] = { uN[q] - lN[q], if p < 0 and f[q] = lN[q]
+* (
+* ( lN[q] - uN[q], if p < 0 and f[q] = uN[q]
+*
+* where T[p,q] is the pivot element of the simplex table, f[q] is the
+* active bound of xN[q] in the current basis.
+*
+* If 1 <= p <= m, in the adjacent basis xN[q] becomes xB[p], so:
+*
+* new beta[p] = f[q] + delta xN[q].
+*
+* Values of other basic variables xB[i] for 1 <= i <= m, i != p, are
+* updated as follows:
+*
+* new beta[i] = beta[i] + T[i,q] * delta xN[q].
+*
+* On exit the routine stores updated components of the vector beta to
+* the same locations, where the input vector beta was stored. */
+
+void spx_update_beta(SPXLP *lp, double beta[/*1+m*/], int p,
+ int p_flag, int q, const double tcol[/*1+m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int i, k;
+ double delta_p, delta_q;
+ if (p < 0)
+ { /* special case: xN[q] goes to its opposite bound */
+ xassert(1 <= q && q <= n-m);
+ /* xN[q] should be double-bounded variable */
+ k = head[m+q]; /* x[k] = xN[q] */
+ xassert(l[k] != -DBL_MAX && u[k] != +DBL_MAX && l[k] != u[k]);
+ /* determine delta xN[q] */
+ if (flag[q])
+ { /* xN[q] goes from its upper bound to its lower bound */
+ delta_q = l[k] - u[k];
+ }
+ else
+ { /* xN[q] goes from its lower bound to its upper bound */
+ delta_q = u[k] - l[k];
+ }
+ }
+ else
+ { /* xB[p] leaves the basis, xN[q] enters the basis */
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n-m);
+ /* determine delta xB[p] */
+ k = head[p]; /* x[k] = xB[p] */
+ if (p_flag)
+ { /* xB[p] goes to its upper bound */
+ xassert(l[k] != u[k] && u[k] != +DBL_MAX);
+ delta_p = u[k] - beta[p];
+ }
+ else if (l[k] == -DBL_MAX)
+ { /* unbounded xB[p] becomes non-basic (unusual case) */
+ xassert(u[k] == +DBL_MAX);
+ delta_p = 0.0 - beta[p];
+ }
+ else
+ { /* xB[p] goes to its lower bound or becomes fixed */
+ delta_p = l[k] - beta[p];
+ }
+ /* determine delta xN[q] */
+ delta_q = delta_p / tcol[p];
+ /* compute new beta[p], which is the value of xN[q] in the
+ * adjacent basis */
+ k = head[m+q]; /* x[k] = xN[q] */
+ if (flag[q])
+ { /* xN[q] has its upper bound active */
+ xassert(l[k] != u[k] && u[k] != +DBL_MAX);
+ beta[p] = u[k] + delta_q;
+ }
+ else if (l[k] == -DBL_MAX)
+ { /* xN[q] is non-basic unbounded variable */
+ xassert(u[k] == +DBL_MAX);
+ beta[p] = 0.0 + delta_q;
+ }
+ else
+ { /* xN[q] has its lower bound active or is fixed (latter
+ * case is unusual) */
+ beta[p] = l[k] + delta_q;
+ }
+ }
+ /* compute new beta[i] for all i != p */
+ for (i = 1; i <= m; i++)
+ { if (i != p)
+ beta[i] += tcol[i] * delta_q;
+ }
+ return;
+}
+
+#if 1 /* 30/III-2016 */
+void spx_update_beta_s(SPXLP *lp, double beta[/*1+m*/], int p,
+ int p_flag, int q, const FVS *tcol)
+{ /* sparse version of spx_update_beta */
+ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int nnz = tcol->nnz;
+ int *ind = tcol->ind;
+ double *vec = tcol->vec;
+ int i, k;
+ double delta_p, delta_q;
+ xassert(tcol->n == m);
+ if (p < 0)
+ { /* special case: xN[q] goes to its opposite bound */
+#if 0 /* 11/VI-2017 */
+ /* FIXME: not tested yet */
+ xassert(0);
+#endif
+ xassert(1 <= q && q <= n-m);
+ /* xN[q] should be double-bounded variable */
+ k = head[m+q]; /* x[k] = xN[q] */
+ xassert(l[k] != -DBL_MAX && u[k] != +DBL_MAX && l[k] != u[k]);
+ /* determine delta xN[q] */
+ if (flag[q])
+ { /* xN[q] goes from its upper bound to its lower bound */
+ delta_q = l[k] - u[k];
+ }
+ else
+ { /* xN[q] goes from its lower bound to its upper bound */
+ delta_q = u[k] - l[k];
+ }
+ }
+ else
+ { /* xB[p] leaves the basis, xN[q] enters the basis */
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n-m);
+ /* determine delta xB[p] */
+ k = head[p]; /* x[k] = xB[p] */
+ if (p_flag)
+ { /* xB[p] goes to its upper bound */
+ xassert(l[k] != u[k] && u[k] != +DBL_MAX);
+ delta_p = u[k] - beta[p];
+ }
+ else if (l[k] == -DBL_MAX)
+ { /* unbounded xB[p] becomes non-basic (unusual case) */
+ xassert(u[k] == +DBL_MAX);
+ delta_p = 0.0 - beta[p];
+ }
+ else
+ { /* xB[p] goes to its lower bound or becomes fixed */
+ delta_p = l[k] - beta[p];
+ }
+ /* determine delta xN[q] */
+ delta_q = delta_p / vec[p];
+ /* compute new beta[p], which is the value of xN[q] in the
+ * adjacent basis */
+ k = head[m+q]; /* x[k] = xN[q] */
+ if (flag[q])
+ { /* xN[q] has its upper bound active */
+ xassert(l[k] != u[k] && u[k] != +DBL_MAX);
+ beta[p] = u[k] + delta_q;
+ }
+ else if (l[k] == -DBL_MAX)
+ { /* xN[q] is non-basic unbounded variable */
+ xassert(u[k] == +DBL_MAX);
+ beta[p] = 0.0 + delta_q;
+ }
+ else
+ { /* xN[q] has its lower bound active or is fixed (latter
+ * case is unusual) */
+ beta[p] = l[k] + delta_q;
+ }
+ }
+ /* compute new beta[i] for all i != p */
+ for (k = 1; k <= nnz; k++)
+ { i = ind[k];
+ if (i != p)
+ beta[i] += vec[i] * delta_q;
+ }
+ return;
+}
+#endif
+
+/***********************************************************************
+* spx_update_d - update reduced costs of non-basic variables
+*
+* This routine updates the vector d = (d[j]) of reduced costs of
+* non-basic variables xN = (xN[j]) for the adjacent basis.
+*
+* On entry to the routine components of the vector d in the current
+* basis should be placed in locations d[1], ..., d[n-m].
+*
+* The parameter 1 <= p <= m specifies basic variable xB[p] which
+* becomes non-basic variable xN[q] in the adjacent basis.
+*
+* The parameter 1 <= q <= n-m specified non-basic variable xN[q] which
+* becomes basic variable xB[p] in the adjacent basis.
+*
+* It is assumed that the array trow contains elements of p-th (pivot)
+* row T'[p] of the simplex table in locations trow[1], ..., trow[n-m].
+* It is also assumed that the array tcol contains elements of q-th
+* (pivot) column T[q] of the simple table in locations tcol[1], ...,
+* tcol[m]. (These row and column should be computed for the current
+* basis.)
+*
+* First, the routine computes more accurate reduced cost d[q] in the
+* current basis using q-th column of the simplex table:
+*
+* n-m
+* d[q] = cN[q] + sum t[i,q] * cB[i],
+* i=1
+*
+* where cN[q] and cB[i] are objective coefficients at variables xN[q]
+* and xB[i], resp. The routine also computes the relative error:
+*
+* e = |d[q] - d'[q]| / (1 + |d[q]|),
+*
+* where d'[q] is the reduced cost of xN[q] on entry to the routine,
+* and returns e on exit. (If e happens to be large enough, the calling
+* program may compute the reduced costs directly, since other reduced
+* costs also may be inaccurate.)
+*
+* In the adjacent basis xB[p] becomes xN[q], so:
+*
+* new d[q] = d[q] / T[p,q],
+*
+* where T[p,q] is the pivot element of the simplex table (it is taken
+* from column T[q] as more accurate). Reduced costs of other non-basic
+* variables xN[j] for 1 <= j <= n-m, j != q, are updated as follows:
+*
+* new d[j] = d[j] + T[p,j] * new d[q].
+*
+* On exit the routine stores updated components of the vector d to the
+* same locations, where the input vector d was stored. */
+
+double spx_update_d(SPXLP *lp, double d[/*1+n-m*/], int p, int q,
+ const double trow[/*1+n-m*/], const double tcol[/*1+m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ int *head = lp->head;
+ int i, j, k;
+ double dq, e;
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n);
+ /* compute d[q] in current basis more accurately */
+ k = head[m+q]; /* x[k] = xN[q] */
+ dq = c[k];
+ for (i = 1; i <= m; i++)
+ dq += tcol[i] * c[head[i]];
+ /* compute relative error in d[q] */
+ e = fabs(dq - d[q]) / (1.0 + fabs(dq));
+ /* compute new d[q], which is the reduced cost of xB[p] in the
+ * adjacent basis */
+ d[q] = (dq /= tcol[p]);
+ /* compute new d[j] for all j != q */
+ for (j = 1; j <= n-m; j++)
+ { if (j != q)
+ d[j] -= trow[j] * dq;
+ }
+ return e;
+}
+
+#if 1 /* 30/III-2016 */
+double spx_update_d_s(SPXLP *lp, double d[/*1+n-m*/], int p, int q,
+ const FVS *trow, const FVS *tcol)
+{ /* sparse version of spx_update_d */
+ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ int *head = lp->head;
+ int trow_nnz = trow->nnz;
+ int *trow_ind = trow->ind;
+ double *trow_vec = trow->vec;
+ int tcol_nnz = tcol->nnz;
+ int *tcol_ind = tcol->ind;
+ double *tcol_vec = tcol->vec;
+ int i, j, k;
+ double dq, e;
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n);
+ xassert(trow->n == n-m);
+ xassert(tcol->n == m);
+ /* compute d[q] in current basis more accurately */
+ k = head[m+q]; /* x[k] = xN[q] */
+ dq = c[k];
+ for (k = 1; k <= tcol_nnz; k++)
+ { i = tcol_ind[k];
+ dq += tcol_vec[i] * c[head[i]];
+ }
+ /* compute relative error in d[q] */
+ e = fabs(dq - d[q]) / (1.0 + fabs(dq));
+ /* compute new d[q], which is the reduced cost of xB[p] in the
+ * adjacent basis */
+ d[q] = (dq /= tcol_vec[p]);
+ /* compute new d[j] for all j != q */
+ for (k = 1; k <= trow_nnz; k++)
+ { j = trow_ind[k];
+ if (j != q)
+ d[j] -= trow_vec[j] * dq;
+ }
+ return e;
+}
+#endif
+
+/***********************************************************************
+* spx_change_basis - change current basis to adjacent one
+*
+* This routine changes the current basis to the adjacent one making
+* necessary changes in lp->head and lp->flag members.
+*
+* The parameters p, p_flag, and q have the same meaning as for the
+* routine spx_update_beta. */
+
+void spx_change_basis(SPXLP *lp, int p, int p_flag, int q)
+{ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int k;
+ if (p < 0)
+ { /* special case: xN[q] goes to its opposite bound */
+ xassert(1 <= q && q <= n-m);
+ /* xN[q] should be double-bounded variable */
+ k = head[m+q]; /* x[k] = xN[q] */
+ xassert(l[k] != -DBL_MAX && u[k] != +DBL_MAX && l[k] != u[k]);
+ /* change active bound flag */
+ flag[q] = 1 - flag[q];
+ }
+ else
+ { /* xB[p] leaves the basis, xN[q] enters the basis */
+ xassert(1 <= p && p <= m);
+ xassert(p_flag == 0 || p_flag == 1);
+ xassert(1 <= q && q <= n-m);
+ k = head[p]; /* xB[p] = x[k] */
+ if (p_flag)
+ { /* xB[p] goes to its upper bound */
+ xassert(l[k] != u[k] && u[k] != +DBL_MAX);
+ }
+ /* swap xB[p] and xN[q] in the basis */
+ head[p] = head[m+q], head[m+q] = k;
+ /* and set active bound flag for new xN[q] */
+ lp->flag[q] = p_flag;
+ }
+ return;
+}
+
+/***********************************************************************
+* spx_update_invb - update factorization of basis matrix
+*
+* This routine updates factorization of the basis matrix B when i-th
+* column of B is replaced by k-th column of the constraint matrix A.
+*
+* The parameter 1 <= i <= m specifies the number of column of matrix B
+* to be replaced by a new column.
+*
+* The parameter 1 <= k <= n specifies the number of column of matrix A
+* to be used for replacement.
+*
+* If the factorization has been successfully updated, the routine
+* validates it and returns zero. Otherwise, the routine invalidates
+* the factorization and returns the code provided by the factorization
+* driver (bfd_update). */
+
+int spx_update_invb(SPXLP *lp, int i, int k)
+{ int m = lp->m;
+ int n = lp->n;
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ double *A_val = lp->A_val;
+ int ptr, len, ret;
+ xassert(1 <= i && i <= m);
+ xassert(1 <= k && k <= n);
+ ptr = A_ptr[k];
+ len = A_ptr[k+1] - ptr;
+ ret = bfd_update(lp->bfd, i, len, &A_ind[ptr-1], &A_val[ptr-1]);
+ lp->valid = (ret == 0);
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxlp.h b/test/monniaux/glpk-4.65/src/simplex/spxlp.h
new file mode 100644
index 00000000..29a135fe
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxlp.h
@@ -0,0 +1,234 @@
+/* spxlp.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#ifndef SPXLP_H
+#define SPXLP_H
+
+#include "bfd.h"
+
+/***********************************************************************
+* The structure SPXLP describes LP problem and its current basis.
+*
+* It is assumed that LP problem has the following formulation (this is
+* so called "working format"):
+*
+* z = c'* x + c0 -> min (1)
+*
+* A * x = b (2)
+*
+* l <= x <= u (3)
+*
+* where:
+*
+* x = (x[k]) is a n-vector of variables;
+*
+* z is an objective function;
+*
+* c = (c[k]) is a n-vector of objective coefficients;
+*
+* c0 is a constant term of the objective function;
+*
+* A = (a[i,k]) is a mxn-matrix of constraint coefficients;
+*
+* b = (b[i]) is a m-vector of right-hand sides;
+*
+* l = (l[k]) is a n-vector of lower bounds of variables;
+*
+* u = (u[k]) is a n-vector of upper bounds of variables.
+*
+* If variable x[k] has no lower (upper) bound, it is formally assumed
+* that l[k] = -inf (u[k] = +inf). Variable having no bounds is called
+* free (unbounded) variable. If l[k] = u[k], variable x[k] is assumed
+* to be fixed.
+*
+* It is also assumed that matrix A has full row rank: rank(A) = m,
+* i.e. all its rows are linearly independent, so m <= n.
+*
+* The (current) basis is defined by an appropriate permutation matrix
+* P of order n such that:
+*
+* ( xB )
+* P * x = ( ), (4)
+* ( xN )
+*
+* where xB = (xB[i]) is a m-vector of basic variables, xN = (xN[j]) is
+* a (n-m)-vector of non-basic variables. If a non-basic variable xN[j]
+* has both lower and upper bounds, there is used an additional flag to
+* indicate which bound is active.
+*
+* From (2) and (4) it follows that:
+*
+* A * P'* P * x = b <=> B * xB + N * xN = b, (5)
+*
+* where P' is a matrix transposed to P, and
+*
+* A * P' = (B | N). (6)
+*
+* Here B is the basis matrix, which is a square non-singular matrix
+* of order m composed from columns of matrix A that correspond to
+* basic variables xB, and N is a mx(n-m) matrix composed from columns
+* of matrix A that correspond to non-basic variables xN. */
+
+typedef struct SPXLP SPXLP;
+
+struct SPXLP
+{ /* LP problem data and its (current) basis */
+ int m;
+ /* number of equality constraints, m > 0 */
+ int n;
+ /* number of variables, n >= m */
+ int nnz;
+ /* number of non-zeros in constraint matrix A */
+ /*--------------------------------------------------------------*/
+ /* mxn-matrix A of constraint coefficients in sparse column-wise
+ * format */
+ int *A_ptr; /* int A_ptr[1+n+1]; */
+ /* A_ptr[0] is not used;
+ * A_ptr[k], 1 <= k <= n, is starting position of k-th column in
+ * arrays A_ind and A_val; note that A_ptr[1] is always 1;
+ * A_ptr[n+1] indicates the position after the last element in
+ * arrays A_ind and A_val, i.e. A_ptr[n+1] = nnz+1, where nnz is
+ * the number of non-zero elements in matrix A;
+ * the length of k-th column (the number of non-zero elements in
+ * that column) can be calculated as A_ptr[k+1] - A_ptr[k] */
+ int *A_ind; /* int A_ind[1+nnz]; */
+ /* row indices */
+ double *A_val; /* double A_val[1+nnz]; */
+ /* non-zero element values (constraint coefficients) */
+ /*--------------------------------------------------------------*/
+ /* principal vectors of LP formulation */
+ double *b; /* double b[1+m]; */
+ /* b[0] is not used;
+ * b[i], 1 <= i <= m, is the right-hand side of i-th equality
+ * constraint */
+ double *c; /* double c[1+n]; */
+ /* c[0] is the constant term of the objective function;
+ * c[k], 1 <= k <= n, is the objective function coefficient at
+ * variable x[k] */
+ double *l; /* double l[1+n]; */
+ /* l[0] is not used;
+ * l[k], 1 <= k <= n, is the lower bound of variable x[k];
+ * if x[k] has no lower bound, l[k] = -DBL_MAX */
+ double *u; /* double u[1+n]; */
+ /* u[0] is not used;
+ * u[k], 1 <= k <= n, is the upper bound of variable u[k];
+ * if x[k] has no upper bound, u[k] = +DBL_MAX;
+ * note that l[k] = u[k] means that x[k] is fixed variable */
+ /*--------------------------------------------------------------*/
+ /* LP basis */
+ int *head; /* int head[1+n]; */
+ /* basis header, which is permutation matrix P (4):
+ * head[0] is not used;
+ * head[i] = k means that xB[i] = x[k], 1 <= i <= m;
+ * head[m+j] = k, means that xN[j] = x[k], 1 <= j <= n-m */
+ char *flag; /* char flag[1+n-m]; */
+ /* flags of non-basic variables:
+ * flag[0] is not used;
+ * flag[j], 1 <= j <= n-m, indicates that non-basic variable
+ * xN[j] is non-fixed and has its upper bound active */
+ /*--------------------------------------------------------------*/
+ /* basis matrix B of order m stored in factorized form */
+ int valid;
+ /* factorization validity flag */
+ BFD *bfd;
+ /* driver to factorization of the basis matrix */
+};
+
+#define spx_factorize _glp_spx_factorize
+int spx_factorize(SPXLP *lp);
+/* compute factorization of current basis matrix */
+
+#define spx_eval_beta _glp_spx_eval_beta
+void spx_eval_beta(SPXLP *lp, double beta[/*1+m*/]);
+/* compute values of basic variables */
+
+#define spx_eval_obj _glp_spx_eval_obj
+double spx_eval_obj(SPXLP *lp, const double beta[/*1+m*/]);
+/* compute value of objective function */
+
+#define spx_eval_pi _glp_spx_eval_pi
+void spx_eval_pi(SPXLP *lp, double pi[/*1+m*/]);
+/* compute simplex multipliers */
+
+#define spx_eval_dj _glp_spx_eval_dj
+double spx_eval_dj(SPXLP *lp, const double pi[/*1+m*/], int j);
+/* compute reduced cost of j-th non-basic variable */
+
+#define spx_eval_tcol _glp_spx_eval_tcol
+void spx_eval_tcol(SPXLP *lp, int j, double tcol[/*1+m*/]);
+/* compute j-th column of simplex table */
+
+#define spx_eval_rho _glp_spx_eval_rho
+void spx_eval_rho(SPXLP *lp, int i, double rho[/*1+m*/]);
+/* compute i-th row of basis matrix inverse */
+
+#if 1 /* 31/III-2016 */
+#define spx_eval_rho_s _glp_spx_eval_rho_s
+void spx_eval_rho_s(SPXLP *lp, int i, FVS *rho);
+/* sparse version of spx_eval_rho */
+#endif
+
+#define spx_eval_tij _glp_spx_eval_tij
+double spx_eval_tij(SPXLP *lp, const double rho[/*1+m*/], int j);
+/* compute element T[i,j] of simplex table */
+
+#define spx_eval_trow _glp_spx_eval_trow
+void spx_eval_trow(SPXLP *lp, const double rho[/*1+m*/], double
+ trow[/*1+n-m*/]);
+/* compute i-th row of simplex table */
+
+#define spx_update_beta _glp_spx_update_beta
+void spx_update_beta(SPXLP *lp, double beta[/*1+m*/], int p,
+ int p_flag, int q, const double tcol[/*1+m*/]);
+/* update values of basic variables */
+
+#if 1 /* 30/III-2016 */
+#define spx_update_beta_s _glp_spx_update_beta_s
+void spx_update_beta_s(SPXLP *lp, double beta[/*1+m*/], int p,
+ int p_flag, int q, const FVS *tcol);
+/* sparse version of spx_update_beta */
+#endif
+
+#define spx_update_d _glp_spx_update_d
+double spx_update_d(SPXLP *lp, double d[/*1+n-m*/], int p, int q,
+ const double trow[/*1+n-m*/], const double tcol[/*1+m*/]);
+/* update reduced costs of non-basic variables */
+
+#if 1 /* 30/III-2016 */
+#define spx_update_d_s _glp_spx_update_d_s
+double spx_update_d_s(SPXLP *lp, double d[/*1+n-m*/], int p, int q,
+ const FVS *trow, const FVS *tcol);
+/* sparse version of spx_update_d */
+#endif
+
+#define spx_change_basis _glp_spx_change_basis
+void spx_change_basis(SPXLP *lp, int p, int p_flag, int q);
+/* change current basis to adjacent one */
+
+#define spx_update_invb _glp_spx_update_invb
+int spx_update_invb(SPXLP *lp, int i, int k);
+/* update factorization of basis matrix */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxnt.c b/test/monniaux/glpk-4.65/src/simplex/spxnt.c
new file mode 100644
index 00000000..7eaac852
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxnt.c
@@ -0,0 +1,303 @@
+/* spxnt.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "spxnt.h"
+
+/***********************************************************************
+* spx_alloc_nt - allocate matrix N in sparse row-wise format
+*
+* This routine allocates the memory for arrays needed to represent the
+* matrix N composed of non-basic columns of the constraint matrix A. */
+
+void spx_alloc_nt(SPXLP *lp, SPXNT *nt)
+{ int m = lp->m;
+ int nnz = lp->nnz;
+ nt->ptr = talloc(1+m, int);
+ nt->len = talloc(1+m, int);
+ nt->ind = talloc(1+nnz, int);
+ nt->val = talloc(1+nnz, double);
+ return;
+}
+
+/***********************************************************************
+* spx_init_nt - initialize row pointers for matrix N
+*
+* This routine initializes (sets up) row pointers for the matrix N
+* using column-wise representation of the constraint matrix A.
+*
+* This routine needs to be called only once. */
+
+void spx_init_nt(SPXLP *lp, SPXNT *nt)
+{ int m = lp->m;
+ int n = lp->n;
+ int nnz = lp->nnz;
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ int *NT_ptr = nt->ptr;
+ int *NT_len = nt->len;
+ int i, k, ptr, end;
+ /* calculate NT_len[i] = maximal number of non-zeros in i-th row
+ * of N = number of non-zeros in i-th row of A */
+ memset(&NT_len[1], 0, m * sizeof(int));
+ for (k = 1; k <= n; k++)
+ { ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ NT_len[A_ind[ptr]]++;
+ }
+ /* initialize row pointers NT_ptr[i], i = 1,...,n-m */
+ NT_ptr[1] = 1;
+ for (i = 2; i <= m; i++)
+ NT_ptr[i] = NT_ptr[i-1] + NT_len[i-1];
+ xassert(NT_ptr[m] + NT_len[m] == nnz+1);
+ return;
+}
+
+/***********************************************************************
+* spx_nt_add_col - add column N[j] = A[k] to matrix N
+*
+* This routine adds elements of column N[j] = A[k], 1 <= j <= n-m,
+* 1 <= k <= n, to the row-wise represntation of the matrix N. It is
+* assumed (with no check) that elements of the specified column are
+* missing in the row-wise represntation of N. */
+
+void spx_nt_add_col(SPXLP *lp, SPXNT *nt, int j, int k)
+{ int m = lp->m;
+ int n = lp->n;
+ int nnz = lp->nnz;
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ double *A_val = lp->A_val;
+ int *NT_ptr = nt->ptr;
+ int *NT_len = nt->len;
+ int *NT_ind = nt->ind;
+ double *NT_val = nt->val;
+ int i, ptr, end, pos;
+ xassert(1 <= j && j <= n-m);
+ xassert(1 <= k && k <= n);
+ ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ { i = A_ind[ptr];
+ /* add element N[i,j] = A[i,k] to i-th row of matrix N */
+ pos = NT_ptr[i] + (NT_len[i]++);
+ if (i < m)
+ xassert(pos < NT_ptr[i+1]);
+ else
+ xassert(pos <= nnz);
+ NT_ind[pos] = j;
+ NT_val[pos] = A_val[ptr];
+ }
+ return;
+}
+
+/***********************************************************************
+* spx_build_nt - build matrix N for current basis
+*
+* This routine builds the row-wise represntation of the matrix N
+* for the current basis by adding columns of the constraint matrix A
+* corresponding to non-basic variables. */
+
+void spx_build_nt(SPXLP *lp, SPXNT *nt)
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ int *NT_len = nt->len;
+ int j, k;
+ /* N := 0 */
+ memset(&NT_len[1], 0, m * sizeof(int));
+ /* add non-basic columns N[j] = A[k] */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ spx_nt_add_col(lp, nt, j, k);
+ }
+ return;
+}
+
+/***********************************************************************
+* spx_nt_del_col - remove column N[j] = A[k] from matrix N
+*
+* This routine removes elements of column N[j] = A[k], 1 <= j <= n-m,
+* 1 <= k <= n, from the row-wise representation of the matrix N. It is
+* assumed (with no check) that elements of the specified column are
+* present in the row-wise representation of N. */
+
+void spx_nt_del_col(SPXLP *lp, SPXNT *nt, int j, int k)
+{ int m = lp->m;
+ int n = lp->n;
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ int *NT_ptr = nt->ptr;
+ int *NT_len = nt->len;
+ int *NT_ind = nt->ind;
+ double *NT_val = nt->val;
+ int i, ptr, end, ptr1, end1;
+ xassert(1 <= j && j <= n-m);
+ xassert(1 <= k && k <= n);
+ ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ { i = A_ind[ptr];
+ /* find element N[i,j] = A[i,k] in i-th row of matrix N */
+ ptr1 = NT_ptr[i];
+ end1 = ptr1 + NT_len[i];
+ for (; NT_ind[ptr1] != j; ptr1++)
+ /* nop */;
+ xassert(ptr1 < end1);
+ /* and remove it from i-th row element list */
+ NT_len[i]--;
+ NT_ind[ptr1] = NT_ind[end1-1];
+ NT_val[ptr1] = NT_val[end1-1];
+ }
+ return;
+}
+
+/***********************************************************************
+* spx_update_nt - update matrix N for adjacent basis
+*
+* This routine updates the row-wise represntation of matrix N for
+* the adjacent basis, where column N[q], 1 <= q <= n-m, is replaced by
+* column B[p], 1 <= p <= m, of the current basis matrix B. */
+
+void spx_update_nt(SPXLP *lp, SPXNT *nt, int p, int q)
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n-m);
+ /* remove old column N[q] corresponding to variable xN[q] */
+ spx_nt_del_col(lp, nt, q, head[m+q]);
+ /* add new column N[q] corresponding to variable xB[p] */
+ spx_nt_add_col(lp, nt, q, head[p]);
+ return;
+}
+
+/***********************************************************************
+* spx_nt_prod - compute product y := y + s * N'* x
+*
+* This routine computes the product:
+*
+* y := y + s * N'* x,
+*
+* where N' is a matrix transposed to the mx(n-m)-matrix N composed
+* from non-basic columns of the constraint matrix A, x is a m-vector,
+* s is a scalar, y is (n-m)-vector.
+*
+* If the flag ign is non-zero, the routine ignores the input content
+* of the array y assuming that y = 0.
+*
+* The routine uses the row-wise representation of the matrix N and
+* computes the product as a linear combination:
+*
+* y := y + s * (N'[1] * x[1] + ... + N'[m] * x[m]),
+*
+* where N'[i] is i-th row of N, 1 <= i <= m. */
+
+void spx_nt_prod(SPXLP *lp, SPXNT *nt, double y[/*1+n-m*/], int ign,
+ double s, const double x[/*1+m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ int *NT_ptr = nt->ptr;
+ int *NT_len = nt->len;
+ int *NT_ind = nt->ind;
+ double *NT_val = nt->val;
+ int i, j, ptr, end;
+ double t;
+ if (ign)
+ { /* y := 0 */
+ for (j = 1; j <= n-m; j++)
+ y[j] = 0.0;
+ }
+ for (i = 1; i <= m; i++)
+ { if (x[i] != 0.0)
+ { /* y := y + s * (i-th row of N) * x[i] */
+ t = s * x[i];
+ ptr = NT_ptr[i];
+ end = ptr + NT_len[i];
+ for (; ptr < end; ptr++)
+ y[NT_ind[ptr]] += NT_val[ptr] * t;
+ }
+ }
+ return;
+}
+
+#if 1 /* 31/III-2016 */
+void spx_nt_prod_s(SPXLP *lp, SPXNT *nt, FVS *y, int ign, double s,
+ const FVS *x, double eps)
+{ /* sparse version of spx_nt_prod */
+ int *NT_ptr = nt->ptr;
+ int *NT_len = nt->len;
+ int *NT_ind = nt->ind;
+ double *NT_val = nt->val;
+ int *x_ind = x->ind;
+ double *x_vec = x->vec;
+ int *y_ind = y->ind;
+ double *y_vec = y->vec;
+ int i, j, k, nnz, ptr, end;
+ double t;
+ xassert(x->n == lp->m);
+ xassert(y->n == lp->n-lp->m);
+ if (ign)
+ { /* y := 0 */
+ fvs_clear_vec(y);
+ }
+ nnz = y->nnz;
+ for (k = x->nnz; k >= 1; k--)
+ { i = x_ind[k];
+ /* y := y + s * (i-th row of N) * x[i] */
+ t = s * x_vec[i];
+ ptr = NT_ptr[i];
+ end = ptr + NT_len[i];
+ for (; ptr < end; ptr++)
+ { j = NT_ind[ptr];
+ if (y_vec[j] == 0.0)
+ y_ind[++nnz] = j;
+ y_vec[j] += NT_val[ptr] * t;
+ /* don't forget about numeric cancellation */
+ if (y_vec[j] == 0.0)
+ y_vec[j] = DBL_MIN;
+ }
+ }
+ y->nnz = nnz;
+ fvs_adjust_vec(y, eps);
+ return;
+}
+#endif
+
+/***********************************************************************
+* spx_free_nt - deallocate matrix N in sparse row-wise format
+*
+* This routine deallocates the memory used for arrays of the program
+* object nt. */
+
+void spx_free_nt(SPXLP *lp, SPXNT *nt)
+{ xassert(lp == lp);
+ tfree(nt->ptr);
+ tfree(nt->len);
+ tfree(nt->ind);
+ tfree(nt->val);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxnt.h b/test/monniaux/glpk-4.65/src/simplex/spxnt.h
new file mode 100644
index 00000000..857917b8
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxnt.h
@@ -0,0 +1,96 @@
+/* spxnt.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#ifndef SPXNT_H
+#define SPXNT_H
+
+#include "spxlp.h"
+
+typedef struct SPXNT SPXNT;
+
+struct SPXNT
+{ /* mx(n-m)-matrix N composed of non-basic columns of constraint
+ * matrix A, in sparse row-wise format */
+ int *ptr; /* int ptr[1+m]; */
+ /* ptr[0] is not used;
+ * ptr[i], 1 <= i <= m, is starting position of i-th row in
+ * arrays ind and val; note that ptr[1] is always 1;
+ * these starting positions are set up *once* as if they would
+ * correspond to rows of matrix A stored without gaps, i.e.
+ * ptr[i+1] - ptr[i] is the number of non-zeros in i-th (i < m)
+ * row of matrix A, and (nnz+1) - ptr[m] is the number of
+ * non-zero in m-th (last) row of matrix A, where nnz is the
+ * total number of non-zeros in matrix A */
+ int *len; /* int len[1+m]; */
+ /* len[0] is not used;
+ * len[i], 1 <= i <= m, is the number of non-zeros in i-th row
+ * of current matrix N */
+ int *ind; /* int ind[1+nnz]; */
+ /* column indices */
+ double *val; /* double val[1+nnz]; */
+ /* non-zero element values */
+};
+
+#define spx_alloc_nt _glp_spx_alloc_nt
+void spx_alloc_nt(SPXLP *lp, SPXNT *nt);
+/* allocate matrix N in sparse row-wise format */
+
+#define spx_init_nt _glp_spx_init_nt
+void spx_init_nt(SPXLP *lp, SPXNT *nt);
+/* initialize row pointers for matrix N */
+
+#define spx_nt_add_col _glp_spx_nt_add_col
+void spx_nt_add_col(SPXLP *lp, SPXNT *nt, int j, int k);
+/* add column N[j] = A[k] */
+
+#define spx_build_nt _glp_spx_build_nt
+void spx_build_nt(SPXLP *lp, SPXNT *nt);
+/* build matrix N for current basis */
+
+#define spx_nt_del_col _glp_spx_nt_del_col
+void spx_nt_del_col(SPXLP *lp, SPXNT *nt, int j, int k);
+/* remove column N[j] = A[k] from matrix N */
+
+#define spx_update_nt _glp_spx_update_nt
+void spx_update_nt(SPXLP *lp, SPXNT *nt, int p, int q);
+/* update matrix N for adjacent basis */
+
+#define spx_nt_prod _glp_spx_nt_prod
+void spx_nt_prod(SPXLP *lp, SPXNT *nt, double y[/*1+n-m*/], int ign,
+ double s, const double x[/*1+m*/]);
+/* compute product y := y + s * N'* x */
+
+#if 1 /* 31/III-2016 */
+#define spx_nt_prod_s _glp_spx_nt_prod_s
+void spx_nt_prod_s(SPXLP *lp, SPXNT *nt, FVS *y, int ign, double s,
+ const FVS *x, double eps);
+/* sparse version of spx_nt_prod */
+#endif
+
+#define spx_free_nt _glp_spx_free_nt
+void spx_free_nt(SPXLP *lp, SPXNT *nt);
+/* deallocate matrix N in sparse row-wise format */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxprim.c b/test/monniaux/glpk-4.65/src/simplex/spxprim.c
new file mode 100644
index 00000000..e1cdfb5a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxprim.c
@@ -0,0 +1,1860 @@
+/* spxprim.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015-2017 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/>.
+***********************************************************************/
+
+#if 1 /* 18/VII-2017 */
+#define SCALE_Z 1
+#endif
+
+#include "env.h"
+#include "simplex.h"
+#include "spxat.h"
+#include "spxnt.h"
+#include "spxchuzc.h"
+#include "spxchuzr.h"
+#include "spxprob.h"
+
+#define CHECK_ACCURACY 0
+/* (for debugging) */
+
+struct csa
+{ /* common storage area */
+ SPXLP *lp;
+ /* LP problem data and its (current) basis; this LP has m rows
+ * and n columns */
+ int dir;
+ /* original optimization direction:
+ * +1 - minimization
+ * -1 - maximization */
+#if SCALE_Z
+ double fz;
+ /* factor used to scale original objective */
+#endif
+ double *orig_c; /* double orig_c[1+n]; */
+ /* copy of original objective coefficients */
+ double *orig_l; /* double orig_l[1+n]; */
+ /* copy of original lower bounds */
+ double *orig_u; /* double orig_u[1+n]; */
+ /* copy of original upper bounds */
+ SPXAT *at;
+ /* mxn-matrix A of constraint coefficients, in sparse row-wise
+ * format (NULL if not used) */
+ SPXNT *nt;
+ /* mx(n-m)-matrix N composed of non-basic columns of constraint
+ * matrix A, in sparse row-wise format (NULL if not used) */
+ int phase;
+ /* search phase:
+ * 0 - not determined yet
+ * 1 - searching for primal feasible solution
+ * 2 - searching for optimal solution */
+ double *beta; /* double beta[1+m]; */
+ /* beta[i] is a primal value of basic variable xB[i] */
+ int beta_st;
+ /* status of the vector beta:
+ * 0 - undefined
+ * 1 - just computed
+ * 2 - updated */
+ double *d; /* double d[1+n-m]; */
+ /* d[j] is a reduced cost of non-basic variable xN[j] */
+ int d_st;
+ /* status of the vector d:
+ * 0 - undefined
+ * 1 - just computed
+ * 2 - updated */
+ SPXSE *se;
+ /* projected steepest edge and Devex pricing data block (NULL if
+ * not used) */
+ int num;
+ /* number of eligible non-basic variables */
+ int *list; /* int list[1+n-m]; */
+ /* list[1], ..., list[num] are indices j of eligible non-basic
+ * variables xN[j] */
+ int q;
+ /* xN[q] is a non-basic variable chosen to enter the basis */
+#if 0 /* 11/VI-2017 */
+ double *tcol; /* double tcol[1+m]; */
+#else
+ FVS tcol; /* FVS tcol[1:m]; */
+#endif
+ /* q-th (pivot) column of the simplex table */
+#if 1 /* 23/VI-2017 */
+ SPXBP *bp; /* SPXBP bp[1+2*m+1]; */
+ /* penalty function break points */
+#endif
+ int p;
+ /* xB[p] is a basic variable chosen to leave the basis;
+ * p = 0 means that no basic variable reaches its bound;
+ * p < 0 means that non-basic variable xN[q] reaches its opposite
+ * bound before any basic variable */
+ int p_flag;
+ /* if this flag is set, the active bound of xB[p] in the adjacent
+ * basis should be set to the upper bound */
+#if 0 /* 11/VI-2017 */
+ double *trow; /* double trow[1+n-m]; */
+#else
+ FVS trow; /* FVS trow[1:n-m]; */
+#endif
+ /* p-th (pivot) row of the simplex table */
+#if 0 /* 09/VII-2017 */
+ double *work; /* double work[1+m]; */
+ /* working array */
+#else
+ FVS work; /* FVS work[1:m]; */
+ /* working vector */
+#endif
+ int p_stat, d_stat;
+ /* primal and dual solution statuses */
+ /*--------------------------------------------------------------*/
+ /* control parameters (see struct glp_smcp) */
+ int msg_lev;
+ /* message level */
+#if 0 /* 23/VI-2017 */
+ int harris;
+ /* ratio test technique:
+ * 0 - textbook ratio test
+ * 1 - Harris' two pass ratio test */
+#else
+ int r_test;
+ /* ratio test technique:
+ * GLP_RT_STD - textbook ratio test
+ * GLP_RT_HAR - Harris' two pass ratio test
+ * GLP_RT_FLIP - long-step ratio test (only for phase I) */
+#endif
+ double tol_bnd, tol_bnd1;
+ /* primal feasibility tolerances */
+ double tol_dj, tol_dj1;
+ /* dual feasibility tolerances */
+ double tol_piv;
+ /* pivot tolerance */
+ int it_lim;
+ /* iteration limit */
+ int tm_lim;
+ /* time limit, milliseconds */
+ int out_frq;
+#if 0 /* 15/VII-2017 */
+ /* display output frequency, iterations */
+#else
+ /* display output frequency, milliseconds */
+#endif
+ int out_dly;
+ /* display output delay, milliseconds */
+ /*--------------------------------------------------------------*/
+ /* working parameters */
+ double tm_beg;
+ /* time value at the beginning of the search */
+ int it_beg;
+ /* simplex iteration count at the beginning of the search */
+ int it_cnt;
+ /* simplex iteration count; it increases by one every time the
+ * basis changes (including the case when a non-basic variable
+ * jumps to its opposite bound) */
+ int it_dpy;
+ /* simplex iteration count at most recent display output */
+#if 1 /* 15/VII-2017 */
+ double tm_dpy;
+ /* time value at most recent display output */
+#endif
+ int inv_cnt;
+ /* basis factorization count since most recent display output */
+#if 1 /* 01/VII-2017 */
+ int degen;
+ /* count of successive degenerate iterations; this count is used
+ * to detect stalling */
+#endif
+#if 1 /* 23/VI-2017 */
+ int ns_cnt, ls_cnt;
+ /* normal and long-step iteration counts */
+#endif
+};
+
+/***********************************************************************
+* set_penalty - set penalty function coefficients
+*
+* This routine sets up objective coefficients of the penalty function,
+* which is the sum of primal infeasibilities, as follows:
+*
+* if beta[i] < l[k] - eps1, set c[k] = -1,
+*
+* if beta[i] > u[k] + eps2, set c[k] = +1,
+*
+* otherwise, set c[k] = 0,
+*
+* where beta[i] is current value of basic variable xB[i] = x[k], l[k]
+* and u[k] are original bounds of x[k], and
+*
+* eps1 = tol + tol1 * |l[k]|,
+*
+* eps2 = tol + tol1 * |u[k]|.
+*
+* The routine returns the number of non-zero objective coefficients,
+* which is the number of basic variables violating their bounds. Thus,
+* if the value returned is zero, the current basis is primal feasible
+* within the specified tolerances. */
+
+static int set_penalty(struct csa *csa, double tol, double tol1)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ double *beta = csa->beta;
+ int i, k, count = 0;
+ double t, eps;
+ /* reset objective coefficients */
+ for (k = 0; k <= n; k++)
+ c[k] = 0.0;
+ /* walk thru the list of basic variables */
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ /* check lower bound */
+ if ((t = l[k]) != -DBL_MAX)
+ { eps = tol + tol1 * (t >= 0.0 ? +t : -t);
+ if (beta[i] < t - eps)
+ { /* lower bound is violated */
+ c[k] = -1.0, count++;
+ }
+ }
+ /* check upper bound */
+ if ((t = u[k]) != +DBL_MAX)
+ { eps = tol + tol1 * (t >= 0.0 ? +t : -t);
+ if (beta[i] > t + eps)
+ { /* upper bound is violated */
+ c[k] = +1.0, count++;
+ }
+ }
+ }
+ return count;
+}
+
+/***********************************************************************
+* check_feas - check primal feasibility of basic solution
+*
+* This routine checks if the specified values of all basic variables
+* beta = (beta[i]) are within their bounds.
+*
+* Let l[k] and u[k] be original bounds of basic variable xB[i] = x[k].
+* The actual bounds of x[k] are determined as follows:
+*
+* 1) if phase = 1 and c[k] < 0, x[k] violates its lower bound, so its
+* actual bounds are artificial: -inf < x[k] <= l[k];
+*
+* 2) if phase = 1 and c[k] > 0, x[k] violates its upper bound, so its
+* actual bounds are artificial: u[k] <= x[k] < +inf;
+*
+* 3) in all other cases (if phase = 1 and c[k] = 0, or if phase = 2)
+* actual bounds are original: l[k] <= x[k] <= u[k].
+*
+* The parameters tol and tol1 are bound violation tolerances. The
+* actual bounds l'[k] and u'[k] are considered as non-violated within
+* the specified tolerance if
+*
+* l'[k] - eps1 <= beta[i] <= u'[k] + eps2,
+*
+* where eps1 = tol + tol1 * |l'[k]|, eps2 = tol + tol1 * |u'[k]|.
+*
+* The routine returns one of the following codes:
+*
+* 0 - solution is feasible (no actual bounds are violated);
+*
+* 1 - solution is infeasible, however, only artificial bounds are
+* violated (this is possible only if phase = 1);
+*
+* 2 - solution is infeasible and at least one original bound is
+* violated. */
+
+static int check_feas(struct csa *csa, int phase, double tol, double
+ tol1)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ double *beta = csa->beta;
+ int i, k, orig, ret = 0;
+ double lk, uk, eps;
+ xassert(phase == 1 || phase == 2);
+ /* walk thru the list of basic variables */
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ /* determine actual bounds of x[k] */
+ if (phase == 1 && c[k] < 0.0)
+ { /* -inf < x[k] <= l[k] */
+ lk = -DBL_MAX, uk = l[k];
+ orig = 0; /* artificial bounds */
+ }
+ else if (phase == 1 && c[k] > 0.0)
+ { /* u[k] <= x[k] < +inf */
+ lk = u[k], uk = +DBL_MAX;
+ orig = 0; /* artificial bounds */
+ }
+ else
+ { /* l[k] <= x[k] <= u[k] */
+ lk = l[k], uk = u[k];
+ orig = 1; /* original bounds */
+ }
+ /* check actual lower bound */
+ if (lk != -DBL_MAX)
+ { eps = tol + tol1 * (lk >= 0.0 ? +lk : -lk);
+ if (beta[i] < lk - eps)
+ { /* actual lower bound is violated */
+ if (orig)
+ { ret = 2;
+ break;
+ }
+ ret = 1;
+ }
+ }
+ /* check actual upper bound */
+ if (uk != +DBL_MAX)
+ { eps = tol + tol1 * (uk >= 0.0 ? +uk : -uk);
+ if (beta[i] > uk + eps)
+ { /* actual upper bound is violated */
+ if (orig)
+ { ret = 2;
+ break;
+ }
+ ret = 1;
+ }
+ }
+ }
+ return ret;
+}
+
+/***********************************************************************
+* adjust_penalty - adjust penalty function coefficients
+*
+* On searching for primal feasible solution it may happen that some
+* basic variable xB[i] = x[k] has non-zero objective coefficient c[k]
+* indicating that xB[i] violates its lower (if c[k] < 0) or upper (if
+* c[k] > 0) original bound, but due to primal degenarcy the violation
+* is close to zero.
+*
+* This routine identifies such basic variables and sets objective
+* coefficients at these variables to zero that allows avoiding zero-
+* step simplex iterations.
+*
+* The parameters tol and tol1 are bound violation tolerances. The
+* original bounds l[k] and u[k] are considered as non-violated within
+* the specified tolerance if
+*
+* l[k] - eps1 <= beta[i] <= u[k] + eps2,
+*
+* where beta[i] is value of basic variable xB[i] = x[k] in the current
+* basis, eps1 = tol + tol1 * |l[k]|, eps2 = tol + tol1 * |u[k]|.
+*
+* The routine returns the number of objective coefficients which were
+* set to zero. */
+
+#if 0
+static int adjust_penalty(struct csa *csa, double tol, double tol1)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ double *beta = csa->beta;
+ int i, k, count = 0;
+ double t, eps;
+ xassert(csa->phase == 1);
+ /* walk thru the list of basic variables */
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ if (c[k] < 0.0)
+ { /* x[k] violates its original lower bound l[k] */
+ xassert((t = l[k]) != -DBL_MAX);
+ eps = tol + tol1 * (t >= 0.0 ? +t : -t);
+ if (beta[i] >= t - eps)
+ { /* however, violation is close to zero */
+ c[k] = 0.0, count++;
+ }
+ }
+ else if (c[k] > 0.0)
+ { /* x[k] violates its original upper bound u[k] */
+ xassert((t = u[k]) != +DBL_MAX);
+ eps = tol + tol1 * (t >= 0.0 ? +t : -t);
+ if (beta[i] <= t + eps)
+ { /* however, violation is close to zero */
+ c[k] = 0.0, count++;
+ }
+ }
+ }
+ return count;
+}
+#else
+static int adjust_penalty(struct csa *csa, int num, const int
+ ind[/*1+num*/], double tol, double tol1)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ double *beta = csa->beta;
+ int i, k, t, cnt = 0;
+ double lk, uk, eps;
+ xassert(csa->phase == 1);
+ /* walk thru the specified list of basic variables */
+ for (t = 1; t <= num; t++)
+ { i = ind[t];
+ xassert(1 <= i && i <= m);
+ k = head[i]; /* x[k] = xB[i] */
+ if (c[k] < 0.0)
+ { /* x[k] violates its original lower bound */
+ lk = l[k];
+ xassert(lk != -DBL_MAX);
+ eps = tol + tol1 * (lk >= 0.0 ? +lk : -lk);
+ if (beta[i] >= lk - eps)
+ { /* however, violation is close to zero */
+ c[k] = 0.0, cnt++;
+ }
+ }
+ else if (c[k] > 0.0)
+ { /* x[k] violates its original upper bound */
+ uk = u[k];
+ xassert(uk != +DBL_MAX);
+ eps = tol + tol1 * (uk >= 0.0 ? +uk : -uk);
+ if (beta[i] <= uk + eps)
+ { /* however, violation is close to zero */
+ c[k] = 0.0, cnt++;
+ }
+ }
+ }
+ return cnt;
+}
+#endif
+
+#if CHECK_ACCURACY
+/***********************************************************************
+* err_in_vec - compute maximal relative error between two vectors
+*
+* This routine computes and returns maximal relative error between
+* n-vectors x and y:
+*
+* err_max = max |x[i] - y[i]| / (1 + |x[i]|).
+*
+* NOTE: This routine is intended only for debugginig purposes. */
+
+static double err_in_vec(int n, const double x[], const double y[])
+{ int i;
+ double err, err_max;
+ err_max = 0.0;
+ for (i = 1; i <= n; i++)
+ { err = fabs(x[i] - y[i]) / (1.0 + fabs(x[i]));
+ if (err_max < err)
+ err_max = err;
+ }
+ return err_max;
+}
+#endif
+
+#if CHECK_ACCURACY
+/***********************************************************************
+* err_in_beta - compute maximal relative error in vector beta
+*
+* This routine computes and returns maximal relative error in vector
+* of values of basic variables beta = (beta[i]).
+*
+* NOTE: This routine is intended only for debugginig purposes. */
+
+static double err_in_beta(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ double err, *beta;
+ beta = talloc(1+m, double);
+ spx_eval_beta(lp, beta);
+ err = err_in_vec(m, beta, csa->beta);
+ tfree(beta);
+ return err;
+}
+#endif
+
+#if CHECK_ACCURACY
+/***********************************************************************
+* err_in_d - compute maximal relative error in vector d
+*
+* This routine computes and returns maximal relative error in vector
+* of reduced costs of non-basic variables d = (d[j]).
+*
+* NOTE: This routine is intended only for debugginig purposes. */
+
+static double err_in_d(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ int j;
+ double err, *pi, *d;
+ pi = talloc(1+m, double);
+ d = talloc(1+n-m, double);
+ spx_eval_pi(lp, pi);
+ for (j = 1; j <= n-m; j++)
+ d[j] = spx_eval_dj(lp, pi, j);
+ err = err_in_vec(n-m, d, csa->d);
+ tfree(pi);
+ tfree(d);
+ return err;
+}
+#endif
+
+#if CHECK_ACCURACY
+/***********************************************************************
+* err_in_gamma - compute maximal relative error in vector gamma
+*
+* This routine computes and returns maximal relative error in vector
+* of projected steepest edge weights gamma = (gamma[j]).
+*
+* NOTE: This routine is intended only for debugginig purposes. */
+
+static double err_in_gamma(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ SPXSE *se = csa->se;
+ int j;
+ double err, *gamma;
+ xassert(se != NULL);
+ gamma = talloc(1+n-m, double);
+ for (j = 1; j <= n-m; j++)
+ gamma[j] = spx_eval_gamma_j(lp, se, j);
+ err = err_in_vec(n-m, gamma, se->gamma);
+ tfree(gamma);
+ return err;
+}
+#endif
+
+#if CHECK_ACCURACY
+/***********************************************************************
+* check_accuracy - check accuracy of basic solution components
+*
+* This routine checks accuracy of current basic solution components.
+*
+* NOTE: This routine is intended only for debugginig purposes. */
+
+static void check_accuracy(struct csa *csa)
+{ double e_beta, e_d, e_gamma;
+ e_beta = err_in_beta(csa);
+ e_d = err_in_d(csa);
+ if (csa->se == NULL)
+ e_gamma = 0.;
+ else
+ e_gamma = err_in_gamma(csa);
+ xprintf("e_beta = %10.3e; e_d = %10.3e; e_gamma = %10.3e\n",
+ e_beta, e_d, e_gamma);
+ xassert(e_beta <= 1e-5 && e_d <= 1e-5 && e_gamma <= 1e-3);
+ return;
+}
+#endif
+
+/***********************************************************************
+* choose_pivot - choose xN[q] and xB[p]
+*
+* Given the list of eligible non-basic variables this routine first
+* chooses non-basic variable xN[q]. This choice is always possible,
+* because the list is assumed to be non-empty. Then the routine
+* computes q-th column T[*,q] of the simplex table T[i,j] and chooses
+* basic variable xB[p]. If the pivot T[p,q] is small in magnitude,
+* the routine attempts to choose another xN[q] and xB[p] in order to
+* avoid badly conditioned adjacent bases. */
+
+#if 1 /* 17/III-2016 */
+#define MIN_RATIO 0.0001
+
+static int choose_pivot(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *beta = csa->beta;
+ double *d = csa->d;
+ SPXSE *se = csa->se;
+ int *list = csa->list;
+#if 0 /* 09/VII-2017 */
+ double *tcol = csa->work;
+#else
+ double *tcol = csa->work.vec;
+#endif
+ double tol_piv = csa->tol_piv;
+ int try, nnn, /*i,*/ p, p_flag, q, t;
+ double big, /*temp,*/ best_ratio;
+#if 1 /* 23/VI-2017 */
+ double *c = lp->c;
+ int *head = lp->head;
+ SPXBP *bp = csa->bp;
+ int nbp, t_best, ret, k;
+ double dz_best;
+#endif
+ xassert(csa->beta_st);
+ xassert(csa->d_st);
+more: /* initial number of eligible non-basic variables */
+ nnn = csa->num;
+ /* nothing has been chosen so far */
+ csa->q = 0;
+ best_ratio = 0.0;
+#if 0 /* 23/VI-2017 */
+ try = 0;
+#else
+ try = ret = 0;
+#endif
+try: /* choose non-basic variable xN[q] */
+ xassert(nnn > 0);
+ try++;
+ if (se == NULL)
+ { /* Dantzig's rule */
+ q = spx_chuzc_std(lp, d, nnn, list);
+ }
+ else
+ { /* projected steepest edge */
+ q = spx_chuzc_pse(lp, se, d, nnn, list);
+ }
+ xassert(1 <= q && q <= n-m);
+ /* compute q-th column of the simplex table */
+ spx_eval_tcol(lp, q, tcol);
+#if 0
+ /* big := max(1, |tcol[1]|, ..., |tcol[m]|) */
+ big = 1.0;
+ for (i = 1; i <= m; i++)
+ { temp = tcol[i];
+ if (temp < 0.0)
+ temp = - temp;
+ if (big < temp)
+ big = temp;
+ }
+#else
+ /* this still puzzles me */
+ big = 1.0;
+#endif
+ /* choose basic variable xB[p] */
+#if 1 /* 23/VI-2017 */
+ if (csa->phase == 1 && csa->r_test == GLP_RT_FLIP && try <= 2)
+ { /* long-step ratio test */
+ int t, num, num1;
+ double slope, teta_lim;
+ /* determine penalty function break points */
+ nbp = spx_ls_eval_bp(lp, beta, q, d[q], tcol, tol_piv, bp);
+ if (nbp < 2)
+ goto skip;
+ /* set initial slope */
+ slope = - fabs(d[q]);
+ /* estimate initial teta_lim */
+ teta_lim = DBL_MAX;
+ for (t = 1; t <= nbp; t++)
+ { if (teta_lim > bp[t].teta)
+ teta_lim = bp[t].teta;
+ }
+ xassert(teta_lim >= 0.0);
+ if (teta_lim < 1e-3)
+ teta_lim = 1e-3;
+ /* nothing has been chosen so far */
+ t_best = 0, dz_best = 0.0, num = 0;
+ /* choose appropriate break point */
+ while (num < nbp)
+ { /* select and process a new portion of break points */
+ num1 = spx_ls_select_bp(lp, tcol, nbp, bp, num, &slope,
+ teta_lim);
+ for (t = num+1; t <= num1; t++)
+ { int i = (bp[t].i >= 0 ? bp[t].i : -bp[t].i);
+ xassert(0 <= i && i <= m);
+ if (i == 0 || fabs(tcol[i]) / big >= MIN_RATIO)
+ { if (dz_best > bp[t].dz)
+ t_best = t, dz_best = bp[t].dz;
+ }
+#if 0
+ if (i == 0)
+ { /* do not consider further break points beyond this
+ * point, where xN[q] reaches its opposite bound;
+ * in principle (see spx_ls_eval_bp), this break
+ * point should be the last one, however, due to
+ * round-off errors there may be other break points
+ * with the same teta beyond this one */
+ slope = +1.0;
+ }
+#endif
+ }
+ if (slope > 0.0)
+ { /* penalty function starts increasing */
+ break;
+ }
+ /* penalty function continues decreasing */
+ num = num1;
+ teta_lim += teta_lim;
+ }
+ if (dz_best == 0.0)
+ goto skip;
+ /* the choice has been made */
+ xassert(1 <= t_best && t_best <= num1);
+ if (t_best == 1)
+ { /* the very first break point was chosen; it is reasonable
+ * to use the short-step ratio test */
+ goto skip;
+ }
+ csa->q = q;
+ memcpy(&csa->tcol.vec[1], &tcol[1], m * sizeof(double));
+ fvs_gather_vec(&csa->tcol, DBL_EPSILON);
+ if (bp[t_best].i == 0)
+ { /* xN[q] goes to its opposite bound */
+ csa->p = -1;
+ csa->p_flag = 0;
+ best_ratio = 1.0;
+ }
+ else if (bp[t_best].i > 0)
+ { /* xB[p] leaves the basis and goes to its lower bound */
+ csa->p = + bp[t_best].i;
+ xassert(1 <= csa->p && csa->p <= m);
+ csa->p_flag = 0;
+ best_ratio = fabs(tcol[csa->p]) / big;
+ }
+ else
+ { /* xB[p] leaves the basis and goes to its upper bound */
+ csa->p = - bp[t_best].i;
+ xassert(1 <= csa->p && csa->p <= m);
+ csa->p_flag = 1;
+ best_ratio = fabs(tcol[csa->p]) / big;
+ }
+#if 0
+ xprintf("num1 = %d; t_best = %d; dz = %g\n", num1, t_best,
+ bp[t_best].dz);
+#endif
+ ret = 1;
+ goto done;
+skip: ;
+ }
+#endif
+#if 0 /* 23/VI-2017 */
+ if (!csa->harris)
+#else
+ if (csa->r_test == GLP_RT_STD)
+#endif
+ { /* textbook ratio test */
+ p = spx_chuzr_std(lp, csa->phase, beta, q,
+ d[q] < 0.0 ? +1. : -1., tcol, &p_flag, tol_piv,
+ .30 * csa->tol_bnd, .30 * csa->tol_bnd1);
+ }
+ else
+ { /* Harris' two-pass ratio test */
+ p = spx_chuzr_harris(lp, csa->phase, beta, q,
+ d[q] < 0.0 ? +1. : -1., tcol, &p_flag , tol_piv,
+ .50 * csa->tol_bnd, .50 * csa->tol_bnd1);
+ }
+ if (p <= 0)
+ { /* primal unboundedness or special case */
+ csa->q = q;
+#if 0 /* 11/VI-2017 */
+ memcpy(&csa->tcol[1], &tcol[1], m * sizeof(double));
+#else
+ memcpy(&csa->tcol.vec[1], &tcol[1], m * sizeof(double));
+ fvs_gather_vec(&csa->tcol, DBL_EPSILON);
+#endif
+ csa->p = p;
+ csa->p_flag = p_flag;
+ best_ratio = 1.0;
+ goto done;
+ }
+ /* either keep previous choice or accept new choice depending on
+ * which one is better */
+ if (best_ratio < fabs(tcol[p]) / big)
+ { csa->q = q;
+#if 0 /* 11/VI-2017 */
+ memcpy(&csa->tcol[1], &tcol[1], m * sizeof(double));
+#else
+ memcpy(&csa->tcol.vec[1], &tcol[1], m * sizeof(double));
+ fvs_gather_vec(&csa->tcol, DBL_EPSILON);
+#endif
+ csa->p = p;
+ csa->p_flag = p_flag;
+ best_ratio = fabs(tcol[p]) / big;
+ }
+ /* check if the current choice is acceptable */
+ if (best_ratio >= MIN_RATIO || nnn == 1 || try == 5)
+ goto done;
+ /* try to choose other xN[q] and xB[p] */
+ /* find xN[q] in the list */
+ for (t = 1; t <= nnn; t++)
+ if (list[t] == q) break;
+ xassert(t <= nnn);
+ /* move xN[q] to the end of the list */
+ list[t] = list[nnn], list[nnn] = q;
+ /* and exclude it from consideration */
+ nnn--;
+ /* repeat the choice */
+ goto try;
+done: /* the choice has been made */
+#if 1 /* FIXME: currently just to avoid badly conditioned basis */
+ if (best_ratio < .001 * MIN_RATIO)
+ { /* looks like this helps */
+ if (bfd_get_count(lp->bfd) > 0)
+ return -1;
+ /* didn't help; last chance to improve the choice */
+ if (tol_piv == csa->tol_piv)
+ { tol_piv *= 1000.;
+ goto more;
+ }
+ }
+#endif
+#if 0 /* 23/VI-2017 */
+ return 0;
+#else /* FIXME */
+ if (ret)
+ { /* invalidate dual basic solution components */
+ csa->d_st = 0;
+ /* change penalty function coefficients at basic variables for
+ * all break points preceding the chosen one */
+ for (t = 1; t < t_best; t++)
+ { int i = (bp[t].i >= 0 ? bp[t].i : -bp[t].i);
+ xassert(0 <= i && i <= m);
+ if (i == 0)
+ { /* xN[q] crosses its opposite bound */
+ xassert(1 <= csa->q && csa->q <= n-m);
+ k = head[m+csa->q];
+ }
+ else
+ { /* xB[i] crosses its (lower or upper) bound */
+ k = head[i]; /* x[k] = xB[i] */
+ }
+ c[k] += bp[t].dc;
+ xassert(c[k] == 0.0 || c[k] == +1.0 || c[k] == -1.0);
+ }
+ }
+ return ret;
+#endif
+}
+#endif
+
+/***********************************************************************
+* play_bounds - play bounds of primal variables
+*
+* This routine is called after the primal values of basic variables
+* beta[i] were updated and the basis was changed to the adjacent one.
+*
+* It is assumed that before updating all the primal values beta[i]
+* were strongly feasible, so in the adjacent basis beta[i] remain
+* feasible within a tolerance, i.e. if some beta[i] violates its lower
+* or upper bound, the violation is insignificant.
+*
+* If some beta[i] violates its lower or upper bound, this routine
+* changes (perturbs) the bound to remove such violation, i.e. to make
+* all beta[i] strongly feasible. Otherwise, if beta[i] has a feasible
+* value, this routine attempts to reduce (or remove) perturbation of
+* corresponding lower/upper bound keeping strong feasibility. */
+
+/* FIXME: what to do if l[k] = u[k]? */
+
+/* FIXME: reduce/remove perturbation if x[k] becomes non-basic? */
+
+static void play_bounds(struct csa *csa, int all)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ double *orig_l = csa->orig_l;
+ double *orig_u = csa->orig_u;
+ double *beta = csa->beta;
+#if 0 /* 11/VI-2017 */
+ const double *tcol = csa->tcol; /* was used to update beta */
+#else
+ const double *tcol = csa->tcol.vec;
+#endif
+ int i, k;
+ xassert(csa->phase == 1 || csa->phase == 2);
+ /* primal values beta = (beta[i]) should be valid */
+ xassert(csa->beta_st);
+ /* walk thru the list of basic variables xB = (xB[i]) */
+ for (i = 1; i <= m; i++)
+ { if (all || tcol[i] != 0.0)
+ { /* beta[i] has changed in the adjacent basis */
+ k = head[i]; /* x[k] = xB[i] */
+ if (csa->phase == 1 && c[k] < 0.0)
+ { /* -inf < xB[i] <= lB[i] (artificial bounds) */
+ if (beta[i] < l[k] - 1e-9)
+ continue;
+ /* restore actual bounds */
+ c[k] = 0.0;
+ csa->d_st = 0; /* since c[k] = cB[i] has changed */
+ }
+ if (csa->phase == 1 && c[k] > 0.0)
+ { /* uB[i] <= xB[i] < +inf (artificial bounds) */
+ if (beta[i] > u[k] + 1e-9)
+ continue;
+ /* restore actual bounds */
+ c[k] = 0.0;
+ csa->d_st = 0; /* since c[k] = cB[i] has changed */
+ }
+ /* lB[i] <= xB[i] <= uB[i] */
+ if (csa->phase == 1)
+ xassert(c[k] == 0.0);
+ if (l[k] != -DBL_MAX)
+ { /* xB[i] has lower bound */
+ if (beta[i] < l[k])
+ { /* strong feasibility means xB[i] >= lB[i] */
+#if 0 /* 11/VI-2017 */
+ l[k] = beta[i];
+#else
+ l[k] = beta[i] - 1e-9;
+#endif
+ }
+ else if (l[k] < orig_l[k])
+ { /* remove/reduce perturbation of lB[i] */
+ if (beta[i] >= orig_l[k])
+ l[k] = orig_l[k];
+ else
+ l[k] = beta[i];
+ }
+ }
+ if (u[k] != +DBL_MAX)
+ { /* xB[i] has upper bound */
+ if (beta[i] > u[k])
+ { /* strong feasibility means xB[i] <= uB[i] */
+#if 0 /* 11/VI-2017 */
+ u[k] = beta[i];
+#else
+ u[k] = beta[i] + 1e-9;
+#endif
+ }
+ else if (u[k] > orig_u[k])
+ { /* remove/reduce perturbation of uB[i] */
+ if (beta[i] <= orig_u[k])
+ u[k] = orig_u[k];
+ else
+ u[k] = beta[i];
+ }
+ }
+ }
+ }
+ return;
+}
+
+static void remove_perturb(struct csa *csa)
+{ /* remove perturbation */
+ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ double *orig_l = csa->orig_l;
+ double *orig_u = csa->orig_u;
+ int j, k;
+ /* restore original bounds of variables */
+ memcpy(l, orig_l, (1+n) * sizeof(double));
+ memcpy(u, orig_u, (1+n) * sizeof(double));
+ /* adjust flags of fixed non-basic variables, because in the
+ * perturbed problem such variables might be changed to double-
+ * bounded type */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ if (l[k] == u[k])
+ flag[j] = 0;
+ }
+ /* removing perturbation changes primal solution components */
+ csa->phase = csa->beta_st = 0;
+#if 1
+ if (csa->msg_lev >= GLP_MSG_ALL)
+ xprintf("Removing LP perturbation [%d]...\n",
+ csa->it_cnt);
+#endif
+ return;
+}
+
+/***********************************************************************
+* sum_infeas - compute sum of primal infeasibilities
+*
+* This routine compute the sum of primal infeasibilities, which is the
+* current penalty function value. */
+
+static double sum_infeas(SPXLP *lp, const double beta[/*1+m*/])
+{ int m = lp->m;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ int i, k;
+ double sum = 0.0;
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ if (l[k] != -DBL_MAX && beta[i] < l[k])
+ sum += l[k] - beta[i];
+ if (u[k] != +DBL_MAX && beta[i] > u[k])
+ sum += beta[i] - u[k];
+ }
+ return sum;
+}
+
+/***********************************************************************
+* display - display search progress
+*
+* This routine displays some information about the search progress
+* that includes:
+*
+* search phase;
+*
+* number of simplex iterations performed by the solver;
+*
+* original objective value;
+*
+* sum of (scaled) primal infeasibilities;
+*
+* number of infeasibilities (phase I) or non-optimalities (phase II);
+*
+* number of basic factorizations since last display output. */
+
+static void display(struct csa *csa, int spec)
+{ int nnn, k;
+ double obj, sum, *save, *save1;
+#if 1 /* 15/VII-2017 */
+ double tm_cur;
+#endif
+ /* check if the display output should be skipped */
+ if (csa->msg_lev < GLP_MSG_ON) goto skip;
+#if 1 /* 15/VII-2017 */
+ tm_cur = xtime();
+#endif
+ if (csa->out_dly > 0 &&
+#if 0 /* 15/VII-2017 */
+ 1000.0 * xdifftime(xtime(), csa->tm_beg) < csa->out_dly)
+#else
+ 1000.0 * xdifftime(tm_cur, csa->tm_beg) < csa->out_dly)
+#endif
+ goto skip;
+ if (csa->it_cnt == csa->it_dpy) goto skip;
+#if 0 /* 15/VII-2017 */
+ if (!spec && csa->it_cnt % csa->out_frq != 0) goto skip;
+#else
+ if (!spec &&
+ 1000.0 * xdifftime(tm_cur, csa->tm_dpy) < csa->out_frq)
+ goto skip;
+#endif
+ /* compute original objective value */
+ save = csa->lp->c;
+ csa->lp->c = csa->orig_c;
+ obj = csa->dir * spx_eval_obj(csa->lp, csa->beta);
+ csa->lp->c = save;
+#if SCALE_Z
+ obj *= csa->fz;
+#endif
+ /* compute sum of (scaled) primal infeasibilities */
+#if 1 /* 01/VII-2017 */
+ save = csa->lp->l;
+ save1 = csa->lp->u;
+ csa->lp->l = csa->orig_l;
+ csa->lp->u = csa->orig_u;
+#endif
+ sum = sum_infeas(csa->lp, csa->beta);
+#if 1 /* 01/VII-2017 */
+ csa->lp->l = save;
+ csa->lp->u = save1;
+#endif
+ /* compute number of infeasibilities/non-optimalities */
+ switch (csa->phase)
+ { case 1:
+ nnn = 0;
+ for (k = 1; k <= csa->lp->n; k++)
+ if (csa->lp->c[k] != 0.0) nnn++;
+ break;
+ case 2:
+ xassert(csa->d_st);
+ nnn = spx_chuzc_sel(csa->lp, csa->d, csa->tol_dj,
+ csa->tol_dj1, NULL);
+ break;
+ default:
+ xassert(csa != csa);
+ }
+ /* display search progress */
+ xprintf("%c%6d: obj = %17.9e inf = %11.3e (%d)",
+ csa->phase == 2 ? '*' : ' ', csa->it_cnt, obj, sum, nnn);
+ if (csa->inv_cnt)
+ { /* number of basis factorizations performed */
+ xprintf(" %d", csa->inv_cnt);
+ csa->inv_cnt = 0;
+ }
+#if 1 /* 23/VI-2017 */
+ if (csa->phase == 1 && csa->r_test == GLP_RT_FLIP)
+ { /*xprintf(" %d,%d", csa->ns_cnt, csa->ls_cnt);*/
+ if (csa->ns_cnt + csa->ls_cnt)
+ xprintf(" %d%%",
+ (100 * csa->ls_cnt) / (csa->ns_cnt + csa->ls_cnt));
+ csa->ns_cnt = csa->ls_cnt = 0;
+ }
+#endif
+ xprintf("\n");
+ csa->it_dpy = csa->it_cnt;
+#if 1 /* 15/VII-2017 */
+ csa->tm_dpy = tm_cur;
+#endif
+skip: return;
+}
+
+/***********************************************************************
+* spx_primal - driver to the primal simplex method
+*
+* This routine is a driver to the two-phase primal simplex method.
+*
+* On exit this routine returns one of the following codes:
+*
+* 0 LP instance has been successfully solved.
+*
+* GLP_EITLIM
+* Iteration limit has been exhausted.
+*
+* GLP_ETMLIM
+* Time limit has been exhausted.
+*
+* GLP_EFAIL
+* The solver failed to solve LP instance. */
+
+static int primal_simplex(struct csa *csa)
+{ /* primal simplex method main logic routine */
+ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ int *head = lp->head;
+ SPXAT *at = csa->at;
+ SPXNT *nt = csa->nt;
+ double *beta = csa->beta;
+ double *d = csa->d;
+ SPXSE *se = csa->se;
+ int *list = csa->list;
+#if 0 /* 11/VI-2017 */
+ double *tcol = csa->tcol;
+ double *trow = csa->trow;
+#endif
+#if 0 /* 09/VII-2017 */
+ double *pi = csa->work;
+ double *rho = csa->work;
+#else
+ double *pi = csa->work.vec;
+ double *rho = csa->work.vec;
+#endif
+ int msg_lev = csa->msg_lev;
+ double tol_bnd = csa->tol_bnd;
+ double tol_bnd1 = csa->tol_bnd1;
+ double tol_dj = csa->tol_dj;
+ double tol_dj1 = csa->tol_dj1;
+ int perturb = -1;
+ /* -1 = perturbation is not used, but enabled
+ * 0 = perturbation is not used and disabled
+ * +1 = perturbation is being used */
+ int j, refct, ret;
+loop: /* main loop starts here */
+ /* compute factorization of the basis matrix */
+ if (!lp->valid)
+ { double cond;
+ ret = spx_factorize(lp);
+ csa->inv_cnt++;
+ if (ret != 0)
+ { if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Error: unable to factorize the basis matrix (%d"
+ ")\n", ret);
+ csa->p_stat = csa->d_stat = GLP_UNDEF;
+ ret = GLP_EFAIL;
+ goto fini;
+ }
+ /* check condition of the basis matrix */
+ cond = bfd_condest(lp->bfd);
+ if (cond > 1.0 / DBL_EPSILON)
+ { if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Error: basis matrix is singular to working prec"
+ "ision (cond = %.3g)\n", cond);
+ csa->p_stat = csa->d_stat = GLP_UNDEF;
+ ret = GLP_EFAIL;
+ goto fini;
+ }
+ if (cond > 0.001 / DBL_EPSILON)
+ { if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Warning: basis matrix is ill-conditioned (cond "
+ "= %.3g)\n", cond);
+ }
+ /* invalidate basic solution components */
+ csa->beta_st = csa->d_st = 0;
+ }
+ /* compute values of basic variables beta = (beta[i]) */
+ if (!csa->beta_st)
+ { spx_eval_beta(lp, beta);
+ csa->beta_st = 1; /* just computed */
+ /* determine the search phase, if not determined yet */
+ if (!csa->phase)
+ { if (set_penalty(csa, 0.97 * tol_bnd, 0.97 * tol_bnd1))
+ { /* current basic solution is primal infeasible */
+ /* start to minimize the sum of infeasibilities */
+ csa->phase = 1;
+ }
+ else
+ { /* current basic solution is primal feasible */
+ /* start to minimize the original objective function */
+ csa->phase = 2;
+ memcpy(c, csa->orig_c, (1+n) * sizeof(double));
+ }
+ /* working objective coefficients have been changed, so
+ * invalidate reduced costs */
+ csa->d_st = 0;
+ }
+ /* make sure that the current basic solution remains primal
+ * feasible (or pseudo-feasible on phase I) */
+ if (perturb <= 0)
+ { if (check_feas(csa, csa->phase, tol_bnd, tol_bnd1))
+ { /* excessive bound violations due to round-off errors */
+#if 1 /* 01/VII-2017 */
+ if (perturb < 0)
+ { if (msg_lev >= GLP_MSG_ALL)
+ xprintf("Perturbing LP to avoid instability [%d].."
+ ".\n", csa->it_cnt);
+ perturb = 1;
+ goto loop;
+ }
+#endif
+ if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Warning: numerical instability (primal simpl"
+ "ex, phase %s)\n", csa->phase == 1 ? "I" : "II");
+ /* restart the search */
+ lp->valid = 0;
+ csa->phase = 0;
+ goto loop;
+ }
+ if (csa->phase == 1)
+ { int i, cnt;
+ for (i = 1; i <= m; i++)
+ csa->tcol.ind[i] = i;
+ cnt = adjust_penalty(csa, m, csa->tcol.ind,
+ 0.99 * tol_bnd, 0.99 * tol_bnd1);
+ if (cnt)
+ { /*xprintf("*** cnt = %d\n", cnt);*/
+ csa->d_st = 0;
+ }
+ }
+ }
+ else
+ { /* FIXME */
+ play_bounds(csa, 1);
+ }
+ }
+ /* at this point the search phase is determined */
+ xassert(csa->phase == 1 || csa->phase == 2);
+ /* compute reduced costs of non-basic variables d = (d[j]) */
+ if (!csa->d_st)
+ { spx_eval_pi(lp, pi);
+ for (j = 1; j <= n-m; j++)
+ d[j] = spx_eval_dj(lp, pi, j);
+ csa->d_st = 1; /* just computed */
+ }
+ /* reset the reference space, if necessary */
+ if (se != NULL && !se->valid)
+ spx_reset_refsp(lp, se), refct = 1000;
+ /* at this point the basis factorization and all basic solution
+ * components are valid */
+ xassert(lp->valid && csa->beta_st && csa->d_st);
+#if CHECK_ACCURACY
+ /* check accuracy of current basic solution components (only for
+ * debugging) */
+ check_accuracy(csa);
+#endif
+ /* check if the iteration limit has been exhausted */
+ if (csa->it_cnt - csa->it_beg >= csa->it_lim)
+ { if (perturb > 0)
+ { /* remove perturbation */
+ remove_perturb(csa);
+ perturb = 0;
+ }
+ if (csa->beta_st != 1)
+ csa->beta_st = 0;
+ if (csa->d_st != 1)
+ csa->d_st = 0;
+ if (!(csa->beta_st && csa->d_st))
+ goto loop;
+ display(csa, 1);
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
+ csa->p_stat = (csa->phase == 2 ? GLP_FEAS : GLP_INFEAS);
+ csa->d_stat = GLP_UNDEF; /* will be set below */
+ ret = GLP_EITLIM;
+ goto fini;
+ }
+ /* check if the time limit has been exhausted */
+ if (1000.0 * xdifftime(xtime(), csa->tm_beg) >= csa->tm_lim)
+ { if (perturb > 0)
+ { /* remove perturbation */
+ remove_perturb(csa);
+ perturb = 0;
+ }
+ if (csa->beta_st != 1)
+ csa->beta_st = 0;
+ if (csa->d_st != 1)
+ csa->d_st = 0;
+ if (!(csa->beta_st && csa->d_st))
+ goto loop;
+ display(csa, 1);
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+ csa->p_stat = (csa->phase == 2 ? GLP_FEAS : GLP_INFEAS);
+ csa->d_stat = GLP_UNDEF; /* will be set below */
+ ret = GLP_ETMLIM;
+ goto fini;
+ }
+ /* display the search progress */
+ display(csa, 0);
+ /* select eligible non-basic variables */
+ switch (csa->phase)
+ { case 1:
+ csa->num = spx_chuzc_sel(lp, d, 1e-8, 0.0, list);
+ break;
+ case 2:
+ csa->num = spx_chuzc_sel(lp, d, tol_dj, tol_dj1, list);
+ break;
+ default:
+ xassert(csa != csa);
+ }
+ /* check for optimality */
+ if (csa->num == 0)
+ { if (perturb > 0 && csa->phase == 2)
+ { /* remove perturbation */
+ remove_perturb(csa);
+ perturb = 0;
+ }
+ if (csa->beta_st != 1)
+ csa->beta_st = 0;
+ if (csa->d_st != 1)
+ csa->d_st = 0;
+ if (!(csa->beta_st && csa->d_st))
+ goto loop;
+ /* current basis is optimal */
+ display(csa, 1);
+ switch (csa->phase)
+ { case 1:
+ /* check for primal feasibility */
+ if (!check_feas(csa, 2, tol_bnd, tol_bnd1))
+ { /* feasible solution found; switch to phase II */
+ memcpy(c, csa->orig_c, (1+n) * sizeof(double));
+ csa->phase = 2;
+ csa->d_st = 0;
+ goto loop;
+ }
+ /* no feasible solution exists */
+#if 1 /* 09/VII-2017 */
+ /* FIXME: remove perturbation */
+#endif
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("LP HAS NO PRIMAL FEASIBLE SOLUTION\n");
+ csa->p_stat = GLP_NOFEAS;
+ csa->d_stat = GLP_UNDEF; /* will be set below */
+ ret = 0;
+ goto fini;
+ case 2:
+ /* optimal solution found */
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("OPTIMAL LP SOLUTION FOUND\n");
+ csa->p_stat = csa->d_stat = GLP_FEAS;
+ ret = 0;
+ goto fini;
+ default:
+ xassert(csa != csa);
+ }
+ }
+ /* choose xN[q] and xB[p] */
+#if 0 /* 23/VI-2017 */
+#if 0 /* 17/III-2016 */
+ choose_pivot(csa);
+#else
+ if (choose_pivot(csa) < 0)
+ { lp->valid = 0;
+ goto loop;
+ }
+#endif
+#else
+ ret = choose_pivot(csa);
+ if (ret < 0)
+ { lp->valid = 0;
+ goto loop;
+ }
+ if (ret == 0)
+ csa->ns_cnt++;
+ else
+ csa->ls_cnt++;
+#endif
+ /* check for unboundedness */
+ if (csa->p == 0)
+ { if (perturb > 0)
+ { /* remove perturbation */
+ remove_perturb(csa);
+ perturb = 0;
+ }
+ if (csa->beta_st != 1)
+ csa->beta_st = 0;
+ if (csa->d_st != 1)
+ csa->d_st = 0;
+ if (!(csa->beta_st && csa->d_st))
+ goto loop;
+ display(csa, 1);
+ switch (csa->phase)
+ { case 1:
+ /* this should never happen */
+ if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Error: primal simplex failed\n");
+ csa->p_stat = csa->d_stat = GLP_UNDEF;
+ ret = GLP_EFAIL;
+ goto fini;
+ case 2:
+ /* primal unboundedness detected */
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("LP HAS UNBOUNDED PRIMAL SOLUTION\n");
+ csa->p_stat = GLP_FEAS;
+ csa->d_stat = GLP_NOFEAS;
+ ret = 0;
+ goto fini;
+ default:
+ xassert(csa != csa);
+ }
+ }
+#if 1 /* 01/VII-2017 */
+ /* check for stalling */
+ if (csa->p > 0)
+ { int k;
+ xassert(1 <= csa->p && csa->p <= m);
+ k = head[csa->p]; /* x[k] = xB[p] */
+ if (lp->l[k] != lp->u[k])
+ { if (csa->p_flag)
+ { /* xB[p] goes to its upper bound */
+ xassert(lp->u[k] != +DBL_MAX);
+ if (fabs(beta[csa->p] - lp->u[k]) >= 1e-6)
+ { csa->degen = 0;
+ goto skip1;
+ }
+ }
+ else if (lp->l[k] == -DBL_MAX)
+ { /* unusual case */
+ goto skip1;
+ }
+ else
+ { /* xB[p] goes to its lower bound */
+ xassert(lp->l[k] != -DBL_MAX);
+ if (fabs(beta[csa->p] - lp->l[k]) >= 1e-6)
+ { csa->degen = 0;
+ goto skip1;
+ }
+ }
+ /* degenerate iteration has been detected */
+ csa->degen++;
+ if (perturb < 0 && csa->degen >= 200)
+ { if (msg_lev >= GLP_MSG_ALL)
+ xprintf("Perturbing LP to avoid stalling [%d]...\n",
+ csa->it_cnt);
+ perturb = 1;
+ }
+skip1: ;
+ }
+ }
+#endif
+ /* update values of basic variables for adjacent basis */
+#if 0 /* 11/VI-2017 */
+ spx_update_beta(lp, beta, csa->p, csa->p_flag, csa->q, tcol);
+#else
+ spx_update_beta_s(lp, beta, csa->p, csa->p_flag, csa->q,
+ &csa->tcol);
+#endif
+ csa->beta_st = 2;
+ /* p < 0 means that xN[q] jumps to its opposite bound */
+ if (csa->p < 0)
+ goto skip;
+ /* xN[q] enters and xB[p] leaves the basis */
+ /* compute p-th row of inv(B) */
+ spx_eval_rho(lp, csa->p, rho);
+ /* compute p-th (pivot) row of the simplex table */
+#if 0 /* 11/VI-2017 */
+ if (at != NULL)
+ spx_eval_trow1(lp, at, rho, trow);
+ else
+ spx_nt_prod(lp, nt, trow, 1, -1.0, rho);
+#else
+ if (at != NULL)
+ spx_eval_trow1(lp, at, rho, csa->trow.vec);
+ else
+ spx_nt_prod(lp, nt, csa->trow.vec, 1, -1.0, rho);
+ fvs_gather_vec(&csa->trow, DBL_EPSILON);
+#endif
+ /* FIXME: tcol[p] and trow[q] should be close to each other */
+#if 0 /* 26/V-2017 by cmatraki */
+ xassert(trow[csa->q] != 0.0);
+#else
+ if (csa->trow.vec[csa->q] == 0.0)
+ { if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Error: trow[q] = 0.0\n");
+ csa->p_stat = csa->d_stat = GLP_UNDEF;
+ ret = GLP_EFAIL;
+ goto fini;
+ }
+#endif
+ /* update reduced costs of non-basic variables for adjacent
+ * basis */
+#if 1 /* 23/VI-2017 */
+ /* dual solution may be invalidated due to long step */
+ if (csa->d_st)
+#endif
+#if 0 /* 11/VI-2017 */
+ if (spx_update_d(lp, d, csa->p, csa->q, trow, tcol) <= 1e-9)
+#else
+ if (spx_update_d_s(lp, d, csa->p, csa->q, &csa->trow, &csa->tcol)
+ <= 1e-9)
+#endif
+ { /* successful updating */
+ csa->d_st = 2;
+ if (csa->phase == 1)
+ { /* adjust reduced cost of xN[q] in adjacent basis, since
+ * its penalty coefficient changes (see below) */
+ d[csa->q] -= c[head[csa->p]];
+ }
+ }
+ else
+ { /* new reduced costs are inaccurate */
+ csa->d_st = 0;
+ }
+ if (csa->phase == 1)
+ { /* xB[p] leaves the basis replacing xN[q], so set its penalty
+ * coefficient to zero */
+ c[head[csa->p]] = 0.0;
+ }
+ /* update steepest edge weights for adjacent basis, if used */
+ if (se != NULL)
+ { if (refct > 0)
+#if 0 /* 11/VI-2017 */
+ { if (spx_update_gamma(lp, se, csa->p, csa->q, trow, tcol)
+ <= 1e-3)
+#else /* FIXME: spx_update_gamma_s */
+ { if (spx_update_gamma(lp, se, csa->p, csa->q, csa->trow.vec,
+ csa->tcol.vec) <= 1e-3)
+#endif
+ { /* successful updating */
+ refct--;
+ }
+ else
+ { /* new weights are inaccurate; reset reference space */
+ se->valid = 0;
+ }
+ }
+ else
+ { /* too many updates; reset reference space */
+ se->valid = 0;
+ }
+ }
+ /* update matrix N for adjacent basis, if used */
+ if (nt != NULL)
+ spx_update_nt(lp, nt, csa->p, csa->q);
+skip: /* change current basis header to adjacent one */
+ spx_change_basis(lp, csa->p, csa->p_flag, csa->q);
+ /* and update factorization of the basis matrix */
+ if (csa->p > 0)
+ spx_update_invb(lp, csa->p, head[csa->p]);
+#if 1
+ if (perturb <= 0)
+ { if (csa->phase == 1)
+ { int cnt;
+ /* adjust penalty function coefficients */
+ cnt = adjust_penalty(csa, csa->tcol.nnz, csa->tcol.ind,
+ 0.99 * tol_bnd, 0.99 * tol_bnd1);
+ if (cnt)
+ { /* some coefficients were changed, so invalidate reduced
+ * costs of non-basic variables */
+ /*xprintf("... cnt = %d\n", cnt);*/
+ csa->d_st = 0;
+ }
+ }
+ }
+ else
+ { /* FIXME */
+ play_bounds(csa, 0);
+ }
+#endif
+ /* simplex iteration complete */
+ csa->it_cnt++;
+ goto loop;
+fini: /* restore original objective function */
+ memcpy(c, csa->orig_c, (1+n) * sizeof(double));
+ /* compute reduced costs of non-basic variables and determine
+ * solution dual status, if necessary */
+ if (csa->p_stat != GLP_UNDEF && csa->d_stat == GLP_UNDEF)
+ { xassert(ret != GLP_EFAIL);
+ spx_eval_pi(lp, pi);
+ for (j = 1; j <= n-m; j++)
+ d[j] = spx_eval_dj(lp, pi, j);
+ csa->num = spx_chuzc_sel(lp, d, tol_dj, tol_dj1, NULL);
+ csa->d_stat = (csa->num == 0 ? GLP_FEAS : GLP_INFEAS);
+ }
+ return ret;
+}
+
+int spx_primal(glp_prob *P, const glp_smcp *parm)
+{ /* driver to the primal simplex method */
+ struct csa csa_, *csa = &csa_;
+ SPXLP lp;
+ SPXAT at;
+ SPXNT nt;
+ SPXSE se;
+ int ret, *map, *daeh;
+#if SCALE_Z
+ int i, j, k;
+#endif
+ /* build working LP and its initial basis */
+ memset(csa, 0, sizeof(struct csa));
+ csa->lp = &lp;
+ spx_init_lp(csa->lp, P, parm->excl);
+ spx_alloc_lp(csa->lp);
+ map = talloc(1+P->m+P->n, int);
+ spx_build_lp(csa->lp, P, parm->excl, parm->shift, map);
+ spx_build_basis(csa->lp, P, map);
+ switch (P->dir)
+ { case GLP_MIN:
+ csa->dir = +1;
+ break;
+ case GLP_MAX:
+ csa->dir = -1;
+ break;
+ default:
+ xassert(P != P);
+ }
+#if SCALE_Z
+ csa->fz = 0.0;
+ for (k = 1; k <= csa->lp->n; k++)
+ { double t = fabs(csa->lp->c[k]);
+ if (csa->fz < t)
+ csa->fz = t;
+ }
+ if (csa->fz <= 1000.0)
+ csa->fz = 1.0;
+ else
+ csa->fz /= 1000.0;
+ /*xprintf("csa->fz = %g\n", csa->fz);*/
+ for (k = 0; k <= csa->lp->n; k++)
+ csa->lp->c[k] /= csa->fz;
+#endif
+ csa->orig_c = talloc(1+csa->lp->n, double);
+ memcpy(csa->orig_c, csa->lp->c, (1+csa->lp->n) * sizeof(double));
+#if 1 /*PERTURB*/
+ csa->orig_l = talloc(1+csa->lp->n, double);
+ memcpy(csa->orig_l, csa->lp->l, (1+csa->lp->n) * sizeof(double));
+ csa->orig_u = talloc(1+csa->lp->n, double);
+ memcpy(csa->orig_u, csa->lp->u, (1+csa->lp->n) * sizeof(double));
+#else
+ csa->orig_l = csa->orig_u = NULL;
+#endif
+ switch (parm->aorn)
+ { case GLP_USE_AT:
+ /* build matrix A in row-wise format */
+ csa->at = &at;
+ csa->nt = NULL;
+ spx_alloc_at(csa->lp, csa->at);
+ spx_build_at(csa->lp, csa->at);
+ break;
+ case GLP_USE_NT:
+ /* build matrix N in row-wise format for initial basis */
+ csa->at = NULL;
+ csa->nt = &nt;
+ spx_alloc_nt(csa->lp, csa->nt);
+ spx_init_nt(csa->lp, csa->nt);
+ spx_build_nt(csa->lp, csa->nt);
+ break;
+ default:
+ xassert(parm != parm);
+ }
+ /* allocate and initialize working components */
+ csa->phase = 0;
+ csa->beta = talloc(1+csa->lp->m, double);
+ csa->beta_st = 0;
+ csa->d = talloc(1+csa->lp->n-csa->lp->m, double);
+ csa->d_st = 0;
+ switch (parm->pricing)
+ { case GLP_PT_STD:
+ csa->se = NULL;
+ break;
+ case GLP_PT_PSE:
+ csa->se = &se;
+ spx_alloc_se(csa->lp, csa->se);
+ break;
+ default:
+ xassert(parm != parm);
+ }
+ csa->list = talloc(1+csa->lp->n-csa->lp->m, int);
+#if 0 /* 11/VI-2017 */
+ csa->tcol = talloc(1+csa->lp->m, double);
+ csa->trow = talloc(1+csa->lp->n-csa->lp->m, double);
+#else
+ fvs_alloc_vec(&csa->tcol, csa->lp->m);
+ fvs_alloc_vec(&csa->trow, csa->lp->n-csa->lp->m);
+#endif
+#if 1 /* 23/VI-2017 */
+ csa->bp = NULL;
+#endif
+#if 0 /* 09/VII-2017 */
+ csa->work = talloc(1+csa->lp->m, double);
+#else
+ fvs_alloc_vec(&csa->work, csa->lp->m);
+#endif
+ /* initialize control parameters */
+ csa->msg_lev = parm->msg_lev;
+#if 0 /* 23/VI-2017 */
+ switch (parm->r_test)
+ { case GLP_RT_STD:
+ csa->harris = 0;
+ break;
+ case GLP_RT_HAR:
+#if 1 /* 16/III-2016 */
+ case GLP_RT_FLIP:
+ /* FIXME */
+ /* currently for primal simplex GLP_RT_FLIP is equivalent
+ * to GLP_RT_HAR */
+#endif
+ csa->harris = 1;
+ break;
+ default:
+ xassert(parm != parm);
+ }
+#else
+ switch (parm->r_test)
+ { case GLP_RT_STD:
+ case GLP_RT_HAR:
+ break;
+ case GLP_RT_FLIP:
+ csa->bp = talloc(1+2*csa->lp->m+1, SPXBP);
+ break;
+ default:
+ xassert(parm != parm);
+ }
+ csa->r_test = parm->r_test;
+#endif
+ csa->tol_bnd = parm->tol_bnd;
+ csa->tol_bnd1 = .001 * parm->tol_bnd;
+ csa->tol_dj = parm->tol_dj;
+ csa->tol_dj1 = .001 * parm->tol_dj;
+ csa->tol_piv = parm->tol_piv;
+ csa->it_lim = parm->it_lim;
+ csa->tm_lim = parm->tm_lim;
+ csa->out_frq = parm->out_frq;
+ csa->out_dly = parm->out_dly;
+ /* initialize working parameters */
+ csa->tm_beg = xtime();
+ csa->it_beg = csa->it_cnt = P->it_cnt;
+ csa->it_dpy = -1;
+#if 1 /* 15/VII-2017 */
+ csa->tm_dpy = 0.0;
+#endif
+ csa->inv_cnt = 0;
+#if 1 /* 01/VII-2017 */
+ csa->degen = 0;
+#endif
+#if 1 /* 23/VI-2017 */
+ csa->ns_cnt = csa->ls_cnt = 0;
+#endif
+ /* try to solve working LP */
+ ret = primal_simplex(csa);
+ /* return basis factorization back to problem object */
+ P->valid = csa->lp->valid;
+ P->bfd = csa->lp->bfd;
+ /* set solution status */
+ P->pbs_stat = csa->p_stat;
+ P->dbs_stat = csa->d_stat;
+ /* if the solver failed, do not store basis header and basic
+ * solution components to problem object */
+ if (ret == GLP_EFAIL)
+ goto skip;
+ /* convert working LP basis to original LP basis and store it to
+ * problem object */
+ daeh = talloc(1+csa->lp->n, int);
+ spx_store_basis(csa->lp, P, map, daeh);
+ /* compute simplex multipliers for final basic solution found by
+ * the solver */
+#if 0 /* 09/VII-2017 */
+ spx_eval_pi(csa->lp, csa->work);
+#else
+ spx_eval_pi(csa->lp, csa->work.vec);
+#endif
+ /* convert working LP solution to original LP solution and store
+ * it into the problem object */
+#if SCALE_Z
+ for (i = 1; i <= csa->lp->m; i++)
+ csa->work.vec[i] *= csa->fz;
+ for (j = 1; j <= csa->lp->n-csa->lp->m; j++)
+ csa->d[j] *= csa->fz;
+#endif
+#if 0 /* 09/VII-2017 */
+ spx_store_sol(csa->lp, P, SHIFT, map, daeh, csa->beta, csa->work,
+ csa->d);
+#else
+ spx_store_sol(csa->lp, P, parm->shift, map, daeh, csa->beta,
+ csa->work.vec, csa->d);
+#endif
+ tfree(daeh);
+ /* save simplex iteration count */
+ P->it_cnt = csa->it_cnt;
+ /* report auxiliary/structural variable causing unboundedness */
+ P->some = 0;
+ if (csa->p_stat == GLP_FEAS && csa->d_stat == GLP_NOFEAS)
+ { int k, kk;
+ /* xN[q] = x[k] causes unboundedness */
+ xassert(1 <= csa->q && csa->q <= csa->lp->n - csa->lp->m);
+ k = csa->lp->head[csa->lp->m + csa->q];
+ xassert(1 <= k && k <= csa->lp->n);
+ /* convert to number of original variable */
+ for (kk = 1; kk <= P->m + P->n; kk++)
+ { if (abs(map[kk]) == k)
+ { P->some = kk;
+ break;
+ }
+ }
+ xassert(P->some != 0);
+ }
+skip: /* deallocate working objects and arrays */
+ spx_free_lp(csa->lp);
+ tfree(map);
+ tfree(csa->orig_c);
+#if 1 /*PERTURB*/
+ tfree(csa->orig_l);
+ tfree(csa->orig_u);
+#endif
+ if (csa->at != NULL)
+ spx_free_at(csa->lp, csa->at);
+ if (csa->nt != NULL)
+ spx_free_nt(csa->lp, csa->nt);
+ tfree(csa->beta);
+ tfree(csa->d);
+ if (csa->se != NULL)
+ spx_free_se(csa->lp, csa->se);
+ tfree(csa->list);
+#if 0 /* 11/VI-2017 */
+ tfree(csa->tcol);
+ tfree(csa->trow);
+#else
+ fvs_free_vec(&csa->tcol);
+ fvs_free_vec(&csa->trow);
+#endif
+#if 1 /* 23/VI-2017 */
+ if (csa->bp != NULL)
+ tfree(csa->bp);
+#endif
+#if 0 /* 09/VII-2017 */
+ tfree(csa->work);
+#else
+ fvs_free_vec(&csa->work);
+#endif
+ /* return to calling program */
+ return ret;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxprob.c b/test/monniaux/glpk-4.65/src/simplex/spxprob.c
new file mode 100644
index 00000000..4bebe2e7
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxprob.c
@@ -0,0 +1,679 @@
+/* spxprob.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "spxprob.h"
+
+/***********************************************************************
+* spx_init_lp - initialize working LP object
+*
+* This routine determines the number of equality constraints m, the
+* number of variables n, and the number of non-zero elements nnz in
+* the constraint matrix for the working LP, which corresponds to the
+* original LP, and stores these dimensions to the working LP object.
+* (The working LP object should be allocated by the calling routine.)
+*
+* If the flag excl is set, the routine assumes that non-basic fixed
+* variables will be excluded from the working LP. */
+
+void spx_init_lp(SPXLP *lp, glp_prob *P, int excl)
+{ int i, j, m, n, nnz;
+ m = P->m;
+ xassert(m > 0);
+ n = 0;
+ nnz = P->nnz;
+ xassert(P->valid);
+ /* scan rows of original LP */
+ for (i = 1; i <= m; i++)
+ { GLPROW *row = P->row[i];
+ if (excl && row->stat == GLP_NS)
+ { /* skip non-basic fixed auxiliary variable */
+ /* nop */
+ }
+ else
+ { /* include auxiliary variable in working LP */
+ n++;
+ nnz++; /* unity column */
+ }
+ }
+ /* scan columns of original LP */
+ for (j = 1; j <= P->n; j++)
+ { GLPCOL *col = P->col[j];
+ if (excl && col->stat == GLP_NS)
+ { /* skip non-basic fixed structural variable */
+ GLPAIJ *aij;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ nnz--;
+ }
+ else
+ { /* include structural variable in working LP */
+ n++;
+ }
+ }
+ /* initialize working LP data block */
+ memset(lp, 0, sizeof(SPXLP));
+ lp->m = m;
+ xassert(n > 0);
+ lp->n = n;
+ lp->nnz = nnz;
+ return;
+}
+
+/***********************************************************************
+* spx_alloc_lp - allocate working LP arrays
+*
+* This routine allocates the memory for all arrays in the working LP
+* object. */
+
+void spx_alloc_lp(SPXLP *lp)
+{ int m = lp->m;
+ int n = lp->n;
+ int nnz = lp->nnz;
+ lp->A_ptr = talloc(1+n+1, int);
+ lp->A_ind = talloc(1+nnz, int);
+ lp->A_val = talloc(1+nnz, double);
+ lp->b = talloc(1+m, double);
+ lp->c = talloc(1+n, double);
+ lp->l = talloc(1+n, double);
+ lp->u = talloc(1+n, double);
+ lp->head = talloc(1+n, int);
+ lp->flag = talloc(1+n-m, char);
+ return;
+}
+
+/***********************************************************************
+* spx_build_lp - convert original LP to working LP
+*
+* This routine converts components (except the current basis) of the
+* original LP to components of the working LP and perform scaling of
+* these components. Also, if the original LP is maximization, the
+* routine changes the signs of the objective coefficients and constant
+* term to opposite ones.
+*
+* If the flag excl is set, original non-basic fixed variables are
+* *not* included in the working LP. Otherwise, all (auxiliary and
+* structural) original variables are included in the working LP. Note
+* that this flag should have the same value as it has in a call to the
+* routine spx_init_lp.
+*
+* If the flag shift is set, the routine shift bounds of variables
+* included in the working LP to make at least one bound to be zero.
+* If a variable has both lower and upper bounds, the bound having
+* smaller magnitude is shifted to zero.
+*
+* On exit the routine stores information about correspondence between
+* numbers of variables in the original and working LPs to the array
+* map, which should have 1+P->m+P->n locations (location [0] is not
+* used), where P->m is the numbers of rows and P->n is the number of
+* columns in the original LP:
+*
+* map[i] = +k, 1 <= i <= P->m, means that i-th auxiliary variable of
+* the original LP corresponds to variable x[k] of the working LP;
+*
+* map[i] = -k, 1 <= i <= P->m, means that i-th auxiliary variable of
+* the original LP corresponds to variable x[k] of the working LP, and
+* the upper bound of that variable was shifted to zero;
+*
+* map[i] = 0, 1 <= i <= P->m, means that i-th auxiliary variable of
+* the original LP was excluded from the working LP;
+*
+* map[P->m+j], 1 <= j <= P->n, has the same sense as above, however,
+* for j-th structural variable of the original LP. */
+
+void spx_build_lp(SPXLP *lp, glp_prob *P, int excl, int shift,
+ int map[/*1+P->m+P->n*/])
+{ int m = lp->m;
+ int n = lp->n;
+ int nnz = lp->nnz;
+ int *A_ptr = lp->A_ptr;
+ int *A_ind = lp->A_ind;
+ double *A_val = lp->A_val;
+ double *b = lp->b;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int i, j, k, kk, ptr, end;
+ double dir, delta;
+ /* working LP is always minimization */
+ switch (P->dir)
+ { case GLP_MIN:
+ dir = +1.0;
+ break;
+ case GLP_MAX:
+ dir = -1.0;
+ break;
+ default:
+ xassert(P != P);
+ }
+ /* initialize constant term of the objective */
+ c[0] = dir * P->c0;
+ k = 0; /* number of variable in working LP */
+ ptr = 1; /* current available position in A_ind/A_val */
+ /* process rows of original LP */
+ xassert(P->m == m);
+ for (i = 1; i <= m; i++)
+ { GLPROW *row = P->row[i];
+ if (excl && row->stat == GLP_NS)
+ { /* i-th auxiliary variable is non-basic and fixed */
+ /* substitute its scaled value in working LP */
+ xassert(row->type == GLP_FX);
+ map[i] = 0;
+ b[i] = - row->lb * row->rii;
+ }
+ else
+ { /* include i-th auxiliary variable in working LP */
+ map[i] = ++k;
+ /* setup k-th column of working constraint matrix which is
+ * i-th column of unity matrix */
+ A_ptr[k] = ptr;
+ A_ind[ptr] = i;
+ A_val[ptr] = 1.0;
+ ptr++;
+ /* initialize right-hand side of i-th equality constraint
+ * and setup zero objective coefficient at variable x[k] */
+ b[i] = c[k] = 0.0;
+ /* setup scaled bounds of variable x[k] */
+ switch (row->type)
+ { case GLP_FR:
+ l[k] = -DBL_MAX, u[k] = +DBL_MAX;
+ break;
+ case GLP_LO:
+ l[k] = row->lb * row->rii, u[k] = +DBL_MAX;
+ break;
+ case GLP_UP:
+ l[k] = -DBL_MAX, u[k] = row->ub * row->rii;
+ break;
+ case GLP_DB:
+ l[k] = row->lb * row->rii, u[k] = row->ub * row->rii;
+ xassert(l[k] != u[k]);
+ break;
+ case GLP_FX:
+ l[k] = u[k] = row->lb * row->rii;
+ break;
+ default:
+ xassert(row != row);
+ }
+ }
+ }
+ /* process columns of original LP */
+ for (j = 1; j <= P->n; j++)
+ { GLPCOL *col = P->col[j];
+ GLPAIJ *aij;
+ if (excl && col->stat == GLP_NS)
+ { /* j-th structural variable is non-basic and fixed */
+ /* substitute its scaled value in working LP */
+ xassert(col->type == GLP_FX);
+ map[m+j] = 0;
+ if (col->lb != 0.0)
+ { /* (note that sjj scale factor is cancelled) */
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ b[aij->row->i] +=
+ (aij->row->rii * aij->val) * col->lb;
+ c[0] += (dir * col->coef) * col->lb;
+ }
+ }
+ else
+ { /* include j-th structural variable in working LP */
+ map[m+j] = ++k;
+ /* setup k-th column of working constraint matrix which is
+ * scaled j-th column of original constraint matrix (-A) */
+ A_ptr[k] = ptr;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ { A_ind[ptr] = aij->row->i;
+ A_val[ptr] = - aij->row->rii * aij->val * col->sjj;
+ ptr++;
+ }
+ /* setup scaled objective coefficient at variable x[k] */
+ c[k] = dir * col->coef * col->sjj;
+ /* setup scaled bounds of variable x[k] */
+ switch (col->type)
+ { case GLP_FR:
+ l[k] = -DBL_MAX, u[k] = +DBL_MAX;
+ break;
+ case GLP_LO:
+ l[k] = col->lb / col->sjj, u[k] = +DBL_MAX;
+ break;
+ case GLP_UP:
+ l[k] = -DBL_MAX, u[k] = col->ub / col->sjj;
+ break;
+ case GLP_DB:
+ l[k] = col->lb / col->sjj, u[k] = col->ub / col->sjj;
+ xassert(l[k] != u[k]);
+ break;
+ case GLP_FX:
+ l[k] = u[k] = col->lb / col->sjj;
+ break;
+ default:
+ xassert(col != col);
+ }
+ }
+ }
+ xassert(k == n);
+ xassert(ptr == nnz+1);
+ A_ptr[n+1] = ptr;
+ /* shift bounds of all variables of working LP (optionally) */
+ if (shift)
+ { for (kk = 1; kk <= m+P->n; kk++)
+ { k = map[kk];
+ if (k == 0)
+ { /* corresponding original variable was excluded */
+ continue;
+ }
+ /* shift bounds of variable x[k] */
+ if (l[k] == -DBL_MAX && u[k] == +DBL_MAX)
+ { /* x[k] is unbounded variable */
+ delta = 0.0;
+ }
+ else if (l[k] != -DBL_MAX && u[k] == +DBL_MAX)
+ { /* shift lower bound to zero */
+ delta = l[k];
+ l[k] = 0.0;
+ }
+ else if (l[k] == -DBL_MAX && u[k] != +DBL_MAX)
+ { /* shift upper bound to zero */
+ map[kk] = -k;
+ delta = u[k];
+ u[k] = 0.0;
+ }
+ else if (l[k] != u[k])
+ { /* x[k] is double bounded variable */
+ if (fabs(l[k]) <= fabs(u[k]))
+ { /* shift lower bound to zero */
+ delta = l[k];
+ l[k] = 0.0, u[k] -= delta;
+ }
+ else
+ { /* shift upper bound to zero */
+ map[kk] = -k;
+ delta = u[k];
+ l[k] -= delta, u[k] = 0.0;
+ }
+ xassert(l[k] != u[k]);
+ }
+ else
+ { /* shift fixed value to zero */
+ delta = l[k];
+ l[k] = u[k] = 0.0;
+ }
+ /* substitute x[k] = x'[k] + delta into all constraints
+ * and the objective function of working LP */
+ if (delta != 0.0)
+ { ptr = A_ptr[k];
+ end = A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ b[A_ind[ptr]] -= A_val[ptr] * delta;
+ c[0] += c[k] * delta;
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* spx_build_basis - convert original LP basis to working LP basis
+*
+* This routine converts the current basis of the original LP to
+* corresponding initial basis of the working LP, and moves the basis
+* factorization driver from the original LP object to the working LP
+* object.
+*
+* The array map should contain information provided by the routine
+* spx_build_lp. */
+
+void spx_build_basis(SPXLP *lp, glp_prob *P, const int map[])
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int i, j, k, ii, jj;
+ /* original basis factorization should be valid that guarantees
+ * the basis is correct */
+ xassert(P->m == m);
+ xassert(P->valid);
+ /* initialize basis header for working LP */
+ memset(&head[1], 0, m * sizeof(int));
+ jj = 0;
+ /* scan rows of original LP */
+ xassert(P->m == m);
+ for (i = 1; i <= m; i++)
+ { GLPROW *row = P->row[i];
+ /* determine ordinal number of x[k] in working LP */
+ if ((k = map[i]) < 0)
+ k = -k;
+ if (k == 0)
+ { /* corresponding original variable was excluded */
+ continue;
+ }
+ xassert(1 <= k && k <= n);
+ if (row->stat == GLP_BS)
+ { /* x[k] is basic variable xB[ii] */
+ ii = row->bind;
+ xassert(1 <= ii && ii <= m);
+ xassert(head[ii] == 0);
+ head[ii] = k;
+ }
+ else
+ { /* x[k] is non-basic variable xN[jj] */
+ jj++;
+ head[m+jj] = k;
+ flag[jj] = (row->stat == GLP_NU);
+ }
+ }
+ /* scan columns of original LP */
+ for (j = 1; j <= P->n; j++)
+ { GLPCOL *col = P->col[j];
+ /* determine ordinal number of x[k] in working LP */
+ if ((k = map[m+j]) < 0)
+ k = -k;
+ if (k == 0)
+ { /* corresponding original variable was excluded */
+ continue;
+ }
+ xassert(1 <= k && k <= n);
+ if (col->stat == GLP_BS)
+ { /* x[k] is basic variable xB[ii] */
+ ii = col->bind;
+ xassert(1 <= ii && ii <= m);
+ xassert(head[ii] == 0);
+ head[ii] = k;
+ }
+ else
+ { /* x[k] is non-basic variable xN[jj] */
+ jj++;
+ head[m+jj] = k;
+ flag[jj] = (col->stat == GLP_NU);
+ }
+ }
+ xassert(m+jj == n);
+ /* acquire basis factorization */
+ lp->valid = 1;
+ lp->bfd = P->bfd;
+ P->valid = 0;
+ P->bfd = NULL;
+ return;
+}
+
+/***********************************************************************
+* spx_store_basis - convert working LP basis to original LP basis
+*
+* This routine converts the current working LP basis to corresponding
+* original LP basis. This operations includes determining and setting
+* statuses of all rows (auxiliary variables) and columns (structural
+* variables), and building the basis header.
+*
+* The array map should contain information provided by the routine
+* spx_build_lp.
+*
+* On exit the routine fills the array daeh. This array should have
+* 1+lp->n locations (location [0] is not used) and contain the inverse
+* of the working basis header lp->head, i.e. head[k'] = k means that
+* daeh[k] = k'. */
+
+void spx_store_basis(SPXLP *lp, glp_prob *P, const int map[],
+ int daeh[/*1+n*/])
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int i, j, k, kk;
+ /* determine inverse of working basis header */
+ for (kk = 1; kk <= n; kk++)
+ daeh[head[kk]] = kk;
+ /* set row statuses */
+ xassert(P->m == m);
+ for (i = 1; i <= m; i++)
+ { GLPROW *row = P->row[i];
+ if ((k = map[i]) < 0)
+ k = -k;
+ if (k == 0)
+ { /* non-basic fixed auxiliary variable was excluded */
+ xassert(row->type == GLP_FX);
+ row->stat = GLP_NS;
+ row->bind = 0;
+ }
+ else
+ { /* auxiliary variable corresponds to variable x[k] */
+ kk = daeh[k];
+ if (kk <= m)
+ { /* x[k] = xB[kk] */
+ P->head[kk] = i;
+ row->stat = GLP_BS;
+ row->bind = kk;
+ }
+ else
+ { /* x[k] = xN[kk-m] */
+ switch (row->type)
+ { case GLP_FR:
+ row->stat = GLP_NF;
+ break;
+ case GLP_LO:
+ row->stat = GLP_NL;
+ break;
+ case GLP_UP:
+ row->stat = GLP_NU;
+ break;
+ case GLP_DB:
+ row->stat = (flag[kk-m] ? GLP_NU : GLP_NL);
+ break;
+ case GLP_FX:
+ row->stat = GLP_NS;
+ break;
+ default:
+ xassert(row != row);
+ }
+ row->bind = 0;
+ }
+ }
+ }
+ /* set column statuses */
+ for (j = 1; j <= P->n; j++)
+ { GLPCOL *col = P->col[j];
+ if ((k = map[m+j]) < 0)
+ k = -k;
+ if (k == 0)
+ { /* non-basic fixed structural variable was excluded */
+ xassert(col->type == GLP_FX);
+ col->stat = GLP_NS;
+ col->bind = 0;
+ }
+ else
+ { /* structural variable corresponds to variable x[k] */
+ kk = daeh[k];
+ if (kk <= m)
+ { /* x[k] = xB[kk] */
+ P->head[kk] = m+j;
+ col->stat = GLP_BS;
+ col->bind = kk;
+ }
+ else
+ { /* x[k] = xN[kk-m] */
+ switch (col->type)
+ { case GLP_FR:
+ col->stat = GLP_NF;
+ break;
+ case GLP_LO:
+ col->stat = GLP_NL;
+ break;
+ case GLP_UP:
+ col->stat = GLP_NU;
+ break;
+ case GLP_DB:
+ col->stat = (flag[kk-m] ? GLP_NU : GLP_NL);
+ break;
+ case GLP_FX:
+ col->stat = GLP_NS;
+ break;
+ default:
+ xassert(col != col);
+ }
+ col->bind = 0;
+ }
+ }
+ }
+ return;
+}
+
+/***********************************************************************
+* spx_store_sol - convert working LP solution to original LP solution
+*
+* This routine converts the current basic solution of the working LP
+* (values of basic variables, simplex multipliers, reduced costs of
+* non-basic variables) to corresponding basic solution of the original
+* LP (values and reduced costs of auxiliary and structural variables).
+* This conversion includes unscaling all basic solution components,
+* computing reduced costs of excluded non-basic variables, recovering
+* unshifted values of basic variables, changing the signs of reduced
+* costs (if the original LP is maximization), and computing the value
+* of the objective function.
+*
+* The flag shift should have the same value as it has in a call to the
+* routine spx_build_lp.
+*
+* The array map should contain information provided by the routine
+* spx_build_lp.
+*
+* The array daeh should contain information provided by the routine
+* spx_store_basis.
+*
+* The arrays beta, pi, and d should contain basic solution components
+* for the working LP:
+*
+* array locations beta[1], ..., beta[m] should contain values of basic
+* variables beta = (beta[i]);
+*
+* array locations pi[1], ..., pi[m] should contain simplex multipliers
+* pi = (pi[i]);
+*
+* array locations d[1], ..., d[n-m] should contain reduced costs of
+* non-basic variables d = (d[j]). */
+
+void spx_store_sol(SPXLP *lp, glp_prob *P, int shift,
+ const int map[], const int daeh[], const double beta[],
+ const double pi[], const double d[])
+{ int m = lp->m;
+ char *flag = lp->flag;
+ int i, j, k, kk;
+ double dir;
+ /* working LP is always minimization */
+ switch (P->dir)
+ { case GLP_MIN:
+ dir = +1.0;
+ break;
+ case GLP_MAX:
+ dir = -1.0;
+ break;
+ default:
+ xassert(P != P);
+ }
+ /* compute row solution components */
+ xassert(P->m == m);
+ for (i = 1; i <= m; i++)
+ { GLPROW *row = P->row[i];
+ if ((k = map[i]) < 0)
+ k = -k;
+ if (k == 0)
+ { /* non-basic fixed auxiliary variable was excluded */
+ xassert(row->type == GLP_FX);
+ row->prim = row->lb;
+ /* compute reduced cost d[k] = c[k] - A'[k] * pi as if x[k]
+ * would be non-basic in working LP */
+ row->dual = - dir * pi[i] * row->rii;
+ }
+ else
+ { /* auxiliary variable corresponds to variable x[k] */
+ kk = daeh[k];
+ if (kk <= m)
+ { /* x[k] = xB[kk] */
+ row->prim = beta[kk] / row->rii;
+ if (shift)
+ row->prim += (map[i] < 0 ? row->ub : row->lb);
+ row->dual = 0.0;
+ }
+ else
+ { /* x[k] = xN[kk-m] */
+ row->prim = (flag[kk-m] ? row->ub : row->lb);
+ row->dual = (dir * d[kk-m]) * row->rii;
+ }
+ }
+ }
+ /* compute column solution components and objective value */
+ P->obj_val = P->c0;
+ for (j = 1; j <= P->n; j++)
+ { GLPCOL *col = P->col[j];
+ if ((k = map[m+j]) < 0)
+ k = -k;
+ if (k == 0)
+ { /* non-basic fixed structural variable was excluded */
+ GLPAIJ *aij;
+ double dk;
+ xassert(col->type == GLP_FX);
+ col->prim = col->lb;
+ /* compute reduced cost d[k] = c[k] - A'[k] * pi as if x[k]
+ * would be non-basic in working LP */
+ /* (note that sjj scale factor is cancelled) */
+ dk = dir * col->coef;
+ for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+ dk += (aij->row->rii * aij->val) * pi[aij->row->i];
+ col->dual = dir * dk;
+ }
+ else
+ { /* structural variable corresponds to variable x[k] */
+ kk = daeh[k];
+ if (kk <= m)
+ { /* x[k] = xB[kk] */
+ col->prim = beta[kk] * col->sjj;
+ if (shift)
+ col->prim += (map[m+j] < 0 ? col->ub : col->lb);
+ col->dual = 0.0;
+ }
+ else
+ { /* x[k] = xN[kk-m] */
+ col->prim = (flag[kk-m] ? col->ub : col->lb);
+ col->dual = (dir * d[kk-m]) / col->sjj;
+ }
+ }
+ P->obj_val += col->coef * col->prim;
+ }
+ return;
+}
+
+/***********************************************************************
+* spx_free_lp - deallocate working LP arrays
+*
+* This routine deallocates the memory used for arrays of the working
+* LP object. */
+
+void spx_free_lp(SPXLP *lp)
+{ tfree(lp->A_ptr);
+ tfree(lp->A_ind);
+ tfree(lp->A_val);
+ tfree(lp->b);
+ tfree(lp->c);
+ tfree(lp->l);
+ tfree(lp->u);
+ tfree(lp->head);
+ tfree(lp->flag);
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spxprob.h b/test/monniaux/glpk-4.65/src/simplex/spxprob.h
new file mode 100644
index 00000000..b7d87fa7
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spxprob.h
@@ -0,0 +1,64 @@
+/* spxprob.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#ifndef SPXPROB_H
+#define SPXPROB_H
+
+#include "prob.h"
+#include "spxlp.h"
+
+#define spx_init_lp _glp_spx_init_lp
+void spx_init_lp(SPXLP *lp, glp_prob *P, int excl);
+/* initialize working LP object */
+
+#define spx_alloc_lp _glp_spx_alloc_lp
+void spx_alloc_lp(SPXLP *lp);
+/* allocate working LP arrays */
+
+#define spx_build_lp _glp_spx_build_lp
+void spx_build_lp(SPXLP *lp, glp_prob *P, int excl, int shift,
+ int map[/*1+P->m+P->n*/]);
+/* convert original LP to working LP */
+
+#define spx_build_basis _glp_spx_build_basis
+void spx_build_basis(SPXLP *lp, glp_prob *P, const int map[]);
+/* convert original LP basis to working LP basis */
+
+#define spx_store_basis _glp_spx_store_basis
+void spx_store_basis(SPXLP *lp, glp_prob *P, const int map[],
+ int daeh[/*1+n*/]);
+/* convert working LP basis to original LP basis */
+
+#define spx_store_sol _glp_spx_store_sol
+void spx_store_sol(SPXLP *lp, glp_prob *P, int shift,
+ const int map[], const int daeh[], const double beta[],
+ const double pi[], const double d[]);
+/* convert working LP solution to original LP solution */
+
+#define spx_free_lp _glp_spx_free_lp
+void spx_free_lp(SPXLP *lp);
+/* deallocate working LP arrays */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spychuzc.c b/test/monniaux/glpk-4.65/src/simplex/spychuzc.c
new file mode 100644
index 00000000..b9221298
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spychuzc.c
@@ -0,0 +1,567 @@
+/* spychuzc.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015-2018 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "spychuzc.h"
+
+/***********************************************************************
+* spy_chuzc_std - choose non-basic variable (dual textbook ratio test)
+*
+* This routine implements an improved dual textbook ratio test to
+* choose non-basic variable xN[q].
+*
+* Current reduced costs of non-basic variables should be placed in the
+* array locations d[1], ..., d[n-m]. Note that d[j] is a value of dual
+* basic variable lambdaN[j] in the current basis.
+*
+#if 0 (* 14/III-2016 *)
+* The parameter s specifies the sign of bound violation for basic
+* variable xB[p] chosen: s = +1.0 means that xB[p] violates its lower
+* bound, so dual non-basic variable lambdaB[p] = lambda^+B[p]
+* increases, and s = -1.0 means that xB[p] violates its upper bound,
+* so dual non-basic variable lambdaB[p] = lambda^-B[p] decreases.
+* (Thus, the dual ray parameter theta = s * lambdaB[p] >= 0.)
+#else
+* The parameter r specifies the bound violation for basic variable
+* xB[p] chosen:
+*
+* r = lB[p] - beta[p] > 0 means that xB[p] violates its lower bound,
+* so dual non-basic variable lambdaB[p] = lambda^+B[p] increases; and
+*
+* r = uB[p] - beta[p] < 0 means that xB[p] violates its upper bound,
+* so dual non-basic variable lambdaB[p] = lambda^-B[p] decreases.
+*
+* (Note that r is the dual reduced cost of lambdaB[p].)
+#endif
+*
+* Elements of p-th simplex table row t[p] = (t[p,j]) corresponding
+* to basic variable xB[p] should be placed in the array locations
+* trow[1], ..., trow[n-m].
+*
+* The parameter tol_piv specifies a tolerance for elements of the
+* simplex table row t[p]. If |t[p,j]| < tol_piv, dual basic variable
+* lambdaN[j] is skipped, i.e. it is assumed that it does not depend on
+* the dual ray parameter theta.
+*
+* The parameters tol and tol1 specify tolerances used to increase the
+* choice freedom by simulating an artificial degeneracy as follows.
+* If lambdaN[j] = lambda^+N[j] >= 0 and d[j] <= +delta[j], or if
+* lambdaN[j] = lambda^-N[j] <= 0 and d[j] >= -delta[j], where
+* delta[j] = tol + tol1 * |cN[j]|, cN[j] is objective coefficient at
+* xN[j], then it is assumed that reduced cost d[j] is equal to zero.
+*
+* The routine determines the index 1 <= q <= n-m of non-basic variable
+* xN[q], for which corresponding dual basic variable lambda^+N[j] or
+* lambda^-N[j] reaches its zero bound first on increasing the dual ray
+* parameter theta, and returns p on exit. And if theta may increase
+* unlimitedly, the routine returns zero. */
+
+int spy_chuzc_std(SPXLP *lp, const double d[/*1+n-m*/],
+#if 0 /* 14/III-2016 */
+ double s, const double trow[/*1+n-m*/], double tol_piv,
+#else
+ double r, const double trow[/*1+n-m*/], double tol_piv,
+#endif
+ double tol, double tol1)
+{ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int j, k, q;
+ double alfa, biga, delta, teta, teta_min;
+#if 0 /* 14/III-2016 */
+ xassert(s == +1.0 || s == -1.0);
+#else
+ double s;
+ xassert(r != 0.0);
+ s = (r > 0.0 ? +1.0 : -1.0);
+#endif
+ /* nothing is chosen so far */
+ q = 0, teta_min = DBL_MAX, biga = 0.0;
+ /* walk thru the list of non-basic variables */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ /* if xN[j] is fixed variable, skip it */
+ if (l[k] == u[k])
+ continue;
+ alfa = s * trow[j];
+ if (alfa >= +tol_piv && !flag[j])
+ { /* xN[j] is either free or has its lower bound active, so
+ * lambdaN[j] = d[j] >= 0 decreases down to zero */
+ delta = tol + tol1 * (c[k] >= 0.0 ? +c[k] : -c[k]);
+ /* determine theta on which lambdaN[j] reaches zero */
+ teta = (d[j] < +delta ? 0.0 : d[j] / alfa);
+ }
+ else if (alfa <= -tol_piv && (l[k] == -DBL_MAX || flag[j]))
+ { /* xN[j] is either free or has its upper bound active, so
+ * lambdaN[j] = d[j] <= 0 increases up to zero */
+ delta = tol + tol1 * (c[k] >= 0.0 ? +c[k] : -c[k]);
+ /* determine theta on which lambdaN[j] reaches zero */
+ teta = (d[j] > -delta ? 0.0 : d[j] / alfa);
+ }
+ else
+ { /* lambdaN[j] cannot reach zero on increasing theta */
+ continue;
+ }
+ /* choose non-basic variable xN[q] by corresponding dual basic
+ * variable lambdaN[q] for which theta is minimal */
+ xassert(teta >= 0.0);
+ alfa = (alfa >= 0.0 ? +alfa : -alfa);
+ if (teta_min > teta || (teta_min == teta && biga < alfa))
+ q = j, teta_min = teta, biga = alfa;
+ }
+ return q;
+}
+
+/***********************************************************************
+* spy_chuzc_harris - choose non-basic var. (dual Harris' ratio test)
+*
+* This routine implements dual Harris' ratio test to choose non-basic
+* variable xN[q].
+*
+* All the parameters, except tol and tol1, as well as the returned
+* value have the same meaning as for the routine spx_chuzr_std (see
+* above).
+*
+* The parameters tol and tol1 specify tolerances on zero bound
+* violations for reduced costs of non-basic variables. For reduced
+* cost d[j] the tolerance is delta[j] = tol + tol1 |cN[j]|, where
+* cN[j] is objective coefficient at non-basic variable xN[j]. */
+
+int spy_chuzc_harris(SPXLP *lp, const double d[/*1+n-m*/],
+#if 0 /* 14/III-2016 */
+ double s, const double trow[/*1+n-m*/], double tol_piv,
+#else
+ double r, const double trow[/*1+n-m*/], double tol_piv,
+#endif
+ double tol, double tol1)
+{ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int j, k, q;
+ double alfa, biga, delta, teta, teta_min;
+#if 0 /* 14/III-2016 */
+ xassert(s == +1.0 || s == -1.0);
+#else
+ double s;
+ xassert(r != 0.0);
+ s = (r > 0.0 ? +1.0 : -1.0);
+#endif
+ /*--------------------------------------------------------------*/
+ /* first pass: determine teta_min for relaxed bounds */
+ /*--------------------------------------------------------------*/
+ teta_min = DBL_MAX;
+ /* walk thru the list of non-basic variables */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ /* if xN[j] is fixed variable, skip it */
+ if (l[k] == u[k])
+ continue;
+ alfa = s * trow[j];
+ if (alfa >= +tol_piv && !flag[j])
+ { /* xN[j] is either free or has its lower bound active, so
+ * lambdaN[j] = d[j] >= 0 decreases down to zero */
+ delta = tol + tol1 * (c[k] >= 0.0 ? +c[k] : -c[k]);
+ /* determine theta on which lambdaN[j] reaches -delta */
+ teta = ((d[j] < 0.0 ? 0.0 : d[j]) + delta) / alfa;
+ }
+ else if (alfa <= -tol_piv && (l[k] == -DBL_MAX || flag[j]))
+ { /* xN[j] is either free or has its upper bound active, so
+ * lambdaN[j] = d[j] <= 0 increases up to zero */
+ delta = tol + tol1 * (c[k] >= 0.0 ? +c[k] : -c[k]);
+ /* determine theta on which lambdaN[j] reaches +delta */
+ teta = ((d[j] > 0.0 ? 0.0 : d[j]) - delta) / alfa;
+ }
+ else
+ { /* lambdaN[j] cannot reach zero on increasing theta */
+ continue;
+ }
+ xassert(teta >= 0.0);
+ if (teta_min > teta)
+ teta_min = teta;
+ }
+ /*--------------------------------------------------------------*/
+ /* second pass: choose non-basic variable xN[q] */
+ /*--------------------------------------------------------------*/
+ if (teta_min == DBL_MAX)
+ { /* theta may increase unlimitedly */
+ q = 0;
+ goto done;
+ }
+ /* nothing is chosen so far */
+ q = 0, biga = 0.0;
+ /* walk thru the list of non-basic variables */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ /* if xN[j] is fixed variable, skip it */
+ if (l[k] == u[k])
+ continue;
+ alfa = s * trow[j];
+ if (alfa >= +tol_piv && !flag[j])
+ { /* xN[j] is either free or has its lower bound active, so
+ * lambdaN[j] = d[j] >= 0 decreases down to zero */
+ /* determine theta on which lambdaN[j] reaches zero */
+ teta = d[j] / alfa;
+ }
+ else if (alfa <= -tol_piv && (l[k] == -DBL_MAX || flag[j]))
+ { /* xN[j] is either free or has its upper bound active, so
+ * lambdaN[j] = d[j] <= 0 increases up to zero */
+ /* determine theta on which lambdaN[j] reaches zero */
+ teta = d[j] / alfa;
+ }
+ else
+ { /* lambdaN[j] cannot reach zero on increasing theta */
+ continue;
+ }
+ /* choose non-basic variable for which theta is not greater
+ * than theta_min determined for relaxed bounds and which has
+ * best (largest in magnitude) pivot */
+ alfa = (alfa >= 0.0 ? +alfa : -alfa);
+ if (teta <= teta_min && biga < alfa)
+ q = j, biga = alfa;
+ }
+ /* something must be chosen */
+ xassert(1 <= q && q <= n-m);
+done: return q;
+}
+
+#if 0 /* 23/III-2016 */
+/***********************************************************************
+* spy_eval_bp - determine dual objective function break-points
+*
+* This routine determines the dual objective function break-points.
+*
+* The parameters lp, d, r, trow, and tol_piv have the same meaning as
+* for the routine spx_chuzc_std (see above).
+*
+* On exit the routine stores the break-points determined to the array
+* elements bp[1], ..., bp[num], where 0 <= num <= n-m is the number of
+* break-points returned by the routine.
+*
+* The break-points stored in the array bp are ordered by ascending
+* the ray parameter teta >= 0. The break-points numbered 1, ..., num-1
+* always correspond to non-basic non-fixed variables xN[j] of primal
+* LP having both lower and upper bounds while the last break-point
+* numbered num may correspond to a non-basic variable having only one
+* lower or upper bound, if such variable prevents further increasing
+* of the ray parameter teta. Besides, the routine includes in the
+* array bp only the break-points that correspond to positive increment
+* of the dual objective. */
+
+static int CDECL fcmp(const void *v1, const void *v2)
+{ const SPYBP *p1 = v1, *p2 = v2;
+ if (p1->teta < p2->teta)
+ return -1;
+ else if (p1->teta > p2->teta)
+ return +1;
+ else
+ return 0;
+}
+
+int spy_eval_bp(SPXLP *lp, const double d[/*1+n-m*/],
+ double r, const double trow[/*1+n-m*/], double tol_piv,
+ SPYBP bp[/*1+n-m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int j, j_max, k, t, nnn, num;
+ double s, alfa, teta, teta_max, dz, v;
+ xassert(r != 0.0);
+ s = (r > 0.0 ? +1.0 : -1.0);
+ /* build the list of all dual basic variables lambdaN[j] that
+ * can reach zero on increasing the ray parameter teta >= 0 */
+ num = 0;
+ /* walk thru the list of non-basic variables */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ /* if xN[j] is fixed variable, skip it */
+ if (l[k] == u[k])
+ continue;
+ alfa = s * trow[j];
+ if (alfa >= +tol_piv && !flag[j])
+ { /* xN[j] is either free or has its lower bound active, so
+ * lambdaN[j] = d[j] >= 0 decreases down to zero */
+ /* determine teta[j] on which lambdaN[j] reaches zero */
+ teta = (d[j] < 0.0 ? 0.0 : d[j] / alfa);
+ }
+ else if (alfa <= -tol_piv && (l[k] == -DBL_MAX || flag[j]))
+ { /* xN[j] is either free or has its upper bound active, so
+ * lambdaN[j] = d[j] <= 0 increases up to zero */
+ /* determine teta[j] on which lambdaN[j] reaches zero */
+ teta = (d[j] > 0.0 ? 0.0 : d[j] / alfa);
+ }
+ else
+ { /* lambdaN[j] cannot reach zero on increasing teta */
+ continue;
+ }
+ /* add lambdaN[j] to the list */
+ num++;
+ bp[num].j = j;
+ bp[num].teta = teta;
+ }
+ if (num == 0)
+ { /* dual unboundedness */
+ goto done;
+ }
+ /* determine "blocking" dual basic variable lambdaN[j_max] that
+ * prevents increasing teta more than teta_max */
+ j_max = 0, teta_max = DBL_MAX;
+ for (t = 1; t <= num; t++)
+ { j = bp[t].j;
+ k = head[m+j]; /* x[k] = xN[j] */
+ if (l[k] == -DBL_MAX || u[k] == +DBL_MAX)
+ { /* lambdaN[j] cannot intersect zero */
+ if (j_max == 0
+ || teta_max > bp[t].teta
+ || (teta_max == bp[t].teta
+ && fabs(trow[j_max]) < fabs(trow[j])))
+ j_max = j, teta_max = bp[t].teta;
+ }
+ }
+ /* keep in the list only dual basic variables lambdaN[j] that
+ * correspond to primal double-bounded variables xN[j] and whose
+ * teta[j] is not greater than teta_max */
+ nnn = 0;
+ for (t = 1; t <= num; t++)
+ { j = bp[t].j;
+ k = head[m+j]; /* x[k] = xN[j] */
+ if (l[k] != -DBL_MAX && u[k] != +DBL_MAX
+ && bp[t].teta <= teta_max)
+ { nnn++;
+ bp[nnn].j = j;
+ bp[nnn].teta = bp[t].teta;
+ }
+ }
+ num = nnn;
+ /* sort break-points by ascending teta[j] */
+ qsort(&bp[1], num, sizeof(SPYBP), fcmp);
+ /* add lambdaN[j_max] to the end of the list */
+ if (j_max != 0)
+ { xassert(num < n-m);
+ num++;
+ bp[num].j = j_max;
+ bp[num].teta = teta_max;
+ }
+ /* compute increments of the dual objective at all break-points
+ * (relative to its value at teta = 0) */
+ dz = 0.0; /* dual objective increment */
+ v = fabs(r); /* dual objective slope d zeta / d teta */
+ for (t = 1; t <= num; t++)
+ { /* compute increment at current break-point */
+ dz += v * (bp[t].teta - (t == 1 ? 0.0 : bp[t-1].teta));
+ if (dz < 0.001)
+ { /* break-point with non-positive increment reached */
+ num = t - 1;
+ break;
+ }
+ bp[t].dz = dz;
+ /* compute next slope on the right to current break-point */
+ if (t < num)
+ { j = bp[t].j;
+ k = head[m+j]; /* x[k] = xN[j] */
+ xassert(-DBL_MAX < l[k] && l[k] < u[k] && u[k] < +DBL_MAX);
+ v -= fabs(trow[j]) * (u[k] - l[k]);
+ }
+ }
+done: return num;
+}
+#endif
+
+/***********************************************************************
+* spy_ls_eval_bp - determine dual objective function break-points
+*
+* This routine determines the dual objective function break-points.
+*
+* The parameters lp, d, r, trow, and tol_piv have the same meaning as
+* for the routine spx_chuzc_std (see above).
+*
+* The routine stores the break-points determined to the array elements
+* bp[1], ..., bp[nbp] in *arbitrary* order, where 0 <= nbp <= n-m is
+* the number of break-points returned by the routine on exit. */
+
+int spy_ls_eval_bp(SPXLP *lp, const double d[/*1+n-m*/],
+ double r, const double trow[/*1+n-m*/], double tol_piv,
+ SPYBP bp[/*1+n-m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int j, k, t, nnn, nbp;
+ double s, alfa, teta, teta_max;
+ xassert(r != 0.0);
+ s = (r > 0.0 ? +1.0 : -1.0);
+ /* build the list of all dual basic variables lambdaN[j] that
+ * can reach zero on increasing the ray parameter teta >= 0 */
+ nnn = 0, teta_max = DBL_MAX;
+ /* walk thru the list of non-basic variables */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ /* if xN[j] is fixed variable, skip it */
+ if (l[k] == u[k])
+ continue;
+ alfa = s * trow[j];
+ if (alfa >= +tol_piv && !flag[j])
+ { /* xN[j] is either free or has its lower bound active, so
+ * lambdaN[j] = d[j] >= 0 decreases down to zero */
+ /* determine teta[j] on which lambdaN[j] reaches zero */
+ teta = (d[j] < 0.0 ? 0.0 : d[j] / alfa);
+ /* if xN[j] has no upper bound, lambdaN[j] cannot become
+ * negative and thereby blocks further increasing teta */
+ if (u[k] == +DBL_MAX && teta_max > teta)
+ teta_max = teta;
+ }
+ else if (alfa <= -tol_piv && (l[k] == -DBL_MAX || flag[j]))
+ { /* xN[j] is either free or has its upper bound active, so
+ * lambdaN[j] = d[j] <= 0 increases up to zero */
+ /* determine teta[j] on which lambdaN[j] reaches zero */
+ teta = (d[j] > 0.0 ? 0.0 : d[j] / alfa);
+ /* if xN[j] has no lower bound, lambdaN[j] cannot become
+ * positive and thereby blocks further increasing teta */
+ if (l[k] == -DBL_MAX && teta_max > teta)
+ teta_max = teta;
+ }
+ else
+ { /* lambdaN[j] cannot reach zero on increasing teta */
+ continue;
+ }
+ /* add lambdaN[j] to the list */
+ nnn++;
+ bp[nnn].j = j;
+ bp[nnn].teta = teta;
+ }
+ /* remove from the list all dual basic variables lambdaN[j], for
+ * which teta[j] > teta_max */
+ nbp = 0;
+ for (t = 1; t <= nnn; t++)
+ { if (bp[t].teta <= teta_max + 1e-6)
+ { nbp++;
+ bp[nbp].j = bp[t].j;
+ bp[nbp].teta = bp[t].teta;
+ }
+ }
+ return nbp;
+}
+
+/***********************************************************************
+* spy_ls_select_bp - select and process dual objective break-points
+*
+* This routine selects a next portion of the dual objective function
+* break-points and processes them.
+*
+* On entry to the routine it is assumed that break-points bp[1], ...,
+* bp[num] are already processed, and slope is the dual objective slope
+* to the right of the last processed break-point bp[num]. (Initially,
+* when num = 0, slope should be specified as fabs(r), where r has the
+* same meaning as above.)
+*
+* The routine selects break-points among bp[num+1], ..., bp[nbp], for
+* which teta <= teta_lim, and moves these break-points to the array
+* elements bp[num+1], ..., bp[num1], where num <= num1 <= n-m is the
+* new number of processed break-points returned by the routine on
+* exit. Then the routine sorts these break-points by ascending teta
+* and computes the change of the dual objective function relative to
+* its value at teta = 0.
+*
+* On exit the routine also replaces the parameter slope with a new
+* value that corresponds to the new last break-point bp[num1]. */
+
+static int CDECL fcmp(const void *v1, const void *v2)
+{ const SPYBP *p1 = v1, *p2 = v2;
+ if (p1->teta < p2->teta)
+ return -1;
+ else if (p1->teta > p2->teta)
+ return +1;
+ else
+ return 0;
+}
+
+int spy_ls_select_bp(SPXLP *lp, const double trow[/*1+n-m*/],
+ int nbp, SPYBP bp[/*1+n-m*/], int num, double *slope, double
+ teta_lim)
+{ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ int j, k, t, num1;
+ double teta, dz;
+ xassert(0 <= num && num <= nbp && nbp <= n-m);
+ /* select a new portion of break-points */
+ num1 = num;
+ for (t = num+1; t <= nbp; t++)
+ { if (bp[t].teta <= teta_lim)
+ { /* move break-point to the beginning of the new portion */
+ num1++;
+ j = bp[num1].j, teta = bp[num1].teta;
+ bp[num1].j = bp[t].j, bp[num1].teta = bp[t].teta;
+ bp[t].j = j, bp[t].teta = teta;
+ }
+ }
+ /* sort new break-points bp[num+1], ..., bp[num1] by ascending
+ * the ray parameter teta */
+ if (num1 - num > 1)
+ qsort(&bp[num+1], num1 - num, sizeof(SPYBP), fcmp);
+ /* calculate the dual objective change at the new break-points */
+ for (t = num+1; t <= num1; t++)
+ { /* calculate the dual objective change relative to its value
+ * at break-point bp[t-1] */
+ if (*slope == -DBL_MAX)
+ dz = -DBL_MAX;
+ else
+ dz = (*slope) *
+ (bp[t].teta - (t == 1 ? 0.0 : bp[t-1].teta));
+ /* calculate the dual objective change relative to its value
+ * at teta = 0 */
+ if (dz == -DBL_MAX)
+ bp[t].dz = -DBL_MAX;
+ else
+ bp[t].dz = (t == 1 ? 0.0 : bp[t-1].dz) + dz;
+ /* calculate a new slope of the dual objective to the right of
+ * the current break-point bp[t] */
+ if (*slope != -DBL_MAX)
+ { j = bp[t].j;
+ k = head[m+j]; /* x[k] = xN[j] */
+ if (l[k] == -DBL_MAX || u[k] == +DBL_MAX)
+ *slope = -DBL_MAX; /* blocking break-point reached */
+ else
+ { xassert(l[k] < u[k]);
+ *slope -= fabs(trow[j]) * (u[k] - l[k]);
+ }
+ }
+ }
+ return num1;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spychuzc.h b/test/monniaux/glpk-4.65/src/simplex/spychuzc.h
new file mode 100644
index 00000000..8aa45a07
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spychuzc.h
@@ -0,0 +1,85 @@
+/* spychuzc.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015-2016 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/>.
+***********************************************************************/
+
+#ifndef SPYCHUZC_H
+#define SPYCHUZC_H
+
+#include "spxlp.h"
+
+#define spy_chuzc_std _glp_spy_chuzc_std
+int spy_chuzc_std(SPXLP *lp, const double d[/*1+n-m*/],
+#if 0 /* 14/III-2016 */
+ double s, const double trow[/*1+n-m*/], double tol_piv,
+#else
+ double r, const double trow[/*1+n-m*/], double tol_piv,
+#endif
+ double tol, double tol1);
+/* choose non-basic variable (dual textbook ratio test) */
+
+#define spy_chuzc_harris _glp_spy_chuzc_harris
+int spy_chuzc_harris(SPXLP *lp, const double d[/*1+n-m*/],
+#if 0 /* 14/III-2016 */
+ double s, const double trow[/*1+n-m*/], double tol_piv,
+#else
+ double r, const double trow[/*1+n-m*/], double tol_piv,
+#endif
+ double tol, double tol1);
+/* choose non-basic variable (dual Harris' ratio test) */
+
+typedef struct SPYBP SPYBP;
+
+struct SPYBP
+{ /* dual objective function break point */
+ int j;
+ /* dual basic variable lambdaN[j], 1 <= j <= n-m, that intersects
+ * zero at this break point */
+ double teta;
+ /* ray parameter value, teta[j] >= 0, at this break point */
+ double dz;
+ /* increment, zeta[j] - zeta[0], of the dual objective function
+ * at this break point */
+};
+
+#if 0 /* 23/III-2016 */
+#define spy_eval_bp _glp_spy_eval_bp
+int spy_eval_bp(SPXLP *lp, const double d[/*1+n-m*/],
+ double r, const double trow[/*1+n-m*/], double tol_piv,
+ SPYBP bp[/*1+n-m*/]);
+/* determine dual objective function break-points */
+#endif
+
+#define spy_ls_eval_bp _glp_spy_ls_eval_bp
+int spy_ls_eval_bp(SPXLP *lp, const double d[/*1+n-m*/],
+ double r, const double trow[/*1+n-m*/], double tol_piv,
+ SPYBP bp[/*1+n-m*/]);
+/* determine dual objective function break-points */
+
+#define spy_ls_select_bp _glp_spy_ls_select_bp
+int spy_ls_select_bp(SPXLP *lp, const double trow[/*1+n-m*/],
+ int nbp, SPYBP bp[/*1+n-m*/], int num, double *slope, double
+ teta_lim);
+/* select and process dual objective break-points */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spychuzr.c b/test/monniaux/glpk-4.65/src/simplex/spychuzr.c
new file mode 100644
index 00000000..63079c17
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spychuzr.c
@@ -0,0 +1,483 @@
+/* spychuzr.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#include "env.h"
+#include "spychuzr.h"
+
+/***********************************************************************
+* spy_chuzr_sel - select eligible basic variables
+*
+* This routine selects eligible basic variables xB[i], whose value
+* beta[i] violates corresponding lower lB[i] or upper uB[i] bound.
+* Positive bound violation rp[i] = lb[i] - beta[i] > 0 is the reduced
+* cost of non-basic dual variable lambda^+B[i] >= 0, so increasing it
+* increases the dual objective. Similarly, negative bound violation
+* rn[i] = ub[i] - beta[i] < 0 is the reduced cost of non-basic dual
+* variable lambda^-B[i] <= 0, so decreasing it also increases the dual
+* objective.
+*
+* Current values of basic variables should be placed in the array
+* locations beta[1], ..., beta[m].
+*
+* Basic variable xB[i] is considered eligible, if:
+*
+* beta[i] <= lB[i] - eps1[i], or
+*
+* beta[i] >= uB[i] + eps2[i],
+*
+* for
+*
+* eps1[i] = tol + tol1 * |lB[i]|,
+*
+* eps2[i] = tol + tol2 * |uB[i]|,
+*
+* where lB[i] and uB[i] are, resp., lower and upper bounds of xB[i],
+* tol and tol1 are specified tolerances.
+*
+* On exit the routine stores indices i of eligible basic variables
+* xB[i] to the array locations list[1], ..., list[num] and returns the
+* number of such variables 0 <= num <= m. (If the parameter list is
+* specified as NULL, no indices are stored.) */
+
+int spy_chuzr_sel(SPXLP *lp, const double beta[/*1+m*/], double tol,
+ double tol1, int list[/*1+m*/])
+{ int m = lp->m;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ int i, k, num;
+ double lk, uk, eps;
+ num = 0;
+ /* walk thru list of basic variables */
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ lk = l[k], uk = u[k];
+ /* check if xB[i] is eligible */
+ if (beta[i] < lk)
+ { /* determine absolute tolerance eps1[i] */
+ eps = tol + tol1 * (lk >= 0.0 ? +lk : -lk);
+ if (beta[i] < lk - eps)
+ { /* lower bound is violated */
+ num++;
+ if (list != NULL)
+ list[num] = i;
+ }
+ }
+ else if (beta[i] > uk)
+ { /* determine absolute tolerance eps2[i] */
+ eps = tol + tol1 * (uk >= 0.0 ? +uk : -uk);
+ if (beta[i] > uk + eps)
+ { /* upper bound is violated */
+ num++;
+ if (list != NULL)
+ list[num] = i;
+ }
+ }
+ }
+ return num;
+}
+
+/***********************************************************************
+* spy_chuzr_std - choose basic variable (dual Dantzig's rule)
+*
+* This routine chooses most eligible basic variable xB[p] according
+* to dual Dantzig's ("standard") rule:
+*
+* r[p] = max |r[i]|,
+* i in I
+*
+* ( lB[i] - beta[i], if beta[i] < lB[i]
+* (
+* r[i] = { 0, if lB[i] <= beta[i] <= uB[i]
+* (
+* ( uB[i] - beta[i], if beta[i] > uB[i]
+*
+* where I <= {1, ..., m} is the set of indices of eligible basic
+* variables, beta[i] is current value of xB[i], lB[i] and uB[i] are,
+* resp., lower and upper bounds of xB[i], r[i] is bound violation.
+*
+* Current values of basic variables should be placed in the array
+* locations beta[1], ..., beta[m].
+*
+* Indices of eligible basic variables i in I should be placed in the
+* array locations list[1], ..., list[num], where num = |J| > 0 is the
+* total number of such variables.
+*
+* On exit the routine returns p, the index of the basic variable xB[p]
+* chosen. */
+
+int spy_chuzr_std(SPXLP *lp, const double beta[/*1+m*/], int num,
+ const int list[])
+{ int m = lp->m;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ int i, k, p, t;
+ double abs_ri, abs_rp;
+ xassert(0 < num && num <= m);
+ p = 0, abs_rp = -1.0;
+ for (t = 1; t <= num; t++)
+ { i = list[t];
+ k = head[i]; /* x[k] = xB[i] */
+ if (beta[i] < l[k])
+ abs_ri = l[k] - beta[i];
+ else if (beta[i] > u[k])
+ abs_ri = beta[i] - u[k];
+ else
+ xassert(t != t);
+ if (abs_rp < abs_ri)
+ p = i, abs_rp = abs_ri;
+ }
+ xassert(p != 0);
+ return p;
+}
+
+/***********************************************************************
+* spy_alloc_se - allocate dual pricing data block
+*
+* This routine allocates the memory for arrays used in the dual
+* pricing data block. */
+
+void spy_alloc_se(SPXLP *lp, SPYSE *se)
+{ int m = lp->m;
+ int n = lp->n;
+#if 1 /* 30/III-2016 */
+ int i;
+#endif
+ se->valid = 0;
+ se->refsp = talloc(1+n, char);
+ se->gamma = talloc(1+m, double);
+ se->work = talloc(1+m, double);
+#if 1 /* 30/III-2016 */
+ se->u.n = m;
+ se->u.nnz = 0;
+ se->u.ind = talloc(1+m, int);
+ se->u.vec = talloc(1+m, double);
+ for (i = 1; i <= m; i++)
+ se->u.vec[i] = 0.0;
+#endif
+ return;
+}
+
+/***********************************************************************
+* spy_reset_refsp - reset dual reference space
+*
+* This routine resets (re-initializes) the dual reference space
+* composing it from dual variables which are non-basic (corresponding
+* to basic primal variables) in the current basis, and sets all
+* weights gamma[i] to 1. */
+
+void spy_reset_refsp(SPXLP *lp, SPYSE *se)
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ char *refsp = se->refsp;
+ double *gamma = se->gamma;
+ int i, k;
+ se->valid = 1;
+ memset(&refsp[1], 0, n * sizeof(char));
+ for (i = 1; i <= m; i++)
+ { k = head[i]; /* x[k] = xB[i] */
+ refsp[k] = 1;
+ gamma[i] = 1.0;
+ }
+ return;
+}
+
+/***********************************************************************
+* spy_eval_gamma_i - compute dual proj. steepest edge weight directly
+*
+* This routine computes dual projected steepest edge weight gamma[i],
+* 1 <= i <= m, for the current basis directly with the formula:
+*
+* n-m
+* gamma[i] = delta[i] + sum eta[j] * T[i,j]**2,
+* j=1
+*
+* where T[i,j] is element of the current simplex table, and
+*
+* ( 1, if lambdaN[j] is in the reference space
+* eta[j] = {
+* ( 0, otherwise
+*
+* ( 1, if lambdaB[i] is in the reference space
+* delta[i] = {
+* ( 0, otherwise
+*
+* Dual basic variable lambdaN[j] corresponds to primal non-basic
+* variable xN[j], and dual non-basic variable lambdaB[j] corresponds
+* to primal basic variable xB[i].
+*
+* NOTE: For testing/debugging only. */
+
+double spy_eval_gamma_i(SPXLP *lp, SPYSE *se, int i)
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ char *refsp = se->refsp;
+ double *rho = se->work;
+ int j, k;
+ double gamma_i, t_ij;
+ xassert(se->valid);
+ xassert(1 <= i && i <= m);
+ k = head[i]; /* x[k] = xB[i] */
+ gamma_i = (refsp[k] ? 1.0 : 0.0);
+ spx_eval_rho(lp, i, rho);
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ if (refsp[k])
+ { t_ij = spx_eval_tij(lp, rho, j);
+ gamma_i += t_ij * t_ij;
+ }
+ }
+ return gamma_i;
+}
+
+/***********************************************************************
+* spy_chuzr_pse - choose basic variable (dual projected steepest edge)
+*
+* This routine chooses most eligible basic variable xB[p] according
+* to the dual projected steepest edge method:
+*
+* r[p]**2 r[i]**2
+* -------- = max -------- ,
+* gamma[p] i in I gamma[i]
+*
+* ( lB[i] - beta[i], if beta[i] < lB[i]
+* (
+* r[i] = { 0, if lB[i] <= beta[i] <= uB[i]
+* (
+* ( uB[i] - beta[i], if beta[i] > uB[i]
+*
+* where I <= {1, ..., m} is the set of indices of eligible basic
+* variables, beta[i] is current value of xB[i], lB[i] and uB[i] are,
+* resp., lower and upper bounds of xB[i], r[i] is bound violation.
+*
+* Current values of basic variables should be placed in the array
+* locations beta[1], ..., beta[m].
+*
+* Indices of eligible basic variables i in I should be placed in the
+* array locations list[1], ..., list[num], where num = |J| > 0 is the
+* total number of such variables.
+*
+* On exit the routine returns p, the index of the basic variable xB[p]
+* chosen. */
+
+int spy_chuzr_pse(SPXLP *lp, SPYSE *se, const double beta[/*1+m*/],
+ int num, const int list[])
+{ int m = lp->m;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ double *gamma = se->gamma;
+ int i, k, p, t;
+ double best, ri, temp;
+ xassert(0 < num && num <= m);
+ p = 0, best = -1.0;
+ for (t = 1; t <= num; t++)
+ { i = list[t];
+ k = head[i]; /* x[k] = xB[i] */
+ if (beta[i] < l[k])
+ ri = l[k] - beta[i];
+ else if (beta[i] > u[k])
+ ri = u[k] - beta[i];
+ else
+ xassert(t != t);
+ /* FIXME */
+ if (gamma[i] < DBL_EPSILON)
+ temp = 0.0;
+ else
+ temp = (ri * ri) / gamma[i];
+ if (best < temp)
+ p = i, best = temp;
+ }
+ xassert(p != 0);
+ return p;
+}
+
+/***********************************************************************
+* spy_update_gamma - update dual proj. steepest edge weights exactly
+*
+* This routine updates the vector gamma = (gamma[i]) of dual projected
+* steepest edge weights exactly, for the adjacent basis.
+*
+* On entry to the routine the content of the se object should be valid
+* and should correspond to the current basis.
+*
+* The parameter 1 <= p <= m specifies basic variable xB[p] which
+* becomes non-basic variable xN[q] in the adjacent basis.
+*
+* The parameter 1 <= q <= n-m specified non-basic variable xN[q] which
+* becomes basic variable xB[p] in the adjacent basis.
+*
+* It is assumed that the array trow contains elements of p-th (pivot)
+* row T'[p] of the simplex table in locations trow[1], ..., trow[n-m].
+* It is also assumed that the array tcol contains elements of q-th
+* (pivot) column T[q] of the simple table in locations tcol[1], ...,
+* tcol[m]. (These row and column should be computed for the current
+* basis.)
+*
+* For details about the formulae used see the program documentation.
+*
+* The routine also computes the relative error:
+*
+* e = |gamma[p] - gamma'[p]| / (1 + |gamma[p]|),
+*
+* where gamma'[p] is the weight for lambdaB[p] (which is dual
+* non-basic variable corresponding to xB[p]) on entry to the routine,
+* and returns e on exit. (If e happens to be large enough, the calling
+* program may reset the reference space, since other weights also may
+* be inaccurate.) */
+
+double spy_update_gamma(SPXLP *lp, SPYSE *se, int p, int q,
+ const double trow[/*1+n-m*/], const double tcol[/*1+m*/])
+{ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ char *refsp = se->refsp;
+ double *gamma = se->gamma;
+ double *u = se->work;
+ int i, j, k, ptr, end;
+ double gamma_p, delta_p, e, r, t1, t2;
+ xassert(se->valid);
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n-m);
+ /* compute gamma[p] in current basis more accurately; also
+ * compute auxiliary vector u */
+ k = head[p]; /* x[k] = xB[p] */
+ gamma_p = delta_p = (refsp[k] ? 1.0 : 0.0);
+ for (i = 1; i <= m; i++)
+ u[i] = 0.0;
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ if (refsp[k] && trow[j] != 0.0)
+ { gamma_p += trow[j] * trow[j];
+ /* u := u + T[p,j] * N[j], where N[j] = A[k] is constraint
+ * matrix column corresponding to xN[j] */
+ ptr = lp->A_ptr[k];
+ end = lp->A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ u[lp->A_ind[ptr]] += trow[j] * lp->A_val[ptr];
+ }
+ }
+ bfd_ftran(lp->bfd, u);
+ /* compute relative error in gamma[p] */
+ e = fabs(gamma_p - gamma[p]) / (1.0 + gamma_p);
+ /* compute new gamma[p] */
+ gamma[p] = gamma_p / (tcol[p] * tcol[p]);
+ /* compute new gamma[i] for all i != p */
+ for (i = 1; i <= m; i++)
+ { if (i == p)
+ continue;
+ /* compute r[i] = T[i,q] / T[p,q] */
+ r = tcol[i] / tcol[p];
+ /* compute new gamma[i] */
+ t1 = gamma[i] + r * (r * gamma_p + u[i] + u[i]);
+ k = head[i]; /* x[k] = xB[i] */
+ t2 = (refsp[k] ? 1.0 : 0.0) + delta_p * r * r;
+ gamma[i] = (t1 >= t2 ? t1 : t2);
+ }
+ return e;
+}
+
+#if 1 /* 30/III-2016 */
+double spy_update_gamma_s(SPXLP *lp, SPYSE *se, int p, int q,
+ const FVS *trow, const FVS *tcol)
+{ /* sparse version of spy_update_gamma */
+ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ char *refsp = se->refsp;
+ double *gamma = se->gamma;
+ double *u = se->work;
+ int trow_nnz = trow->nnz;
+ int *trow_ind = trow->ind;
+ double *trow_vec = trow->vec;
+ int tcol_nnz = tcol->nnz;
+ int *tcol_ind = tcol->ind;
+ double *tcol_vec = tcol->vec;
+ int i, j, k, t, ptr, end;
+ double gamma_p, delta_p, e, r, t1, t2;
+ xassert(se->valid);
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n-m);
+ /* compute gamma[p] in current basis more accurately; also
+ * compute auxiliary vector u */
+ k = head[p]; /* x[k] = xB[p] */
+ gamma_p = delta_p = (refsp[k] ? 1.0 : 0.0);
+ for (i = 1; i <= m; i++)
+ u[i] = 0.0;
+ for (t = 1; t <= trow_nnz; t++)
+ { j = trow_ind[t];
+ k = head[m+j]; /* x[k] = xN[j] */
+ if (refsp[k])
+ { gamma_p += trow_vec[j] * trow_vec[j];
+ /* u := u + T[p,j] * N[j], where N[j] = A[k] is constraint
+ * matrix column corresponding to xN[j] */
+ ptr = lp->A_ptr[k];
+ end = lp->A_ptr[k+1];
+ for (; ptr < end; ptr++)
+ u[lp->A_ind[ptr]] += trow_vec[j] * lp->A_val[ptr];
+ }
+ }
+ bfd_ftran(lp->bfd, u);
+ /* compute relative error in gamma[p] */
+ e = fabs(gamma_p - gamma[p]) / (1.0 + gamma_p);
+ /* compute new gamma[p] */
+ gamma[p] = gamma_p / (tcol_vec[p] * tcol_vec[p]);
+ /* compute new gamma[i] for all i != p */
+ for (t = 1; t <= tcol_nnz; t++)
+ { i = tcol_ind[t];
+ if (i == p)
+ continue;
+ /* compute r[i] = T[i,q] / T[p,q] */
+ r = tcol_vec[i] / tcol_vec[p];
+ /* compute new gamma[i] */
+ t1 = gamma[i] + r * (r * gamma_p + u[i] + u[i]);
+ k = head[i]; /* x[k] = xB[i] */
+ t2 = (refsp[k] ? 1.0 : 0.0) + delta_p * r * r;
+ gamma[i] = (t1 >= t2 ? t1 : t2);
+ }
+ return e;
+}
+#endif
+
+/***********************************************************************
+* spy_free_se - deallocate dual pricing data block
+*
+* This routine deallocates the memory used for arrays in the dual
+* pricing data block. */
+
+void spy_free_se(SPXLP *lp, SPYSE *se)
+{ xassert(lp == lp);
+ tfree(se->refsp);
+ tfree(se->gamma);
+ tfree(se->work);
+#if 1 /* 30/III-2016 */
+ tfree(se->u.ind);
+ tfree(se->u.vec);
+#endif
+ return;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spychuzr.h b/test/monniaux/glpk-4.65/src/simplex/spychuzr.h
new file mode 100644
index 00000000..31f01b78
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spychuzr.h
@@ -0,0 +1,97 @@
+/* spychuzr.h */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015 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/>.
+***********************************************************************/
+
+#ifndef SPYCHUZR_H
+#define SPYCHUZR_H
+
+#include "spxlp.h"
+
+#define spy_chuzr_sel _glp_spy_chuzr_sel
+int spy_chuzr_sel(SPXLP *lp, const double beta[/*1+m*/], double tol,
+ double tol1, int list[/*1+m*/]);
+/* select eligible basic variables */
+
+#define spy_chuzr_std _glp_spy_chuzr_std
+int spy_chuzr_std(SPXLP *lp, const double beta[/*1+m*/], int num,
+ const int list[]);
+/* choose basic variable (dual Dantzig's rule) */
+
+typedef struct SPYSE SPYSE;
+
+struct SPYSE
+{ /* dual projected steepest edge and Devex pricing data block */
+ int valid;
+ /* content validity flag */
+ char *refsp; /* char refsp[1+n]; */
+ /* refsp[0] is not used;
+ * refsp[k], 1 <= k <= n, is the flag meaning that dual variable
+ * lambda[k] is in the dual reference space */
+ double *gamma; /* double gamma[1+m]; */
+ /* gamma[0] is not used;
+ * gamma[i], 1 <= i <= m, is the weight for reduced cost r[i]
+ * of dual non-basic variable lambdaB[j] in the current basis
+ * (r[i] is bound violation for basic variable xB[i]) */
+ double *work; /* double work[1+m]; */
+ /* working array */
+#if 1 /* 30/III-2016 */
+ FVS u; /* FVS u[1:m]; */
+ /* working vector */
+#endif
+};
+
+#define spy_alloc_se _glp_spy_alloc_se
+void spy_alloc_se(SPXLP *lp, SPYSE *se);
+/* allocate dual pricing data block */
+
+#define spy_reset_refsp _glp_spy_reset_refsp
+void spy_reset_refsp(SPXLP *lp, SPYSE *se);
+/* reset dual reference space */
+
+#define spy_eval_gamma_i _glp_spy_eval_gamma_i
+double spy_eval_gamma_i(SPXLP *lp, SPYSE *se, int i);
+/* compute dual projected steepest edge weight directly */
+
+#define spy_chuzr_pse _glp_spy_chuzr_pse
+int spy_chuzr_pse(SPXLP *lp, SPYSE *se, const double beta[/*1+m*/],
+ int num, const int list[]);
+/* choose basic variable (dual projected steepest edge) */
+
+#define spy_update_gamma _glp_spy_update_gamma
+double spy_update_gamma(SPXLP *lp, SPYSE *se, int p, int q,
+ const double trow[/*1+n-m*/], const double tcol[/*1+m*/]);
+/* update dual projected steepest edge weights exactly */
+
+#if 1 /* 30/III-2016 */
+#define spy_update_gamma_s _glp_spy_update_gamma_s
+double spy_update_gamma_s(SPXLP *lp, SPYSE *se, int p, int q,
+ const FVS *trow, const FVS *tcol);
+/* sparse version of spy_update_gamma */
+#endif
+
+#define spy_free_se _glp_spy_free_se
+void spy_free_se(SPXLP *lp, SPYSE *se);
+/* deallocate dual pricing data block */
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/simplex/spydual.c b/test/monniaux/glpk-4.65/src/simplex/spydual.c
new file mode 100644
index 00000000..89d98db9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/simplex/spydual.c
@@ -0,0 +1,2101 @@
+/* spydual.c */
+
+/***********************************************************************
+* This code is part of GLPK (GNU Linear Programming Kit).
+*
+* Copyright (C) 2015-2017 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/>.
+***********************************************************************/
+
+#if 1 /* 18/VII-2017 */
+#define SCALE_Z 1
+#endif
+
+#include "env.h"
+#include "simplex.h"
+#include "spxat.h"
+#include "spxnt.h"
+#include "spxprob.h"
+#include "spychuzc.h"
+#include "spychuzr.h"
+#if 0 /* 11/VI-2017 */
+#if 1 /* 29/III-2016 */
+#include "fvs.h"
+#endif
+#endif
+
+#define CHECK_ACCURACY 0
+/* (for debugging) */
+
+struct csa
+{ /* common storage area */
+ SPXLP *lp;
+ /* LP problem data and its (current) basis; this LP has m rows
+ * and n columns */
+ int dir;
+ /* original optimization direction:
+ * +1 - minimization
+ * -1 - maximization */
+#if SCALE_Z
+ double fz;
+ /* factor used to scale original objective */
+#endif
+ double *orig_b; /* double orig_b[1+m]; */
+ /* copy of original right-hand sides */
+ double *orig_c; /* double orig_c[1+n]; */
+ /* copy of original objective coefficients */
+ double *orig_l; /* double orig_l[1+n]; */
+ /* copy of original lower bounds */
+ double *orig_u; /* double orig_u[1+n]; */
+ /* copy of original upper bounds */
+ SPXAT *at;
+ /* mxn-matrix A of constraint coefficients, in sparse row-wise
+ * format (NULL if not used) */
+ SPXNT *nt;
+ /* mx(n-m)-matrix N composed of non-basic columns of constraint
+ * matrix A, in sparse row-wise format (NULL if not used) */
+ int phase;
+ /* search phase:
+ * 0 - not determined yet
+ * 1 - searching for dual feasible solution
+ * 2 - searching for optimal solution */
+ double *beta; /* double beta[1+m]; */
+ /* beta[i] is primal value of basic variable xB[i] */
+ int beta_st;
+ /* status of the vector beta:
+ * 0 - undefined
+ * 1 - just computed
+ * 2 - updated */
+ double *d; /* double d[1+n-m]; */
+ /* d[j] is reduced cost of non-basic variable xN[j] */
+ int d_st;
+ /* status of the vector d:
+ * 0 - undefined
+ * 1 - just computed
+ * 2 - updated */
+ SPYSE *se;
+ /* dual projected steepest edge and Devex pricing data block
+ * (NULL if not used) */
+#if 0 /* 30/III-2016 */
+ int num;
+ /* number of eligible basic variables */
+ int *list; /* int list[1+m]; */
+ /* list[1], ..., list[num] are indices i of eligible basic
+ * variables xB[i] */
+#else
+ FVS r; /* FVS r[1:m]; */
+ /* vector of primal infeasibilities */
+ /* r->nnz = num; r->ind = list */
+ /* vector r has the same status as vector beta (see above) */
+#endif
+ int p;
+ /* xB[p] is a basic variable chosen to leave the basis */
+#if 0 /* 29/III-2016 */
+ double *trow; /* double trow[1+n-m]; */
+#else
+ FVS trow; /* FVS trow[1:n-m]; */
+#endif
+ /* p-th (pivot) row of the simplex table */
+#if 1 /* 16/III-2016 */
+ SPYBP *bp; /* SPYBP bp[1+n-m]; */
+ /* dual objective break-points */
+#endif
+ int q;
+ /* xN[q] is a non-basic variable chosen to enter the basis */
+#if 0 /* 29/III-2016 */
+ double *tcol; /* double tcol[1+m]; */
+#else
+ FVS tcol; /* FVS tcol[1:m]; */
+#endif
+ /* q-th (pivot) column of the simplex table */
+ double *work; /* double work[1+m]; */
+ /* working array */
+ double *work1; /* double work1[1+n-m]; */
+ /* another working array */
+#if 0 /* 11/VI-2017 */
+#if 1 /* 31/III-2016 */
+ FVS wrow; /* FVS wrow[1:n-m]; */
+ FVS wcol; /* FVS wcol[1:m]; */
+ /* working sparse vectors */
+#endif
+#endif
+ int p_stat, d_stat;
+ /* primal and dual solution statuses */
+ /*--------------------------------------------------------------*/
+ /* control parameters (see struct glp_smcp) */
+ int msg_lev;
+ /* message level */
+ int dualp;
+ /* if this flag is set, report failure in case of instability */
+#if 0 /* 16/III-2016 */
+ int harris;
+ /* dual ratio test technique:
+ * 0 - textbook ratio test
+ * 1 - Harris' two pass ratio test */
+#else
+ int r_test;
+ /* dual ratio test technique:
+ * GLP_RT_STD - textbook ratio test
+ * GLP_RT_HAR - Harris' two pass ratio test
+ * GLP_RT_FLIP - long-step (flip-flop) ratio test */
+#endif
+ double tol_bnd, tol_bnd1;
+ /* primal feasibility tolerances */
+ double tol_dj, tol_dj1;
+ /* dual feasibility tolerances */
+ double tol_piv;
+ /* pivot tolerance */
+ double obj_lim;
+ /* objective limit */
+ int it_lim;
+ /* iteration limit */
+ int tm_lim;
+ /* time limit, milliseconds */
+ int out_frq;
+#if 0 /* 15/VII-2017 */
+ /* display output frequency, iterations */
+#else
+ /* display output frequency, milliseconds */
+#endif
+ int out_dly;
+ /* display output delay, milliseconds */
+ /*--------------------------------------------------------------*/
+ /* working parameters */
+ double tm_beg;
+ /* time value at the beginning of the search */
+ int it_beg;
+ /* simplex iteration count at the beginning of the search */
+ int it_cnt;
+ /* simplex iteration count; it increases by one every time the
+ * basis changes */
+ int it_dpy;
+ /* simplex iteration count at most recent display output */
+#if 1 /* 15/VII-2017 */
+ double tm_dpy;
+ /* time value at most recent display output */
+#endif
+ int inv_cnt;
+ /* basis factorization count since most recent display output */
+#if 1 /* 11/VII-2017 */
+ int degen;
+ /* count of successive degenerate iterations; this count is used
+ * to detect stalling */
+#endif
+#if 1 /* 23/III-2016 */
+ int ns_cnt, ls_cnt;
+ /* normal and long-step iteration count */
+#endif
+};
+
+/***********************************************************************
+* check_flags - check correctness of active bound flags
+*
+* This routine checks that flags specifying active bounds of all
+* non-basic variables are correct.
+*
+* NOTE: It is important to note that if bounds of variables have been
+* changed, active bound flags should be corrected accordingly. */
+
+static void check_flags(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ int j, k;
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ if (l[k] == -DBL_MAX && u[k] == +DBL_MAX)
+ xassert(!flag[j]);
+ else if (l[k] != -DBL_MAX && u[k] == +DBL_MAX)
+ xassert(!flag[j]);
+ else if (l[k] == -DBL_MAX && u[k] != +DBL_MAX)
+ xassert(flag[j]);
+ else if (l[k] == u[k])
+ xassert(!flag[j]);
+ }
+ return;
+}
+
+/***********************************************************************
+* set_art_bounds - set artificial right-hand sides and bounds
+*
+* This routine sets artificial right-hand sides and artificial bounds
+* for all variables to minimize the sum of dual infeasibilities on
+* phase I. Given current reduced costs d = (d[j]) this routine also
+* sets active artificial bounds of non-basic variables to provide dual
+* feasibility (this is always possible because all variables have both
+* lower and upper artificial bounds). */
+
+static void set_art_bounds(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *b = lp->b;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ double *d = csa->d;
+ int i, j, k;
+#if 1 /* 31/III-2016: FIXME */
+ /* set artificial right-hand sides */
+ for (i = 1; i <= m; i++)
+ b[i] = 0.0;
+ /* set artificial bounds depending on types of variables */
+ for (k = 1; k <= n; k++)
+ { if (csa->orig_l[k] == -DBL_MAX && csa->orig_u[k] == +DBL_MAX)
+ { /* force free variables to enter the basis */
+ l[k] = -1e3, u[k] = +1e3;
+ }
+ else if (csa->orig_l[k] != -DBL_MAX && csa->orig_u[k] == +DBL_MAX)
+ l[k] = 0.0, u[k] = +1.0;
+ else if (csa->orig_l[k] == -DBL_MAX && csa->orig_u[k] != +DBL_MAX)
+ l[k] = -1.0, u[k] = 0.0;
+ else
+ l[k] = u[k] = 0.0;
+ }
+#endif
+ /* set active artificial bounds for non-basic variables */
+ xassert(csa->d_st == 1);
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ flag[j] = (l[k] != u[k] && d[j] < 0.0);
+ }
+ /* invalidate values of basic variables, since active bounds of
+ * non-basic variables have been changed */
+ csa->beta_st = 0;
+ return;
+}
+
+/***********************************************************************
+* set_orig_bounds - restore original right-hand sides and bounds
+*
+* This routine restores original right-hand sides and original bounds
+* for all variables. This routine also sets active original bounds for
+* non-basic variables; for double-bounded non-basic variables current
+* reduced costs d = (d[j]) are used to decide which bound (lower or
+* upper) should be made active. */
+
+static void set_orig_bounds(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *b = lp->b;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ double *d = csa->d;
+ int j, k;
+ /* restore original right-hand sides */
+ memcpy(b, csa->orig_b, (1+m) * sizeof(double));
+ /* restore original bounds of all variables */
+ memcpy(l, csa->orig_l, (1+n) * sizeof(double));
+ memcpy(u, csa->orig_u, (1+n) * sizeof(double));
+ /* set active original bounds for non-basic variables */
+ xassert(csa->d_st == 1);
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ if (l[k] == -DBL_MAX && u[k] == +DBL_MAX)
+ flag[j] = 0;
+ else if (l[k] != -DBL_MAX && u[k] == +DBL_MAX)
+ flag[j] = 0;
+ else if (l[k] == -DBL_MAX && u[k] != +DBL_MAX)
+ flag[j] = 1;
+ else if (l[k] != u[k])
+ flag[j] = (d[j] < 0.0);
+ else
+ flag[j] = 0;
+ }
+ /* invalidate values of basic variables, since active bounds of
+ * non-basic variables have been changed */
+ csa->beta_st = 0;
+ return;
+}
+
+/***********************************************************************
+* check_feas - check dual feasibility of basic solution
+*
+* This routine checks that reduced costs of all non-basic variables
+* d = (d[j]) have correct signs.
+*
+* Reduced cost d[j] is considered as having correct sign within the
+* specified tolerance depending on status of non-basic variable xN[j]
+* if one of the following conditions is met:
+*
+* xN[j] is free -eps <= d[j] <= +eps
+*
+* xN[j] has its lower bound active d[j] >= -eps
+*
+* xN[j] has its upper bound active d[j] <= +eps
+*
+* xN[j] is fixed d[j] has any value
+*
+* where eps = tol + tol1 * |cN[j]|, cN[j] is the objective coefficient
+* at xN[j]. (See also the routine spx_chuzc_sel.)
+*
+* The flag recov allows the routine to recover dual feasibility by
+* changing active bounds of non-basic variables. (For example, if
+* xN[j] has its lower bound active and d[j] < -eps, the feasibility
+* can be recovered by making xN[j] active on its upper bound.)
+*
+* If the basic solution is dual feasible, the routine returns zero.
+* If the basic solution is dual infeasible, but its dual feasibility
+* can be recovered (or has been recovered, if the flag recov is set),
+* the routine returns a negative value. Otherwise, the routine returns
+* the number j of some non-basic variable xN[j], whose reduced cost
+* d[j] is dual infeasible and cannot be recovered. */
+
+static int check_feas(struct csa *csa, double tol, double tol1,
+ int recov)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ double *d = csa->d;
+ int j, k, ret = 0;
+ double eps;
+ /* reduced costs should be just computed */
+ xassert(csa->d_st == 1);
+ /* walk thru list of non-basic variables */
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ if (l[k] == u[k])
+ { /* xN[j] is fixed variable; skip it */
+ continue;
+ }
+ /* determine absolute tolerance eps[j] */
+ eps = tol + tol1 * (c[k] >= 0.0 ? +c[k] : -c[k]);
+ /* check dual feasibility of xN[j] */
+ if (d[j] > +eps)
+ { /* xN[j] should have its lower bound active */
+ if (l[k] == -DBL_MAX || flag[j])
+ { /* but it either has no lower bound or its lower bound
+ * is inactive */
+ if (l[k] == -DBL_MAX)
+ { /* cannot recover, since xN[j] has no lower bound */
+ ret = j;
+ break;
+ }
+ /* recovering is possible */
+ if (recov)
+ flag[j] = 0;
+ ret = -1;
+ }
+ }
+ else if (d[j] < -eps)
+ { /* xN[j] should have its upper bound active */
+ if (!flag[j])
+ { /* but it either has no upper bound or its upper bound
+ * is inactive */
+ if (u[k] == +DBL_MAX)
+ { /* cannot recover, since xN[j] has no upper bound */
+ ret = j;
+ break;
+ }
+ /* recovering is possible */
+ if (recov)
+ flag[j] = 1;
+ ret = -1;
+ }
+ }
+ }
+ if (recov && ret)
+ { /* invalidate values of basic variables, since active bounds
+ * of non-basic variables have been changed */
+ csa->beta_st = 0;
+ }
+ return ret;
+}
+
+#if CHECK_ACCURACY
+/***********************************************************************
+* err_in_vec - compute maximal relative error between two vectors
+*
+* This routine computes and returns maximal relative error between
+* n-vectors x and y:
+*
+* err_max = max |x[i] - y[i]| / (1 + |x[i]|).
+*
+* NOTE: This routine is intended only for debugging purposes. */
+
+static double err_in_vec(int n, const double x[], const double y[])
+{ int i;
+ double err, err_max;
+ err_max = 0.0;
+ for (i = 1; i <= n; i++)
+ { err = fabs(x[i] - y[i]) / (1.0 + fabs(x[i]));
+ if (err_max < err)
+ err_max = err;
+ }
+ return err_max;
+}
+#endif
+
+#if CHECK_ACCURACY
+/***********************************************************************
+* err_in_beta - compute maximal relative error in vector beta
+*
+* This routine computes and returns maximal relative error in vector
+* of values of basic variables beta = (beta[i]).
+*
+* NOTE: This routine is intended only for debugging purposes. */
+
+static double err_in_beta(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ double err, *beta;
+ beta = talloc(1+m, double);
+ spx_eval_beta(lp, beta);
+ err = err_in_vec(m, beta, csa->beta);
+ tfree(beta);
+ return err;
+}
+#endif
+
+#if CHECK_ACCURACY
+static double err_in_r(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int i, k;
+ double err, *r;
+ r = talloc(1+m, double);
+ for (i = 1; i <= m; i++)
+ { k = lp->head[i];
+ if (csa->beta[i] < lp->l[k])
+ r[i] = lp->l[k] - csa->beta[i];
+ else if (csa->beta[i] > lp->u[k])
+ r[i] = lp->u[k] - csa->beta[i];
+ else
+ r[i] = 0.0;
+
+if (fabs(r[i] - csa->r.vec[i]) > 1e-6)
+printf("i = %d; r = %g; csa->r = %g\n", i, r[i], csa->r.vec[i]);
+
+
+ }
+ err = err_in_vec(m, r, csa->r.vec);
+ tfree(r);
+ return err;
+}
+#endif
+
+#if CHECK_ACCURACY
+/***********************************************************************
+* err_in_d - compute maximal relative error in vector d
+*
+* This routine computes and returns maximal relative error in vector
+* of reduced costs of non-basic variables d = (d[j]).
+*
+* NOTE: This routine is intended only for debugging purposes. */
+
+static double err_in_d(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ int j;
+ double err, *pi, *d;
+ pi = talloc(1+m, double);
+ d = talloc(1+n-m, double);
+ spx_eval_pi(lp, pi);
+ for (j = 1; j <= n-m; j++)
+ d[j] = spx_eval_dj(lp, pi, j);
+ err = err_in_vec(n-m, d, csa->d);
+ tfree(pi);
+ tfree(d);
+ return err;
+}
+#endif
+
+#if CHECK_ACCURACY
+/***********************************************************************
+* err_in_gamma - compute maximal relative error in vector gamma
+*
+* This routine computes and returns maximal relative error in vector
+* of projected steepest edge weights gamma = (gamma[j]).
+*
+* NOTE: This routine is intended only for debugging purposes. */
+
+static double err_in_gamma(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ SPYSE *se = csa->se;
+ int i;
+ double err, *gamma;
+ xassert(se != NULL);
+gamma = talloc(1+m, double);
+ for (i = 1; i <= m; i++)
+ gamma[i] = spy_eval_gamma_i(lp, se, i);
+ err = err_in_vec(m, gamma, se->gamma);
+ tfree(gamma);
+ return err;
+}
+#endif
+
+#if CHECK_ACCURACY
+/***********************************************************************
+* check_accuracy - check accuracy of basic solution components
+*
+* This routine checks accuracy of current basic solution components.
+*
+* NOTE: This routine is intended only for debugging purposes. */
+
+static void check_accuracy(struct csa *csa)
+{ double e_beta, e_r, e_d, e_gamma;
+ e_beta = err_in_beta(csa);
+ e_r = err_in_r(csa);
+ e_d = err_in_d(csa);
+ if (csa->se == NULL)
+ e_gamma = 0.;
+ else
+ e_gamma = err_in_gamma(csa);
+ xprintf("e_beta = %10.3e; e_r = %10.3e; e_d = %10.3e; e_gamma = %"
+ "10.3e\n", e_beta, e_r, e_d, e_gamma);
+ xassert(e_beta <= 1e-5 && e_d <= 1e-5 && e_gamma <= 1e-3);
+ return;
+}
+#endif
+
+#if 1 /* 30/III-2016 */
+static
+void spy_eval_r(SPXLP *lp, const double beta[/*1+m*/], double tol,
+ double tol1, FVS *r)
+{ /* this routine computes the vector of primal infeasibilities:
+ *
+ * ( lB[i] - beta[i] > 0, if beta[i] < lb[i]
+ * r[i] = { 0, if lb[i] <= beta[i] <= ub[i]
+ * ( ub[i] - beta[i] < 0, if beta[i] > ub[i]
+ *
+ * (this routine replaces spy_chuzr_sel) */
+ int m = lp->m;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ int *ind = r->ind;
+ double *vec = r->vec;
+ int i, k, nnz = 0;
+ double lk, uk, eps;
+ xassert(r->n == m);
+ /* walk thru the list of basic variables */
+ for (i = 1; i <= m; i++)
+ { vec[i] = 0.0;
+ k = head[i]; /* x[k] = xB[i] */
+ lk = l[k], uk = u[k];
+ /* check primal feasibility */
+ if (beta[i] < lk)
+ { /* determine absolute tolerance eps1[i] */
+ eps = tol + tol1 * (lk >= 0.0 ? +lk : -lk);
+ if (beta[i] < lk - eps)
+ { /* lower bound is violated */
+ ind[++nnz] = i;
+ vec[i] = lk - beta[i];
+ }
+ }
+ else if (beta[i] > uk)
+ { /* determine absolute tolerance eps2[i] */
+ eps = tol + tol1 * (uk >= 0.0 ? +uk : -uk);
+ if (beta[i] > uk + eps)
+ { /* upper bound is violated */
+ ind[++nnz] = i;
+ vec[i] = uk - beta[i];
+ }
+ }
+ }
+ r->nnz = nnz;
+ return;
+}
+#endif
+
+/***********************************************************************
+* choose_pivot - choose xB[p] and xN[q]
+*
+* Given the list of eligible basic variables this routine first
+* chooses basic variable xB[p]. This choice is always possible,
+* because the list is assumed to be non-empty. Then the routine
+* computes p-th row T[p,*] of the simplex table T[i,j] and chooses
+* non-basic variable xN[q]. If the pivot T[p,q] is small in magnitude,
+* the routine attempts to choose another xB[p] and xN[q] in order to
+* avoid badly conditioned adjacent bases.
+*
+* If the normal choice was made, the routine returns zero. Otherwise,
+* if the long-step choice was made, the routine returns non-zero. */
+
+#ifdef TIMING /* 31/III-2016 */
+
+#include "choose_pivot.c"
+
+#else
+
+#define MIN_RATIO 0.0001
+
+static int choose_pivot(struct csa *csa)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ SPXAT *at = csa->at;
+ SPXNT *nt = csa->nt;
+ double *beta = csa->beta;
+ double *d = csa->d;
+ SPYSE *se = csa->se;
+#if 0 /* 30/III-2016 */
+ int *list = csa->list;
+#else
+ int *list = csa->r.ind;
+#endif
+ double *rho = csa->work;
+ double *trow = csa->work1;
+ SPYBP *bp = csa->bp;
+ double tol_piv = csa->tol_piv;
+ int try, nnn, j, k, p, q, t, t_best, nbp, ret;
+ double big, temp, r, best_ratio, dz_best;
+ xassert(csa->beta_st);
+ xassert(csa->d_st);
+more: /* initial number of eligible basic variables */
+#if 0 /* 30/III-2016 */
+ nnn = csa->num;
+#else
+ nnn = csa->r.nnz;
+#endif
+ /* nothing has been chosen so far */
+ csa->p = 0;
+ best_ratio = 0.0;
+ try = ret = 0;
+try: /* choose basic variable xB[p] */
+ xassert(nnn > 0);
+ try++;
+ if (se == NULL)
+ { /* dual Dantzig's rule */
+ p = spy_chuzr_std(lp, beta, nnn, list);
+ }
+ else
+ { /* dual projected steepest edge */
+ p = spy_chuzr_pse(lp, se, beta, nnn, list);
+ }
+ xassert(1 <= p && p <= m);
+ /* compute p-th row of inv(B) */
+ spx_eval_rho(lp, p, rho);
+ /* compute p-th row of the simplex table */
+ if (at != NULL)
+ spx_eval_trow1(lp, at, rho, trow);
+ else
+ spx_nt_prod(lp, nt, trow, 1, -1.0, rho);
+#if 1 /* 23/III-2016 */
+ /* big := max(1, |trow[1]|, ..., |trow[n-m]|) */
+ big = 1.0;
+ for (j = 1; j <= n-m; j++)
+ { temp = trow[j];
+ if (temp < 0.0)
+ temp = - temp;
+ if (big < temp)
+ big = temp;
+ }
+#else
+ /* this still puzzles me */
+ big = 1.0;
+#endif
+ /* choose non-basic variable xN[q] */
+ k = head[p]; /* x[k] = xB[p] */
+ xassert(beta[p] < l[k] || beta[p] > u[k]);
+ r = beta[p] < l[k] ? l[k] - beta[p] : u[k] - beta[p];
+ if (csa->r_test == GLP_RT_FLIP && try <= 2)
+ { /* long-step ratio test */
+#if 0 /* 23/III-2016 */
+ /* determine dual objective break-points */
+ nbp = spy_eval_bp(lp, d, r, trow, tol_piv, bp);
+ if (nbp <= 1)
+ goto skip;
+ /* choose appropriate break-point */
+ t_best = 0, dz_best = -DBL_MAX;
+ for (t = 1; t <= nbp; t++)
+ { if (fabs(trow[bp[t].j]) / big >= MIN_RATIO)
+ { if (dz_best < bp[t].dz)
+ t_best = t, dz_best = bp[t].dz;
+ }
+ }
+ if (t_best == 0)
+ goto skip;
+#else
+ int t, num, num1;
+ double slope, teta_lim;
+ /* determine dual objective break-points */
+ nbp = spy_ls_eval_bp(lp, d, r, trow, tol_piv, bp);
+ if (nbp < 2)
+ goto skip;
+ /* set initial slope */
+ slope = fabs(r);
+ /* estimate initial teta_lim */
+ teta_lim = DBL_MAX;
+ for (t = 1; t <= nbp; t++)
+ { if (teta_lim > bp[t].teta)
+ teta_lim = bp[t].teta;
+ }
+ xassert(teta_lim >= 0.0);
+ if (teta_lim < 1e-6)
+ teta_lim = 1e-6;
+ /* nothing has been chosen so far */
+ t_best = 0, dz_best = 0.0, num = 0;
+ /* choose appropriate break-point */
+ while (num < nbp)
+ { /* select and process a new portion of break-points */
+ num1 = spy_ls_select_bp(lp, trow, nbp, bp, num, &slope,
+ teta_lim);
+ for (t = num+1; t <= num1; t++)
+ { if (fabs(trow[bp[t].j]) / big >= MIN_RATIO)
+ { if (dz_best < bp[t].dz)
+ t_best = t, dz_best = bp[t].dz;
+ }
+ }
+ if (slope < 0.0)
+ { /* the dual objective starts decreasing */
+ break;
+ }
+ /* the dual objective continues increasing */
+ num = num1;
+ teta_lim += teta_lim;
+ }
+ if (dz_best == 0.0)
+ goto skip;
+ xassert(1 <= t_best && t_best <= num1);
+#endif
+ /* the choice has been made */
+ csa->p = p;
+#if 0 /* 29/III-2016 */
+ memcpy(&csa->trow[1], &trow[1], (n-m) * sizeof(double));
+#else
+ memcpy(&csa->trow.vec[1], &trow[1], (n-m) * sizeof(double));
+ fvs_gather_vec(&csa->trow, DBL_EPSILON);
+#endif
+ csa->q = bp[t_best].j;
+ best_ratio = fabs(trow[bp[t_best].j]) / big;
+#if 0
+ xprintf("num = %d; t_best = %d; dz = %g\n", num, t_best,
+ bp[t_best].dz);
+#endif
+ ret = 1;
+ goto done;
+skip: ;
+ }
+ if (csa->r_test == GLP_RT_STD)
+ { /* textbook dual ratio test */
+ q = spy_chuzc_std(lp, d, r, trow, tol_piv,
+ .30 * csa->tol_dj, .30 * csa->tol_dj1);
+ }
+ else
+ { /* Harris' two-pass dual ratio test */
+ q = spy_chuzc_harris(lp, d, r, trow, tol_piv,
+ .35 * csa->tol_dj, .35 * csa->tol_dj1);
+ }
+ if (q == 0)
+ { /* dual unboundedness */
+ csa->p = p;
+#if 0 /* 29/III-2016 */
+ memcpy(&csa->trow[1], &trow[1], (n-m) * sizeof(double));
+#else
+ memcpy(&csa->trow.vec[1], &trow[1], (n-m) * sizeof(double));
+ fvs_gather_vec(&csa->trow, DBL_EPSILON);
+#endif
+ csa->q = q;
+ best_ratio = 1.0;
+ goto done;
+ }
+ /* either keep previous choice or accept new choice depending on
+ * which one is better */
+ if (best_ratio < fabs(trow[q]) / big)
+ { csa->p = p;
+#if 0 /* 29/III-2016 */
+ memcpy(&csa->trow[1], &trow[1], (n-m) * sizeof(double));
+#else
+ memcpy(&csa->trow.vec[1], &trow[1], (n-m) * sizeof(double));
+ fvs_gather_vec(&csa->trow, DBL_EPSILON);
+#endif
+ csa->q = q;
+ best_ratio = fabs(trow[q]) / big;
+ }
+ /* check if the current choice is acceptable */
+ if (best_ratio >= MIN_RATIO || nnn == 1 || try == 5)
+ goto done;
+ /* try to choose other xB[p] and xN[q] */
+ /* find xB[p] in the list */
+ for (t = 1; t <= nnn; t++)
+ if (list[t] == p) break;
+ xassert(t <= nnn);
+ /* move xB[p] to the end of the list */
+ list[t] = list[nnn], list[nnn] = p;
+ /* and exclude it from consideration */
+ nnn--;
+ /* repeat the choice */
+ goto try;
+done: /* the choice has been made */
+#if 1 /* FIXME: currently just to avoid badly conditioned basis */
+ if (best_ratio < .001 * MIN_RATIO)
+ { /* looks like this helps */
+ if (bfd_get_count(lp->bfd) > 0)
+ return -1;
+ /* didn't help; last chance to improve the choice */
+ if (tol_piv == csa->tol_piv)
+ { tol_piv *= 1000.;
+ goto more;
+ }
+ }
+#endif
+#if 1 /* FIXME */
+ if (ret)
+ { /* invalidate basic solution components */
+#if 0 /* 28/III-2016 */
+ csa->beta_st = csa->d_st = 0;
+#else
+ /* dual solution remains valid */
+ csa->beta_st = 0;
+#endif
+ /* set double-bounded non-basic variables to opposite bounds
+ * for all break-points preceding the chosen one */
+ for (t = 1; t < t_best; t++)
+ { k = head[m + bp[t].j];
+ xassert(-DBL_MAX < l[k] && l[k] < u[k] && u[k] < +DBL_MAX);
+ lp->flag[bp[t].j] = !(lp->flag[bp[t].j]);
+ }
+ }
+#endif
+ return ret;
+}
+
+#endif
+
+/***********************************************************************
+* play_coef - play objective coefficients
+*
+* This routine is called after the reduced costs d[j] was updated and
+* the basis was changed to the adjacent one.
+*
+* It is assumed that before updating all the reduced costs d[j] were
+* strongly feasible, so in the adjacent basis d[j] remain feasible
+* within a tolerance, i.e. if some d[j] violates its zero bound, the
+* violation is insignificant.
+*
+* If some d[j] violates its zero bound, the routine changes (perturbs)
+* objective coefficient cN[j] to provide d[j] = 0, i.e. to make all
+* d[j] strongly feasible. Otherwise, if d[j] has a feasible value, the
+* routine attempts to reduce (or remove) perturbation in cN[j] by
+* shifting d[j] to its zero bound keeping strong feasibility. */
+
+static void play_coef(struct csa *csa, int all)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *c = lp->c;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ double *orig_c = csa->orig_c;
+ double *d = csa->d;
+ const double *trow = csa->trow.vec;
+ /* this vector was used to update d = (d[j]) */
+ int j, k;
+ static const double eps = 1e-9;
+ /* reduced costs d = (d[j]) should be valid */
+ xassert(csa->d_st);
+ /* walk thru the list of non-basic variables xN = (xN[j]) */
+ for (j = 1; j <= n-m; j++)
+ { if (all || trow[j] != 0.0)
+ { /* d[j] has changed in the adjacent basis */
+ k = head[m+j]; /* x[k] = xN[j] */
+ if (l[k] == u[k])
+ { /* xN[j] is fixed variable */
+ /* d[j] may have any sign */
+ }
+ else if (l[k] == -DBL_MAX && u[k] == +DBL_MAX)
+ { /* xN[j] is free (unbounded) variable */
+ /* strong feasibility means d[j] = 0 */
+ c[k] -= d[j], d[j] = 0.0;
+ /* in this case dual degeneracy is not critical, since
+ * if xN[j] enters the basis, it never leaves it */
+ }
+ else if (!flag[j])
+ { /* xN[j] has its lower bound active */
+ xassert(l[k] != -DBL_MAX);
+ /* first, we remove current perturbation to provide
+ * c[k] = orig_c[k] */
+ d[j] -= c[k] - orig_c[k], c[k] = orig_c[k];
+ /* strong feasibility means d[j] >= 0, but we provide
+ * d[j] >= +eps to prevent dual degeneracy */
+ if (d[j] < +eps)
+ c[k] -= d[j] - eps, d[j] = +eps;
+ }
+ else
+ { /* xN[j] has its upper bound active */
+ xassert(u[k] != +DBL_MAX);
+ /* similarly, we remove current perturbation to provide
+ * c[k] = orig_c[k] */
+ d[j] -= c[k] - orig_c[k], c[k] = orig_c[k];
+ /* strong feasibility means d[j] <= 0, but we provide
+ * d[j] <= -eps to prevent dual degeneracy */
+ if (d[j] > -eps)
+ c[k] -= d[j] + eps, d[j] = -eps;
+ }
+ }
+ }
+ return;
+}
+
+#if 1 /* 11/VII-2017 */
+static void remove_perturb(struct csa *csa)
+{ /* remove perturbation */
+ SPXLP *lp = csa->lp;
+ int n = lp->n;
+ double *c = lp->c;
+ double *orig_c = csa->orig_c;
+ memcpy(c, orig_c, (1+n) * sizeof(double));
+ /* removing perturbation changes dual solution components */
+ csa->phase = csa->d_st = 0;
+#if 1
+ if (csa->msg_lev >= GLP_MSG_ALL)
+ xprintf("Removing LP perturbation [%d]...\n",
+ csa->it_cnt);
+#endif
+ return;
+}
+#endif
+
+/***********************************************************************
+* display - display search progress
+*
+* This routine displays some information about the search progress
+* that includes:
+*
+* search phase;
+*
+* number of simplex iterations performed by the solver;
+*
+* original objective value (only on phase II);
+*
+* sum of (scaled) dual infeasibilities for original bounds;
+*
+* number of dual infeasibilities (phase I) or primal infeasibilities
+* (phase II);
+*
+* number of basic factorizations since last display output. */
+
+static void display(struct csa *csa, int spec)
+{ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ int *head = lp->head;
+ char *flag = lp->flag;
+ double *l = csa->orig_l; /* original lower bounds */
+ double *u = csa->orig_u; /* original upper bounds */
+ double *beta = csa->beta;
+ double *d = csa->d;
+ int j, k, nnn;
+ double sum;
+#if 1 /* 15/VII-2017 */
+ double tm_cur;
+#endif
+ /* check if the display output should be skipped */
+ if (csa->msg_lev < GLP_MSG_ON) goto skip;
+#if 1 /* 15/VII-2017 */
+ tm_cur = xtime();
+#endif
+ if (csa->out_dly > 0 &&
+#if 0 /* 15/VII-2017 */
+ 1000.0 * xdifftime(xtime(), csa->tm_beg) < csa->out_dly)
+#else
+ 1000.0 * xdifftime(tm_cur, csa->tm_beg) < csa->out_dly)
+#endif
+ goto skip;
+ if (csa->it_cnt == csa->it_dpy) goto skip;
+#if 0 /* 15/VII-2017 */
+ if (!spec && csa->it_cnt % csa->out_frq != 0) goto skip;
+#else
+ if (!spec &&
+ 1000.0 * xdifftime(tm_cur, csa->tm_dpy) < csa->out_frq)
+ goto skip;
+#endif
+ /* display search progress depending on search phase */
+ switch (csa->phase)
+ { case 1:
+ /* compute sum and number of (scaled) dual infeasibilities
+ * for original bounds */
+ sum = 0.0, nnn = 0;
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ if (d[j] > 0.0)
+ { /* xN[j] should have lower bound */
+ if (l[k] == -DBL_MAX)
+ { sum += d[j];
+ if (d[j] > +1e-7)
+ nnn++;
+ }
+ }
+ else if (d[j] < 0.0)
+ { /* xN[j] should have upper bound */
+ if (u[k] == +DBL_MAX)
+ { sum -= d[j];
+ if (d[j] < -1e-7)
+ nnn++;
+ }
+ }
+ }
+ /* on phase I variables have artificial bounds which are
+ * meaningless for original LP, so corresponding objective
+ * function value is also meaningless */
+#if 0 /* 27/III-2016 */
+ xprintf(" %6d: %23s inf = %11.3e (%d)",
+ csa->it_cnt, "", sum, nnn);
+#else
+ xprintf(" %6d: sum = %17.9e inf = %11.3e (%d)",
+ csa->it_cnt, lp->c[0] - spx_eval_obj(lp, beta),
+ sum, nnn);
+#endif
+ break;
+ case 2:
+ /* compute sum of (scaled) dual infeasibilities */
+ sum = 0.0, nnn = 0;
+ for (j = 1; j <= n-m; j++)
+ { k = head[m+j]; /* x[k] = xN[j] */
+ if (d[j] > 0.0)
+ { /* xN[j] should have its lower bound active */
+ if (l[k] == -DBL_MAX || flag[j])
+ sum += d[j];
+ }
+ else if (d[j] < 0.0)
+ { /* xN[j] should have its upper bound active */
+ if (l[k] != u[k] && !flag[j])
+ sum -= d[j];
+ }
+ }
+ /* compute number of primal infeasibilities */
+ nnn = spy_chuzr_sel(lp, beta, csa->tol_bnd, csa->tol_bnd1,
+ NULL);
+ xprintf("#%6d: obj = %17.9e inf = %11.3e (%d)",
+#if SCALE_Z
+ csa->it_cnt,
+ (double)csa->dir * csa->fz * spx_eval_obj(lp, beta),
+#else
+ csa->it_cnt, (double)csa->dir * spx_eval_obj(lp, beta),
+#endif
+ sum, nnn);
+ break;
+ default:
+ xassert(csa != csa);
+ }
+ if (csa->inv_cnt)
+ { /* number of basis factorizations performed */
+ xprintf(" %d", csa->inv_cnt);
+ csa->inv_cnt = 0;
+ }
+#if 1 /* 23/III-2016 */
+ if (csa->r_test == GLP_RT_FLIP)
+ { /*xprintf(" %d,%d", csa->ns_cnt, csa->ls_cnt);*/
+ if (csa->ns_cnt + csa->ls_cnt)
+ xprintf(" %d%%",
+ (100 * csa->ls_cnt) / (csa->ns_cnt + csa->ls_cnt));
+ csa->ns_cnt = csa->ls_cnt = 0;
+ }
+#endif
+ xprintf("\n");
+ csa->it_dpy = csa->it_cnt;
+#if 1 /* 15/VII-2017 */
+ csa->tm_dpy = tm_cur;
+#endif
+skip: return;
+}
+
+#if 1 /* 31/III-2016 */
+static
+void spy_update_r(SPXLP *lp, int p, int q, const double beta[/*1+m*/],
+ const FVS *tcol, double tol, double tol1, FVS *r)
+{ /* update vector r of primal infeasibilities */
+ /* it is assumed that xB[p] leaves the basis, xN[q] enters the
+ * basis, and beta corresponds to the adjacent basis (i.e. this
+ * routine should be called after spx_update_beta) */
+ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ int *tcol_ind = tcol->ind;
+ int *ind = r->ind;
+ double *vec = r->vec;
+ int i, k, t, nnz;
+ double lk, uk, ri, eps;
+ xassert(1 <= p && p <= m);
+ xassert(1 <= q && q <= n-m);
+ nnz = r->nnz;
+ for (t = tcol->nnz; t >= 1; t--)
+ { i = tcol_ind[t];
+ /* xB[i] changes in the adjacent basis to beta[i], so only
+ * r[i] should be updated */
+ if (i == p)
+ k = head[m+q]; /* x[k] = new xB[p] = old xN[q] */
+ else
+ k = head[i]; /* x[k] = new xB[i] = old xB[i] */
+ lk = l[k], uk = u[k];
+ /* determine new value of r[i]; see spy_eval_r */
+ ri = 0.0;
+ if (beta[i] < lk)
+ { /* determine absolute tolerance eps1[i] */
+ eps = tol + tol1 * (lk >= 0.0 ? +lk : -lk);
+ if (beta[i] < lk - eps)
+ { /* lower bound is violated */
+ ri = lk - beta[i];
+ }
+ }
+ else if (beta[i] > uk)
+ { /* determine absolute tolerance eps2[i] */
+ eps = tol + tol1 * (uk >= 0.0 ? +uk : -uk);
+ if (beta[i] > uk + eps)
+ { /* upper bound is violated */
+ ri = uk - beta[i];
+ }
+ }
+ if (ri == 0.0)
+ { if (vec[i] != 0.0)
+ vec[i] = DBL_MIN; /* will be removed */
+ }
+ else
+ { if (vec[i] == 0.0)
+ ind[++nnz] = i;
+ vec[i] = ri;
+ }
+
+ }
+ r->nnz = nnz;
+ /* remove zero elements */
+ fvs_adjust_vec(r, DBL_MIN + DBL_MIN);
+ return;
+}
+#endif
+
+/***********************************************************************
+* spy_dual - driver to the dual simplex method
+*
+* This routine is a driver to the two-phase dual simplex method.
+*
+* On exit this routine returns one of the following codes:
+*
+* 0 LP instance has been successfully solved.
+*
+* GLP_EOBJLL
+* Objective lower limit has been reached (maximization).
+*
+* GLP_EOBJUL
+* Objective upper limit has been reached (minimization).
+*
+* GLP_EITLIM
+* Iteration limit has been exhausted.
+*
+* GLP_ETMLIM
+* Time limit has been exhausted.
+*
+* GLP_EFAIL
+* The solver failed to solve LP instance. */
+
+static int dual_simplex(struct csa *csa)
+{ /* dual simplex method main logic routine */
+ SPXLP *lp = csa->lp;
+ int m = lp->m;
+ int n = lp->n;
+ double *l = lp->l;
+ double *u = lp->u;
+ int *head = lp->head;
+ SPXNT *nt = csa->nt;
+ double *beta = csa->beta;
+ double *d = csa->d;
+ SPYSE *se = csa->se;
+#if 0 /* 30/III-2016 */
+ int *list = csa->list;
+#endif
+#if 0 /* 31/III-2016 */
+ double *trow = csa->trow;
+ double *tcol = csa->tcol;
+#endif
+ double *pi = csa->work;
+ int msg_lev = csa->msg_lev;
+ double tol_bnd = csa->tol_bnd;
+ double tol_bnd1 = csa->tol_bnd1;
+ double tol_dj = csa->tol_dj;
+ double tol_dj1 = csa->tol_dj1;
+ int j, k, p_flag, refct, ret;
+ int perturb = -1;
+ /* -1 = perturbation is not used, but enabled
+ * 0 = perturbation is not used and disabled
+ * +1 = perturbation is being used */
+#if 1 /* 27/III-2016 */
+ int instab = 0; /* instability count */
+#endif
+#ifdef TIMING
+ double t_total = timer(); /* total time */
+ double t_fact = 0.0; /* computing factorization */
+ double t_rtest = 0.0; /* performing ratio test */
+ double t_pivcol = 0.0; /* computing pivot column */
+ double t_upd1 = 0.0; /* updating primal values */
+ double t_upd2 = 0.0; /* updating dual values */
+ double t_upd3 = 0.0; /* updating se weights */
+ double t_upd4 = 0.0; /* updating matrix N */
+ double t_upd5 = 0.0; /* updating factorization */
+ double t_start;
+#endif
+ check_flags(csa);
+loop: /* main loop starts here */
+ /* compute factorization of the basis matrix */
+ if (!lp->valid)
+ { double cond;
+#ifdef TIMING
+ t_start = timer();
+#endif
+ ret = spx_factorize(lp);
+#ifdef TIMING
+ t_fact += timer() - t_start;
+#endif
+ csa->inv_cnt++;
+ if (ret != 0)
+ { if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Error: unable to factorize the basis matrix (%d"
+ ")\n", ret);
+ csa->p_stat = csa->d_stat = GLP_UNDEF;
+ ret = GLP_EFAIL;
+ goto fini;
+ }
+ /* check condition of the basis matrix */
+ cond = bfd_condest(lp->bfd);
+ if (cond > 1.0 / DBL_EPSILON)
+ { if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Error: basis matrix is singular to working prec"
+ "ision (cond = %.3g)\n", cond);
+ csa->p_stat = csa->d_stat = GLP_UNDEF;
+ ret = GLP_EFAIL;
+ goto fini;
+ }
+ if (cond > 0.001 / DBL_EPSILON)
+ { if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Warning: basis matrix is ill-conditioned (cond "
+ "= %.3g)\n", cond);
+ }
+ /* invalidate basic solution components */
+ csa->beta_st = csa->d_st = 0;
+ }
+ /* compute reduced costs of non-basic variables d = (d[j]) */
+ if (!csa->d_st)
+ { spx_eval_pi(lp, pi);
+ for (j = 1; j <= n-m; j++)
+ d[j] = spx_eval_dj(lp, pi, j);
+ csa->d_st = 1; /* just computed */
+ /* determine the search phase, if not determined yet (this is
+ * performed only once at the beginning of the search for the
+ * original bounds) */
+ if (!csa->phase)
+ { j = check_feas(csa, 0.97 * tol_dj, 0.97 * tol_dj1, 1);
+ if (j > 0)
+ { /* initial basic solution is dual infeasible and cannot
+ * be recovered */
+ /* start to search for dual feasible solution */
+ set_art_bounds(csa);
+ csa->phase = 1;
+ }
+ else
+ { /* initial basic solution is either dual feasible or its
+ * dual feasibility has been recovered */
+ /* start to search for optimal solution */
+ csa->phase = 2;
+ }
+ }
+ /* make sure that current basic solution is dual feasible */
+#if 1 /* 11/VII-2017 */
+ if (perturb <= 0)
+ { if (check_feas(csa, tol_dj, tol_dj1, 0))
+ { /* dual feasibility is broken due to excessive round-off
+ * errors */
+ if (perturb < 0)
+ { if (msg_lev >= GLP_MSG_ALL)
+ xprintf("Perturbing LP to avoid instability [%d].."
+ ".\n", csa->it_cnt);
+ perturb = 1;
+ goto loop;
+ }
+ if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Warning: numerical instability (dual simplex"
+ ", phase %s)\n", csa->phase == 1 ? "I" : "II");
+ instab++;
+ if (csa->dualp && instab >= 10)
+ { /* do not continue the search; report failure */
+ if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Warning: dual simplex failed due to exces"
+ "sive numerical instability\n");
+ csa->p_stat = csa->d_stat = GLP_UNDEF;
+ ret = -1; /* special case of GLP_EFAIL */
+ goto fini;
+ }
+ /* try to recover dual feasibility */
+ j = check_feas(csa, 0.97 * tol_dj, 0.97 * tol_dj1, 1);
+ if (j > 0)
+ { /* dual feasibility cannot be recovered (this may
+ * happen only on phase II) */
+ xassert(csa->phase == 2);
+ /* restart to search for dual feasible solution */
+ set_art_bounds(csa);
+ csa->phase = 1;
+ }
+ }
+ }
+ else
+ { /* FIXME */
+ play_coef(csa, 1);
+ }
+ }
+#endif
+ /* at this point the search phase is determined */
+ xassert(csa->phase == 1 || csa->phase == 2);
+ /* compute values of basic variables beta = (beta[i]) */
+ if (!csa->beta_st)
+ { spx_eval_beta(lp, beta);
+#if 1 /* 31/III-2016 */
+ /* also compute vector r of primal infeasibilities */
+ switch (csa->phase)
+ { case 1:
+ spy_eval_r(lp, beta, 1e-8, 0.0, &csa->r);
+ break;
+ case 2:
+ spy_eval_r(lp, beta, tol_bnd, tol_bnd1, &csa->r);
+ break;
+ default:
+ xassert(csa != csa);
+ }
+#endif
+ csa->beta_st = 1; /* just computed */
+ }
+ /* reset the dual reference space, if necessary */
+ if (se != NULL && !se->valid)
+ spy_reset_refsp(lp, se), refct = 1000;
+ /* at this point the basis factorization and all basic solution
+ * components are valid */
+ xassert(lp->valid && csa->beta_st && csa->d_st);
+#ifdef GLP_DEBUG
+ check_flags(csa);
+#endif
+#if CHECK_ACCURACY
+ /* check accuracy of current basic solution components (only for
+ * debugging) */
+ check_accuracy(csa);
+#endif
+ /* check if the objective limit has been reached */
+ if (csa->phase == 2 && csa->obj_lim != DBL_MAX
+ && spx_eval_obj(lp, beta) >= csa->obj_lim)
+ {
+#if 1 /* 26/V-2017 by mao */
+ if (perturb > 0)
+ { /* remove perturbation */
+ /* [Should note that perturbing of objective coefficients
+ * implemented in play_coef is equivalent to *relaxing* of
+ * (zero) bounds of dual variables, so the perturbed
+ * objective is always better (*greater*) that the original
+ * one at the same basic point.] */
+ remove_perturb(csa);
+ perturb = 0;
+ }
+#endif
+ if (csa->beta_st != 1)
+ csa->beta_st = 0;
+ if (csa->d_st != 1)
+ csa->d_st = 0;
+ if (!(csa->beta_st && csa->d_st))
+ goto loop;
+ display(csa, 1);
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("OBJECTIVE %s LIMIT REACHED; SEARCH TERMINATED\n",
+ csa->dir > 0 ? "UPPER" : "LOWER");
+#if 0 /* 30/III-2016 */
+ csa->num = spy_chuzr_sel(lp, beta, tol_bnd, tol_bnd1, list);
+ csa->p_stat = (csa->num == 0 ? GLP_FEAS : GLP_INFEAS);
+#else
+ spy_eval_r(lp, beta, tol_bnd, tol_bnd1, &csa->r);
+ csa->p_stat = (csa->r.nnz == 0 ? GLP_FEAS : GLP_INFEAS);
+#endif
+ csa->d_stat = GLP_FEAS;
+ ret = (csa->dir > 0 ? GLP_EOBJUL : GLP_EOBJLL);
+ goto fini;
+ }
+ /* check if the iteration limit has been exhausted */
+ if (csa->it_cnt - csa->it_beg >= csa->it_lim)
+ { if (perturb > 0)
+ { /* remove perturbation */
+ remove_perturb(csa);
+ perturb = 0;
+ }
+ if (csa->beta_st != 1)
+ csa->beta_st = 0;
+ if (csa->d_st != 1)
+ csa->d_st = 0;
+ if (!(csa->beta_st && csa->d_st))
+ goto loop;
+ display(csa, 1);
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
+ if (csa->phase == 1)
+ { set_orig_bounds(csa);
+ check_flags(csa);
+ spx_eval_beta(lp, beta);
+ }
+#if 0 /* 30/III-2016 */
+ csa->num = spy_chuzr_sel(lp, beta, tol_bnd, tol_bnd1, list);
+ csa->p_stat = (csa->num == 0 ? GLP_FEAS : GLP_INFEAS);
+#else
+ spy_eval_r(lp, beta, tol_bnd, tol_bnd1, &csa->r);
+ csa->p_stat = (csa->r.nnz == 0 ? GLP_FEAS : GLP_INFEAS);
+#endif
+ csa->d_stat = (csa->phase == 1 ? GLP_INFEAS : GLP_FEAS);
+ ret = GLP_EITLIM;
+ goto fini;
+ }
+ /* check if the time limit has been exhausted */
+ if (1000.0 * xdifftime(xtime(), csa->tm_beg) >= csa->tm_lim)
+ { if (perturb > 0)
+ { /* remove perturbation */
+ remove_perturb(csa);
+ perturb = 0;
+ }
+ if (csa->beta_st != 1)
+ csa->beta_st = 0;
+ if (csa->d_st != 1)
+ csa->d_st = 0;
+ if (!(csa->beta_st && csa->d_st))
+ goto loop;
+ display(csa, 1);
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+ if (csa->phase == 1)
+ { set_orig_bounds(csa);
+ check_flags(csa);
+ spx_eval_beta(lp, beta);
+ }
+#if 0 /* 30/III-2016 */
+ csa->num = spy_chuzr_sel(lp, beta, tol_bnd, tol_bnd1, list);
+ csa->p_stat = (csa->num == 0 ? GLP_FEAS : GLP_INFEAS);
+#else
+ spy_eval_r(lp, beta, tol_bnd, tol_bnd1, &csa->r);
+ csa->p_stat = (csa->r.nnz == 0 ? GLP_FEAS : GLP_INFEAS);
+#endif
+ csa->d_stat = (csa->phase == 1 ? GLP_INFEAS : GLP_FEAS);
+ ret = GLP_ETMLIM;
+ goto fini;
+ }
+ /* display the search progress */
+ display(csa, 0);
+ /* select eligible basic variables */
+#if 0 /* 31/III-2016; not needed because r is valid */
+ switch (csa->phase)
+ { case 1:
+#if 0 /* 30/III-2016 */
+ csa->num = spy_chuzr_sel(lp, beta, 1e-8, 0.0, list);
+#else
+ spy_eval_r(lp, beta, 1e-8, 0.0, &csa->r);
+#endif
+ break;
+ case 2:
+#if 0 /* 30/III-2016 */
+ csa->num = spy_chuzr_sel(lp, beta, tol_bnd, tol_bnd1, list);
+#else
+ spy_eval_r(lp, beta, tol_bnd, tol_bnd1, &csa->r);
+#endif
+ break;
+ default:
+ xassert(csa != csa);
+ }
+#endif
+ /* check for optimality */
+#if 0 /* 30/III-2016 */
+ if (csa->num == 0)
+#else
+ if (csa->r.nnz == 0)
+#endif
+ { if (perturb > 0 && csa->phase == 2)
+ { /* remove perturbation */
+ remove_perturb(csa);
+ perturb = 0;
+ }
+ if (csa->beta_st != 1)
+ csa->beta_st = 0;
+ if (csa->d_st != 1)
+ csa->d_st = 0;
+ if (!(csa->beta_st && csa->d_st))
+ goto loop;
+ /* current basis is optimal */
+ display(csa, 1);
+ switch (csa->phase)
+ { case 1:
+ /* check for dual feasibility */
+ set_orig_bounds(csa);
+ check_flags(csa);
+ if (check_feas(csa, tol_dj, tol_dj1, 0) == 0)
+ { /* dual feasible solution found; switch to phase II */
+ csa->phase = 2;
+ xassert(!csa->beta_st);
+ goto loop;
+ }
+#if 1 /* 26/V-2017 by cmatraki */
+ if (perturb > 0)
+ { /* remove perturbation */
+ remove_perturb(csa);
+ perturb = 0;
+ goto loop;
+ }
+#endif
+ /* no dual feasible solution exists */
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("LP HAS NO DUAL FEASIBLE SOLUTION\n");
+ spx_eval_beta(lp, beta);
+#if 0 /* 30/III-2016 */
+ csa->num = spy_chuzr_sel(lp, beta, tol_bnd, tol_bnd1,
+ list);
+ csa->p_stat = (csa->num == 0 ? GLP_FEAS : GLP_INFEAS);
+#else
+ spy_eval_r(lp, beta, tol_bnd, tol_bnd1, &csa->r);
+ csa->p_stat = (csa->r.nnz == 0 ? GLP_FEAS : GLP_INFEAS);
+#endif
+ csa->d_stat = GLP_NOFEAS;
+ ret = 0;
+ goto fini;
+ case 2:
+ /* optimal solution found */
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("OPTIMAL LP SOLUTION FOUND\n");
+ csa->p_stat = csa->d_stat = GLP_FEAS;
+ ret = 0;
+ goto fini;
+ default:
+ xassert(csa != csa);
+ }
+ }
+ /* choose xB[p] and xN[q] */
+#if 0 /* 23/III-2016 */
+ choose_pivot(csa);
+#else
+#ifdef TIMING
+ t_start = timer();
+#endif
+#if 1 /* 31/III-2016 */
+ ret = choose_pivot(csa);
+#endif
+#ifdef TIMING
+ t_rtest += timer() - t_start;
+#endif
+ if (ret < 0)
+ { lp->valid = 0;
+ goto loop;
+ }
+ if (ret == 0)
+ csa->ns_cnt++;
+ else
+ csa->ls_cnt++;
+#endif
+ /* check for dual unboundedness */
+ if (csa->q == 0)
+ { if (perturb > 0)
+ { /* remove perturbation */
+ remove_perturb(csa);
+ perturb = 0;
+ }
+ if (csa->beta_st != 1)
+ csa->beta_st = 0;
+ if (csa->d_st != 1)
+ csa->d_st = 0;
+ if (!(csa->beta_st && csa->d_st))
+ goto loop;
+ display(csa, 1);
+ switch (csa->phase)
+ { case 1:
+ /* this should never happen */
+ if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Error: dual simplex failed\n");
+ csa->p_stat = csa->d_stat = GLP_UNDEF;
+ ret = GLP_EFAIL;
+ goto fini;
+ case 2:
+ /* dual unboundedness detected */
+ if (msg_lev >= GLP_MSG_ALL)
+ xprintf("LP HAS NO PRIMAL FEASIBLE SOLUTION\n");
+ csa->p_stat = GLP_NOFEAS;
+ csa->d_stat = GLP_FEAS;
+ ret = 0;
+ goto fini;
+ default:
+ xassert(csa != csa);
+ }
+ }
+ /* compute q-th column of the simplex table */
+#ifdef TIMING
+ t_start = timer();
+#endif
+#if 0 /* 31/III-2016 */
+ spx_eval_tcol(lp, csa->q, tcol);
+#else
+ spx_eval_tcol(lp, csa->q, csa->tcol.vec);
+ fvs_gather_vec(&csa->tcol, DBL_EPSILON);
+#endif
+#ifdef TIMING
+ t_pivcol += timer() - t_start;
+#endif
+ /* FIXME: tcol[p] and trow[q] should be close to each other */
+#if 0 /* 26/V-2017 by cmatraki */
+ xassert(csa->tcol.vec[csa->p] != 0.0);
+#else
+ if (csa->tcol.vec[csa->p] == 0.0)
+ { if (msg_lev >= GLP_MSG_ERR)
+ xprintf("Error: tcol[p] = 0.0\n");
+ csa->p_stat = csa->d_stat = GLP_UNDEF;
+ ret = GLP_EFAIL;
+ goto fini;
+ }
+#endif
+ /* update values of basic variables for adjacent basis */
+ k = head[csa->p]; /* x[k] = xB[p] */
+ p_flag = (l[k] != u[k] && beta[csa->p] > u[k]);
+#if 0 /* 16/III-2016 */
+ spx_update_beta(lp, beta, csa->p, p_flag, csa->q, tcol);
+ csa->beta_st = 2;
+#else
+ /* primal solution may be invalidated due to long step */
+#ifdef TIMING
+ t_start = timer();
+#endif
+ if (csa->beta_st)
+#if 0 /* 30/III-2016 */
+ { spx_update_beta(lp, beta, csa->p, p_flag, csa->q, tcol);
+#else
+ { spx_update_beta_s(lp, beta, csa->p, p_flag, csa->q,
+ &csa->tcol);
+ /* also update vector r of primal infeasibilities */
+ /*fvs_check_vec(&csa->r);*/
+ switch (csa->phase)
+ { case 1:
+ spy_update_r(lp, csa->p, csa->q, beta, &csa->tcol,
+ 1e-8, 0.0, &csa->r);
+ break;
+ case 2:
+ spy_update_r(lp, csa->p, csa->q, beta, &csa->tcol,
+ tol_bnd, tol_bnd1, &csa->r);
+ break;
+ default:
+ xassert(csa != csa);
+ }
+ /*fvs_check_vec(&csa->r);*/
+#endif
+ csa->beta_st = 2;
+ }
+#ifdef TIMING
+ t_upd1 += timer() - t_start;
+#endif
+#endif
+#if 1 /* 11/VII-2017 */
+ /* check for stalling */
+ { int k;
+ xassert(1 <= csa->p && csa->p <= m);
+ xassert(1 <= csa->q && csa->q <= n-m);
+ /* FIXME: recompute d[q]; see spx_update_d */
+ k = head[m+csa->q]; /* x[k] = xN[q] */
+ if (!(lp->l[k] == -DBL_MAX && lp->u[k] == +DBL_MAX))
+ { if (fabs(d[csa->q]) >= 1e-6)
+ { csa->degen = 0;
+ goto skip1;
+ }
+ /* degenerate iteration has been detected */
+ csa->degen++;
+ if (perturb < 0 && csa->degen >= 200)
+ { if (msg_lev >= GLP_MSG_ALL)
+ xprintf("Perturbing LP to avoid stalling [%d]...\n",
+ csa->it_cnt);
+ perturb = 1;
+ }
+skip1: ;
+ }
+ }
+#endif
+ /* update reduced costs of non-basic variables for adjacent
+ * basis */
+#if 1 /* 28/III-2016 */
+ xassert(csa->d_st);
+#endif
+#ifdef TIMING
+ t_start = timer();
+#endif
+#if 0 /* 30/III-2016 */
+ if (spx_update_d(lp, d, csa->p, csa->q, trow, tcol) <= 1e-9)
+#else
+ if (spx_update_d_s(lp, d, csa->p, csa->q, &csa->trow, &csa->tcol)
+ <= 1e-9)
+#endif
+ { /* successful updating */
+ csa->d_st = 2;
+ }
+ else
+ { /* new reduced costs are inaccurate */
+ csa->d_st = 0;
+ }
+#ifdef TIMING
+ t_upd2 += timer() - t_start;
+#endif
+ /* update steepest edge weights for adjacent basis, if used */
+#ifdef TIMING
+ t_start = timer();
+#endif
+ if (se != NULL)
+ { if (refct > 0)
+#if 0 /* 30/III-2016 */
+ { if (spy_update_gamma(lp, se, csa->p, csa->q, trow, tcol)
+ <= 1e-3)
+#else
+ { if (spy_update_gamma_s(lp, se, csa->p, csa->q, &csa->trow,
+ &csa->tcol) <= 1e-3)
+#endif
+ { /* successful updating */
+ refct--;
+ }
+ else
+ { /* new weights are inaccurate; reset reference space */
+ se->valid = 0;
+ }
+ }
+ else
+ { /* too many updates; reset reference space */
+ se->valid = 0;
+ }
+ }
+#ifdef TIMING
+ t_upd3 += timer() - t_start;
+#endif
+#ifdef TIMING
+ t_start = timer();
+#endif
+ /* update matrix N for adjacent basis, if used */
+ if (nt != NULL)
+ spx_update_nt(lp, nt, csa->p, csa->q);
+#ifdef TIMING
+ t_upd4 += timer() - t_start;
+#endif
+ /* change current basis header to adjacent one */
+ spx_change_basis(lp, csa->p, p_flag, csa->q);
+ /* and update factorization of the basis matrix */
+#ifdef TIMING
+ t_start = timer();
+#endif
+#if 0 /* 16/III-2016 */
+ if (csa->p > 0)
+#endif
+ spx_update_invb(lp, csa->p, head[csa->p]);
+#ifdef TIMING
+ t_upd5 += timer() - t_start;
+#endif
+ if (perturb > 0 && csa->d_st)
+ play_coef(csa, 0);
+ /* dual simplex iteration complete */
+ csa->it_cnt++;
+ goto loop;
+fini:
+#ifdef TIMING
+ t_total = timer() - t_total;
+ xprintf("Total time = %10.3f\n", t_total);
+ xprintf("Factorization = %10.3f\n", t_fact);
+ xprintf("Ratio test = %10.3f\n", t_rtest);
+ xprintf("Pivot column = %10.3f\n", t_pivcol);
+ xprintf("Updating beta = %10.3f\n", t_upd1);
+ xprintf("Updating d = %10.3f\n", t_upd2);
+ xprintf("Updating gamma = %10.3f\n", t_upd3);
+ xprintf("Updating N = %10.3f\n", t_upd4);
+ xprintf("Updating inv(B) = %10.3f\n", t_upd5);
+#endif
+ return ret;
+}
+
+int spy_dual(glp_prob *P, const glp_smcp *parm)
+{ /* driver to the dual simplex method */
+ struct csa csa_, *csa = &csa_;
+ SPXLP lp;
+ SPXAT at;
+ SPXNT nt;
+ SPYSE se;
+ int ret, *map, *daeh;
+#if SCALE_Z
+ int i, j, k;
+#endif
+ /* build working LP and its initial basis */
+ memset(csa, 0, sizeof(struct csa));
+ csa->lp = &lp;
+ spx_init_lp(csa->lp, P, parm->excl);
+ spx_alloc_lp(csa->lp);
+ map = talloc(1+P->m+P->n, int);
+ spx_build_lp(csa->lp, P, parm->excl, parm->shift, map);
+ spx_build_basis(csa->lp, P, map);
+ switch (P->dir)
+ { case GLP_MIN:
+ csa->dir = +1;
+ break;
+ case GLP_MAX:
+ csa->dir = -1;
+ break;
+ default:
+ xassert(P != P);
+ }
+#if SCALE_Z
+ csa->fz = 0.0;
+ for (k = 1; k <= csa->lp->n; k++)
+ { double t = fabs(csa->lp->c[k]);
+ if (csa->fz < t)
+ csa->fz = t;
+ }
+ if (csa->fz <= 1000.0)
+ csa->fz = 1.0;
+ else
+ csa->fz /= 1000.0;
+ /*xprintf("csa->fz = %g\n", csa->fz);*/
+ for (k = 0; k <= csa->lp->n; k++)
+ csa->lp->c[k] /= csa->fz;
+#endif
+ csa->orig_b = talloc(1+csa->lp->m, double);
+ memcpy(csa->orig_b, csa->lp->b, (1+csa->lp->m) * sizeof(double));
+ csa->orig_c = talloc(1+csa->lp->n, double);
+ memcpy(csa->orig_c, csa->lp->c, (1+csa->lp->n) * sizeof(double));
+ csa->orig_l = talloc(1+csa->lp->n, double);
+ memcpy(csa->orig_l, csa->lp->l, (1+csa->lp->n) * sizeof(double));
+ csa->orig_u = talloc(1+csa->lp->n, double);
+ memcpy(csa->orig_u, csa->lp->u, (1+csa->lp->n) * sizeof(double));
+ switch (parm->aorn)
+ { case GLP_USE_AT:
+ /* build matrix A in row-wise format */
+ csa->at = &at;
+ csa->nt = NULL;
+ spx_alloc_at(csa->lp, csa->at);
+ spx_build_at(csa->lp, csa->at);
+ break;
+ case GLP_USE_NT:
+ /* build matrix N in row-wise format for initial basis */
+ csa->at = NULL;
+ csa->nt = &nt;
+ spx_alloc_nt(csa->lp, csa->nt);
+ spx_init_nt(csa->lp, csa->nt);
+ spx_build_nt(csa->lp, csa->nt);
+ break;
+ default:
+ xassert(parm != parm);
+ }
+ /* allocate and initialize working components */
+ csa->phase = 0;
+ csa->beta = talloc(1+csa->lp->m, double);
+ csa->beta_st = 0;
+ csa->d = talloc(1+csa->lp->n-csa->lp->m, double);
+ csa->d_st = 0;
+ switch (parm->pricing)
+ { case GLP_PT_STD:
+ csa->se = NULL;
+ break;
+ case GLP_PT_PSE:
+ csa->se = &se;
+ spy_alloc_se(csa->lp, csa->se);
+ break;
+ default:
+ xassert(parm != parm);
+ }
+#if 0 /* 30/III-2016 */
+ csa->list = talloc(1+csa->lp->m, int);
+ csa->trow = talloc(1+csa->lp->n-csa->lp->m, double);
+ csa->tcol = talloc(1+csa->lp->m, double);
+#else
+ fvs_alloc_vec(&csa->r, csa->lp->m);
+ fvs_alloc_vec(&csa->trow, csa->lp->n-csa->lp->m);
+ fvs_alloc_vec(&csa->tcol, csa->lp->m);
+#endif
+#if 1 /* 16/III-2016 */
+ csa->bp = NULL;
+#endif
+ csa->work = talloc(1+csa->lp->m, double);
+ csa->work1 = talloc(1+csa->lp->n-csa->lp->m, double);
+#if 0 /* 11/VI-2017 */
+#if 1 /* 31/III-2016 */
+ fvs_alloc_vec(&csa->wrow, csa->lp->n-csa->lp->m);
+ fvs_alloc_vec(&csa->wcol, csa->lp->m);
+#endif
+#endif
+ /* initialize control parameters */
+ csa->msg_lev = parm->msg_lev;
+ csa->dualp = (parm->meth == GLP_DUALP);
+#if 0 /* 16/III-2016 */
+ switch (parm->r_test)
+ { case GLP_RT_STD:
+ csa->harris = 0;
+ break;
+ case GLP_RT_HAR:
+ csa->harris = 1;
+ break;
+ default:
+ xassert(parm != parm);
+ }
+#else
+ switch (parm->r_test)
+ { case GLP_RT_STD:
+ case GLP_RT_HAR:
+ break;
+ case GLP_RT_FLIP:
+ csa->bp = talloc(1+csa->lp->n-csa->lp->m, SPYBP);
+ break;
+ default:
+ xassert(parm != parm);
+ }
+ csa->r_test = parm->r_test;
+#endif
+ csa->tol_bnd = parm->tol_bnd;
+ csa->tol_bnd1 = .001 * parm->tol_bnd;
+ csa->tol_dj = parm->tol_dj;
+ csa->tol_dj1 = .001 * parm->tol_dj;
+#if 0
+ csa->tol_dj1 = 1e-9 * parm->tol_dj;
+#endif
+ csa->tol_piv = parm->tol_piv;
+ switch (P->dir)
+ { case GLP_MIN:
+ csa->obj_lim = + parm->obj_ul;
+ break;
+ case GLP_MAX:
+ csa->obj_lim = - parm->obj_ll;
+ break;
+ default:
+ xassert(parm != parm);
+ }
+#if SCALE_Z
+ if (csa->obj_lim != DBL_MAX)
+ csa->obj_lim /= csa->fz;
+#endif
+ csa->it_lim = parm->it_lim;
+ csa->tm_lim = parm->tm_lim;
+ csa->out_frq = parm->out_frq;
+ csa->out_dly = parm->out_dly;
+ /* initialize working parameters */
+ csa->tm_beg = xtime();
+ csa->it_beg = csa->it_cnt = P->it_cnt;
+ csa->it_dpy = -1;
+#if 1 /* 15/VII-2017 */
+ csa->tm_dpy = 0.0;
+#endif
+ csa->inv_cnt = 0;
+#if 1 /* 11/VII-2017 */
+ csa->degen = 0;
+#endif
+#if 1 /* 23/III-2016 */
+ csa->ns_cnt = csa->ls_cnt = 0;
+#endif
+ /* try to solve working LP */
+ ret = dual_simplex(csa);
+ /* return basis factorization back to problem object */
+ P->valid = csa->lp->valid;
+ P->bfd = csa->lp->bfd;
+ /* set solution status */
+ P->pbs_stat = csa->p_stat;
+ P->dbs_stat = csa->d_stat;
+ /* if the solver failed, do not store basis header and basic
+ * solution components to problem object */
+ if (ret == GLP_EFAIL)
+ goto skip;
+ /* convert working LP basis to original LP basis and store it to
+ * problem object */
+ daeh = talloc(1+csa->lp->n, int);
+ spx_store_basis(csa->lp, P, map, daeh);
+ /* compute simplex multipliers for final basic solution found by
+ * the solver */
+ spx_eval_pi(csa->lp, csa->work);
+ /* convert working LP solution to original LP solution and store
+ * it to problem object */
+#if SCALE_Z
+ for (i = 1; i <= csa->lp->m; i++)
+ csa->work[i] *= csa->fz;
+ for (j = 1; j <= csa->lp->n-csa->lp->m; j++)
+ csa->d[j] *= csa->fz;
+#endif
+ spx_store_sol(csa->lp, P, parm->shift, map, daeh, csa->beta,
+ csa->work, csa->d);
+ tfree(daeh);
+ /* save simplex iteration count */
+ P->it_cnt = csa->it_cnt;
+ /* report auxiliary/structural variable causing unboundedness */
+ P->some = 0;
+ if (csa->p_stat == GLP_NOFEAS && csa->d_stat == GLP_FEAS)
+ { int k, kk;
+ /* xB[p] = x[k] causes dual unboundedness */
+ xassert(1 <= csa->p && csa->p <= csa->lp->m);
+ k = csa->lp->head[csa->p];
+ xassert(1 <= k && k <= csa->lp->n);
+ /* convert to number of original variable */
+ for (kk = 1; kk <= P->m + P->n; kk++)
+ { if (abs(map[kk]) == k)
+ { P->some = kk;
+ break;
+ }
+ }
+ xassert(P->some != 0);
+ }
+skip: /* deallocate working objects and arrays */
+ spx_free_lp(csa->lp);
+ tfree(map);
+ tfree(csa->orig_b);
+ tfree(csa->orig_c);
+ tfree(csa->orig_l);
+ tfree(csa->orig_u);
+ if (csa->at != NULL)
+ spx_free_at(csa->lp, csa->at);
+ if (csa->nt != NULL)
+ spx_free_nt(csa->lp, csa->nt);
+ tfree(csa->beta);
+ tfree(csa->d);
+ if (csa->se != NULL)
+ spy_free_se(csa->lp, csa->se);
+#if 0 /* 30/III-2016 */
+ tfree(csa->list);
+ tfree(csa->trow);
+#else
+ fvs_free_vec(&csa->r);
+ fvs_free_vec(&csa->trow);
+#endif
+#if 1 /* 16/III-2016 */
+ if (csa->bp != NULL)
+ tfree(csa->bp);
+#endif
+#if 0 /* 29/III-2016 */
+ tfree(csa->tcol);
+#else
+ fvs_free_vec(&csa->tcol);
+#endif
+ tfree(csa->work);
+ tfree(csa->work1);
+#if 0 /* 11/VI-2017 */
+#if 1 /* 31/III-2016 */
+ fvs_free_vec(&csa->wrow);
+ fvs_free_vec(&csa->wcol);
+#endif
+#endif
+ /* return to calling program */
+ return ret >= 0 ? ret : GLP_EFAIL;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/zlib/README b/test/monniaux/glpk-4.65/src/zlib/README
new file mode 100644
index 00000000..2796312f
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/README
@@ -0,0 +1,45 @@
+NOTE: Files in this subdirectory are NOT part of the GLPK package, but
+ are used with GLPK.
+
+ The original code was modified according to GLPK requirements by
+ Andrew Makhorin <mao@gnu.org>.
+
+ The following files were rewritten:
+ gzguts.h, zconf.h, zutil.h.
+
+ The following files were added:
+ zio.h, zio.c.
+
+ Other files were not changed.
+************************************************************************
+zlib general purpose compression library
+version 1.2.5, April 19th, 2010
+
+Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would
+ be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+ distribution.
+
+Jean-loup Gailly Mark Adler
+jloup@gzip.org madler@alumni.caltech.edu
+
+The data format used by the zlib library is described by RFCs (Request
+for Comments) 1950 to 1952 in the files
+http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate
+format) and rfc1952.txt (gzip format).
diff --git a/test/monniaux/glpk-4.65/src/zlib/adler32.c b/test/monniaux/glpk-4.65/src/zlib/adler32.c
new file mode 100644
index 00000000..65ad6a5a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/adler32.c
@@ -0,0 +1,169 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2007 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#define local static
+
+local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2);
+
+#define BASE 65521UL /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD4(a) \
+ do { \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD4(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+local uLong adler32_combine_(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ rem = (unsigned)(len2 % BASE);
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 >= BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
+
+uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/compress.c b/test/monniaux/glpk-4.65/src/zlib/compress.c
new file mode 100644
index 00000000..ea4dfbe9
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/compress.c
@@ -0,0 +1,80 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+ (sourceLen >> 25) + 13;
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/crc32.c b/test/monniaux/glpk-4.65/src/zlib/crc32.c
new file mode 100644
index 00000000..91be372d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/crc32.c
@@ -0,0 +1,442 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2006, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# ifdef STDC /* need ANSI C limits.h to determine sizes */
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+# endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2);
+
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ unsigned long c;
+ int n, k;
+ unsigned long poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0UL;
+ for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ poly |= 1UL << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = REV(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = REV(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const unsigned long FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const unsigned long FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ uInt len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+local uLong crc32_combine_(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case (also disallow negative lengths) */
+ if (len2 <= 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ return crc32_combine_(crc1, crc2, len2);
+}
+
+uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+ return crc32_combine_(crc1, crc2, len2);
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/crc32.h b/test/monniaux/glpk-4.65/src/zlib/crc32.h
new file mode 100644
index 00000000..8053b611
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/test/monniaux/glpk-4.65/src/zlib/deflate.c b/test/monniaux/glpk-4.65/src/zlib/deflate.c
new file mode 100644
index 00000000..5c4022f3
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/deflate.c
@@ -0,0 +1,1834 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local block_state deflate_rle OF((deflate_state *s, int flush));
+local block_state deflate_huff OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->high_water = 0; /* nothing written to s->window yet */
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->wrap == 2 ||
+ (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+ return Z_STREAM_ERROR;
+
+ s = strm->state;
+ if (s->wrap)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > s->w_size) {
+ length = s->w_size;
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ strm->state->bi_valid = bits;
+ strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if ((strategy != s->strategy || func != configuration_table[level].func) &&
+ strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_BLOCK);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds for
+ * every combination of windowBits and memLevel. But even the conservative
+ * upper bound of about 14% expansion does not seem onerous for output buffer
+ * allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong complen, wraplen;
+ Bytef *str;
+
+ /* conservative upper bound for compressed data */
+ complen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
+
+ /* if can't get parameters, return conservative bound plus zlib wrapper */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return complen + 6;
+
+ /* compute wrapper length */
+ s = strm->state;
+ switch (s->wrap) {
+ case 0: /* raw deflate */
+ wraplen = 0;
+ break;
+ case 1: /* zlib wrapper */
+ wraplen = 6 + (s->strstart ? 4 : 0);
+ break;
+ case 2: /* gzip wrapper */
+ wraplen = 18;
+ if (s->gzhead != Z_NULL) { /* user-supplied gzip header */
+ if (s->gzhead->extra != Z_NULL)
+ wraplen += 2 + s->gzhead->extra_len;
+ str = s->gzhead->name;
+ if (str != Z_NULL)
+ do {
+ wraplen++;
+ } while (*str++);
+ str = s->gzhead->comment;
+ if (str != Z_NULL)
+ do {
+ wraplen++;
+ } while (*str++);
+ if (s->gzhead->hcrc)
+ wraplen += 2;
+ }
+ break;
+ default: /* for compiler happiness */
+ wraplen = 6;
+ }
+
+ /* if not default parameters, return conservative bound */
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return complen + wraplen;
+
+ /* default settings: return tight bound for that case */
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+ (sourceLen >> 25) + 13 - 6 + wraplen;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_BLOCK || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == Z_NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != Z_NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+ (s->strategy == Z_RLE ? deflate_rle(s, flush) :
+ (*(configuration_table[s->level].func))(s, flush));
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ if (s->lookahead == 0) {
+ s->strstart = 0;
+ s->block_start = 0L;
+ }
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy(dest, source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy(ds, ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, strm->next_in, len);
+ }
+#endif
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+
+#else /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for FASTEST only
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#endif /* FASTEST */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+
+ /* If the WIN_INIT bytes after the end of the current data have never been
+ * written, then zero those bytes in order to avoid memory check reports of
+ * the use of uninitialized (or uninitialised as Julian writes) bytes by
+ * the longest match routines. Update the high water mark for the next
+ * time through here. WIN_INIT is set to MAX_MATCH since the longest match
+ * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+ */
+ if (s->high_water < s->window_size) {
+ ulg curr = s->strstart + (ulg)(s->lookahead);
+ ulg init;
+
+ if (s->high_water < curr) {
+ /* Previous high water mark below current data -- zero WIN_INIT
+ * bytes or up to end of window, whichever is less.
+ */
+ init = s->window_size - curr;
+ if (init > WIN_INIT)
+ init = WIN_INIT;
+ zmemzero(s->window + curr, (unsigned)init);
+ s->high_water = curr + init;
+ }
+ else if (s->high_water < (ulg)curr + WIN_INIT) {
+ /* High water mark at or above current data, but below current data
+ * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+ * to end of window, whichever is less.
+ */
+ init = (ulg)curr + WIN_INIT - s->high_water;
+ if (init > s->window_size - s->high_water)
+ init = s->window_size - s->high_water;
+ zmemzero(s->window + s->high_water, (unsigned)init);
+ s->high_water += init;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, last) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (last)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, last) { \
+ FLUSH_BLOCK_ONLY(s, last); \
+ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ hash_head = NIL;
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ s->match_length = longest_match (s, hash_head);
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ hash_head = NIL;
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ s->match_length = longest_match (s, hash_head);
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan, *strend; /* scan goes up to strend for length of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest encodable run.
+ */
+ if (s->lookahead < MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ s->match_length = 0;
+ if (s->lookahead >= MIN_MATCH && s->strstart > 0) {
+ scan = s->window + s->strstart - 1;
+ prev = *scan;
+ if (prev == *++scan && prev == *++scan && prev == *++scan) {
+ strend = s->window + s->strstart + MAX_MATCH;
+ do {
+ } while (prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ scan < strend);
+ s->match_length = MAX_MATCH - (int)(strend - scan);
+ if (s->match_length > s->lookahead)
+ s->match_length = s->lookahead;
+ }
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, s->match_length);
+
+ _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
+ * (It will be regenerated if this run of deflate switches away from Huffman.)
+ */
+local block_state deflate_huff(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we have a literal to write. */
+ if (s->lookahead == 0) {
+ fill_window(s);
+ if (s->lookahead == 0) {
+ if (flush == Z_NO_FLUSH)
+ return need_more;
+ break; /* flush the current block */
+ }
+ }
+
+ /* Output a literal byte */
+ s->match_length = 0;
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/deflate.h b/test/monniaux/glpk-4.65/src/zlib/deflate.h
new file mode 100644
index 00000000..cbf0d1ea
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/deflate.h
@@ -0,0 +1,342 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2010 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+ ulg high_water;
+ /* High water mark offset in window for initialized bytes -- bytes above
+ * this are set to zero in order to avoid memory check warnings when
+ * longest match routines access bytes past the input. This is then
+ * updated to the new high water mark.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#define WIN_INIT MAX_MATCH
+/* Number of bytes after end of data in window to initialize in order to avoid
+ memory checker errors from longest match routines */
+
+ /* in trees.c */
+void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
+int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
+ ulg stored_len, int last));
+void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
+ ulg stored_len, int last));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch ZLIB_INTERNAL _length_code[];
+ extern uch ZLIB_INTERNAL _dist_code[];
+#else
+ extern const uch ZLIB_INTERNAL _length_code[];
+ extern const uch ZLIB_INTERNAL _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/test/monniaux/glpk-4.65/src/zlib/gzclose.c b/test/monniaux/glpk-4.65/src/zlib/gzclose.c
new file mode 100644
index 00000000..caeb99a3
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/gzclose.c
@@ -0,0 +1,25 @@
+/* gzclose.c -- zlib gzclose() function
+ * Copyright (C) 2004, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* gzclose() is in a separate file so that it is linked in only if it is used.
+ That way the other gzclose functions can be used instead to avoid linking in
+ unneeded compression or decompression routines. */
+int ZEXPORT gzclose(file)
+ gzFile file;
+{
+#ifndef NO_GZCOMPRESS
+ gz_statep state;
+
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file);
+#else
+ return gzclose_r(file);
+#endif
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/gzguts.h b/test/monniaux/glpk-4.65/src/zlib/gzguts.h
new file mode 100644
index 00000000..9d01ac7b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/gzguts.h
@@ -0,0 +1,74 @@
+/* gzguts.h (zlib internal header definitions for gz* operations) */
+
+/* Modified by Andrew Makhorin <mao@gnu.org>, April 2011 */
+
+/* Copyright (C) 2004, 2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in
+ * zlib.h */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h. */
+
+#ifndef GZGUTS_H
+#define GZGUTS_H
+
+#define ZLIB_INTERNAL
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zio.h"
+#include "zlib.h"
+
+#define local static
+
+#define zstrerror() strerror(errno)
+
+#define GZBUFSIZE 8192
+
+#define GZ_NONE 0
+#define GZ_READ 7247
+#define GZ_WRITE 31153
+#define GZ_APPEND 1
+
+#define LOOK 0
+#define COPY 1
+#define GZIP 2
+
+typedef struct
+{ int mode;
+ int fd;
+ char *path;
+ z_off64_t pos;
+ unsigned size;
+ unsigned want;
+ unsigned char *in;
+ unsigned char *out;
+ unsigned char *next;
+ unsigned have;
+ int eof;
+ z_off64_t start;
+ z_off64_t raw;
+ int how;
+ int direct;
+ int level;
+ int strategy;
+ z_off64_t skip;
+ int seek;
+ int err;
+ char *msg;
+ z_stream strm;
+} gz_state;
+
+typedef gz_state *gz_statep;
+
+void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
+
+#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/zlib/gzlib.c b/test/monniaux/glpk-4.65/src/zlib/gzlib.c
new file mode 100644
index 00000000..603e60ed
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/gzlib.c
@@ -0,0 +1,537 @@
+/* gzlib.c -- zlib functions common to reading and writing gzip files
+ * Copyright (C) 2004, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+# define LSEEK lseek64
+#else
+# define LSEEK lseek
+#endif
+
+/* Local functions */
+local void gz_reset OF((gz_statep));
+local gzFile gz_open OF((const char *, int, const char *));
+
+#if defined UNDER_CE
+
+/* Map the Windows error number in ERROR to a locale-dependent error message
+ string and return a pointer to it. Typically, the values for ERROR come
+ from GetLastError.
+
+ The string pointed to shall not be modified by the application, but may be
+ overwritten by a subsequent call to gz_strwinerror
+
+ The gz_strwinerror function does not change the current setting of
+ GetLastError. */
+char ZLIB_INTERNAL *gz_strwinerror (error)
+ DWORD error;
+{
+ static char buf[1024];
+
+ wchar_t *msgbuf;
+ DWORD lasterr = GetLastError();
+ DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL,
+ error,
+ 0, /* Default language */
+ (LPVOID)&msgbuf,
+ 0,
+ NULL);
+ if (chars != 0) {
+ /* If there is an \r\n appended, zap it. */
+ if (chars >= 2
+ && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
+ chars -= 2;
+ msgbuf[chars] = 0;
+ }
+
+ if (chars > sizeof (buf) - 1) {
+ chars = sizeof (buf) - 1;
+ msgbuf[chars] = 0;
+ }
+
+ wcstombs(buf, msgbuf, chars + 1);
+ LocalFree(msgbuf);
+ }
+ else {
+ sprintf(buf, "unknown win32 error (%ld)", error);
+ }
+
+ SetLastError(lasterr);
+ return buf;
+}
+
+#endif /* UNDER_CE */
+
+/* Reset gzip file state */
+local void gz_reset(state)
+ gz_statep state;
+{
+ if (state->mode == GZ_READ) { /* for reading ... */
+ state->have = 0; /* no output data available */
+ state->eof = 0; /* not at end of file */
+ state->how = LOOK; /* look for gzip header */
+ state->direct = 1; /* default for empty file */
+ }
+ state->seek = 0; /* no seek request pending */
+ gz_error(state, Z_OK, NULL); /* clear error */
+ state->pos = 0; /* no uncompressed data yet */
+ state->strm.avail_in = 0; /* no input data yet */
+}
+
+/* Open a gzip file either by name or file descriptor. */
+local gzFile gz_open(path, fd, mode)
+ const char *path;
+ int fd;
+ const char *mode;
+{
+ gz_statep state;
+
+ /* allocate gzFile structure to return */
+ state = malloc(sizeof(gz_state));
+ if (state == NULL)
+ return NULL;
+ state->size = 0; /* no buffers allocated yet */
+ state->want = GZBUFSIZE; /* requested buffer size */
+ state->msg = NULL; /* no error message yet */
+
+ /* interpret mode */
+ state->mode = GZ_NONE;
+ state->level = Z_DEFAULT_COMPRESSION;
+ state->strategy = Z_DEFAULT_STRATEGY;
+ while (*mode) {
+ if (*mode >= '0' && *mode <= '9')
+ state->level = *mode - '0';
+ else
+ switch (*mode) {
+ case 'r':
+ state->mode = GZ_READ;
+ break;
+#ifndef NO_GZCOMPRESS
+ case 'w':
+ state->mode = GZ_WRITE;
+ break;
+ case 'a':
+ state->mode = GZ_APPEND;
+ break;
+#endif
+ case '+': /* can't read and write at the same time */
+ free(state);
+ return NULL;
+ case 'b': /* ignore -- will request binary anyway */
+ break;
+ case 'f':
+ state->strategy = Z_FILTERED;
+ break;
+ case 'h':
+ state->strategy = Z_HUFFMAN_ONLY;
+ break;
+ case 'R':
+ state->strategy = Z_RLE;
+ break;
+ case 'F':
+ state->strategy = Z_FIXED;
+ default: /* could consider as an error, but just ignore */
+ ;
+ }
+ mode++;
+ }
+
+ /* must provide an "r", "w", or "a" */
+ if (state->mode == GZ_NONE) {
+ free(state);
+ return NULL;
+ }
+
+ /* save the path name for error messages */
+ state->path = malloc(strlen(path) + 1);
+ if (state->path == NULL) {
+ free(state);
+ return NULL;
+ }
+ strcpy(state->path, path);
+
+ /* open the file with the appropriate mode (or just use fd) */
+ state->fd = fd != -1 ? fd :
+ open(path,
+#ifdef O_LARGEFILE
+ O_LARGEFILE |
+#endif
+#ifdef O_BINARY
+ O_BINARY |
+#endif
+ (state->mode == GZ_READ ?
+ O_RDONLY :
+ (O_WRONLY | O_CREAT | (
+ state->mode == GZ_WRITE ?
+ O_TRUNC :
+ O_APPEND))),
+ 0666);
+ if (state->fd == -1) {
+ free(state->path);
+ free(state);
+ return NULL;
+ }
+ if (state->mode == GZ_APPEND)
+ state->mode = GZ_WRITE; /* simplify later checks */
+
+ /* save the current position for rewinding (only if reading) */
+ if (state->mode == GZ_READ) {
+ state->start = LSEEK(state->fd, 0, SEEK_CUR);
+ if (state->start == -1) state->start = 0;
+ }
+
+ /* initialize stream */
+ gz_reset(state);
+
+ /* return stream */
+ return (gzFile)state;
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen(path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen64(path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzdopen(fd, mode)
+ int fd;
+ const char *mode;
+{
+ char *path; /* identifier for error messages */
+ gzFile gz;
+
+ if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL)
+ return NULL;
+ sprintf(path, "<fd:%d>", fd); /* for debugging */
+ gz = gz_open(path, fd, mode);
+ free(path);
+ return gz;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzbuffer(file, size)
+ gzFile file;
+ unsigned size;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* make sure we haven't already allocated memory */
+ if (state->size != 0)
+ return -1;
+
+ /* check and set requested size */
+ if (size == 0)
+ return -1;
+ state->want = size;
+ return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzrewind(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no error */
+ if (state->mode != GZ_READ || state->err != Z_OK)
+ return -1;
+
+ /* back up and start over */
+ if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
+ return -1;
+ gz_reset(state);
+ return 0;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzseek64(file, offset, whence)
+ gzFile file;
+ z_off64_t offset;
+ int whence;
+{
+ unsigned n;
+ z_off64_t ret;
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* check that there's no error */
+ if (state->err != Z_OK)
+ return -1;
+
+ /* can only seek from start or relative to current position */
+ if (whence != SEEK_SET && whence != SEEK_CUR)
+ return -1;
+
+ /* normalize offset to a SEEK_CUR specification */
+ if (whence == SEEK_SET)
+ offset -= state->pos;
+ else if (state->seek)
+ offset += state->skip;
+ state->seek = 0;
+
+ /* if within raw area while reading, just go there */
+ if (state->mode == GZ_READ && state->how == COPY &&
+ state->pos + offset >= state->raw) {
+ ret = LSEEK(state->fd, offset - state->have, SEEK_CUR);
+ if (ret == -1)
+ return -1;
+ state->have = 0;
+ state->eof = 0;
+ state->seek = 0;
+ gz_error(state, Z_OK, NULL);
+ state->strm.avail_in = 0;
+ state->pos += offset;
+ return state->pos;
+ }
+
+ /* calculate skip amount, rewinding if needed for back seek when reading */
+ if (offset < 0) {
+ if (state->mode != GZ_READ) /* writing -- can't go backwards */
+ return -1;
+ offset += state->pos;
+ if (offset < 0) /* before start of file! */
+ return -1;
+ if (gzrewind(file) == -1) /* rewind, then skip to offset */
+ return -1;
+ }
+
+ /* if reading, skip what's in output buffer (one less gzgetc() check) */
+ if (state->mode == GZ_READ) {
+ n = GT_OFF(state->have) || (z_off64_t)state->have > offset ?
+ (unsigned)offset : state->have;
+ state->have -= n;
+ state->next += n;
+ state->pos += n;
+ offset -= n;
+ }
+
+ /* request skip (if not zero) */
+ if (offset) {
+ state->seek = 1;
+ state->skip = offset;
+ }
+ return state->pos + offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzseek(file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ z_off64_t ret;
+
+ ret = gzseek64(file, (z_off64_t)offset, whence);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gztell64(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* return position */
+ return state->pos + (state->seek ? state->skip : 0);
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gztell(file)
+ gzFile file;
+{
+ z_off64_t ret;
+
+ ret = gztell64(file);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzoffset64(file)
+ gzFile file;
+{
+ z_off64_t offset;
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return -1;
+
+ /* compute and return effective offset in file */
+ offset = LSEEK(state->fd, 0, SEEK_CUR);
+ if (offset == -1)
+ return -1;
+ if (state->mode == GZ_READ) /* reading */
+ offset -= state->strm.avail_in; /* don't count buffered input */
+ return offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzoffset(file)
+ gzFile file;
+{
+ z_off64_t ret;
+
+ ret = gzoffset64(file);
+ return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzeof(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return 0;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return 0;
+
+ /* return end-of-file state */
+ return state->mode == GZ_READ ?
+ (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0;
+}
+
+/* -- see zlib.h -- */
+const char * ZEXPORT gzerror(file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return NULL;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return NULL;
+
+ /* return error information */
+ if (errnum != NULL)
+ *errnum = state->err;
+ return state->msg == NULL ? "" : state->msg;
+}
+
+/* -- see zlib.h -- */
+void ZEXPORT gzclearerr(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure and check integrity */
+ if (file == NULL)
+ return;
+ state = (gz_statep)file;
+ if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+ return;
+
+ /* clear error and end-of-file */
+ if (state->mode == GZ_READ)
+ state->eof = 0;
+ gz_error(state, Z_OK, NULL);
+}
+
+/* Create an error message in allocated memory and set state->err and
+ state->msg accordingly. Free any previous error message already there. Do
+ not try to free or allocate space if the error is Z_MEM_ERROR (out of
+ memory). Simply save the error message as a static string. If there is an
+ allocation failure constructing the error message, then convert the error to
+ out of memory. */
+void ZLIB_INTERNAL gz_error(state, err, msg)
+ gz_statep state;
+ int err;
+ const char *msg;
+{
+ /* free previously allocated message and clear */
+ if (state->msg != NULL) {
+ if (state->err != Z_MEM_ERROR)
+ free(state->msg);
+ state->msg = NULL;
+ }
+
+ /* set error code, and if no message, then done */
+ state->err = err;
+ if (msg == NULL)
+ return;
+
+ /* for an out of memory error, save as static string */
+ if (err == Z_MEM_ERROR) {
+ state->msg = (char *)msg;
+ return;
+ }
+
+ /* construct error message with path */
+ if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
+ state->err = Z_MEM_ERROR;
+ state->msg = (char *)"out of memory";
+ return;
+ }
+ strcpy(state->msg, state->path);
+ strcat(state->msg, ": ");
+ strcat(state->msg, msg);
+ return;
+}
+
+#ifndef INT_MAX
+/* portably return maximum value for an int (when limits.h presumed not
+ available) -- we need to do this to cover cases where 2's complement not
+ used, since C standard permits 1's complement and sign-bit representations,
+ otherwise we could just use ((unsigned)-1) >> 1 */
+unsigned ZLIB_INTERNAL gz_intmax()
+{
+ unsigned p, q;
+
+ p = 1;
+ do {
+ q = p;
+ p <<= 1;
+ p++;
+ } while (p > q);
+ return q >> 1;
+}
+#endif
diff --git a/test/monniaux/glpk-4.65/src/zlib/gzread.c b/test/monniaux/glpk-4.65/src/zlib/gzread.c
new file mode 100644
index 00000000..548201ab
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/gzread.c
@@ -0,0 +1,653 @@
+/* gzread.c -- zlib functions for reading gzip files
+ * Copyright (C) 2004, 2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
+local int gz_avail OF((gz_statep));
+local int gz_next4 OF((gz_statep, unsigned long *));
+local int gz_head OF((gz_statep));
+local int gz_decomp OF((gz_statep));
+local int gz_make OF((gz_statep));
+local int gz_skip OF((gz_statep, z_off64_t));
+
+/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
+ state->fd, and update state->eof, state->err, and state->msg as appropriate.
+ This function needs to loop on read(), since read() is not guaranteed to
+ read the number of bytes requested, depending on the type of descriptor. */
+local int gz_load(state, buf, len, have)
+ gz_statep state;
+ unsigned char *buf;
+ unsigned len;
+ unsigned *have;
+{
+ int ret;
+
+ *have = 0;
+ do {
+ ret = read(state->fd, buf + *have, len - *have);
+ if (ret <= 0)
+ break;
+ *have += ret;
+ } while (*have < len);
+ if (ret < 0) {
+ gz_error(state, Z_ERRNO, zstrerror());
+ return -1;
+ }
+ if (ret == 0)
+ state->eof = 1;
+ return 0;
+}
+
+/* Load up input buffer and set eof flag if last data loaded -- return -1 on
+ error, 0 otherwise. Note that the eof flag is set when the end of the input
+ file is reached, even though there may be unused data in the buffer. Once
+ that data has been used, no more attempts will be made to read the file.
+ gz_avail() assumes that strm->avail_in == 0. */
+local int gz_avail(state)
+ gz_statep state;
+{
+ z_streamp strm = &(state->strm);
+
+ if (state->err != Z_OK)
+ return -1;
+ if (state->eof == 0) {
+ if (gz_load(state, state->in, state->size,
+ (unsigned *)&(strm->avail_in)) == -1)
+ return -1;
+ strm->next_in = state->in;
+ }
+ return 0;
+}
+
+/* Get next byte from input, or -1 if end or error. */
+#define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \
+ (strm->avail_in == 0 ? -1 : \
+ (strm->avail_in--, *(strm->next_in)++)))
+
+/* Get a four-byte little-endian integer and return 0 on success and the value
+ in *ret. Otherwise -1 is returned and *ret is not modified. */
+local int gz_next4(state, ret)
+ gz_statep state;
+ unsigned long *ret;
+{
+ int ch;
+ unsigned long val;
+ z_streamp strm = &(state->strm);
+
+ val = NEXT();
+ val += (unsigned)NEXT() << 8;
+ val += (unsigned long)NEXT() << 16;
+ ch = NEXT();
+ if (ch == -1)
+ return -1;
+ val += (unsigned long)ch << 24;
+ *ret = val;
+ return 0;
+}
+
+/* Look for gzip header, set up for inflate or copy. state->have must be zero.
+ If this is the first time in, allocate required memory. state->how will be
+ left unchanged if there is no more input data available, will be set to COPY
+ if there is no gzip header and direct copying will be performed, or it will
+ be set to GZIP for decompression, and the gzip header will be skipped so
+ that the next available input data is the raw deflate stream. If direct
+ copying, then leftover input data from the input buffer will be copied to
+ the output buffer. In that case, all further file reads will be directly to
+ either the output buffer or a user buffer. If decompressing, the inflate
+ state and the check value will be initialized. gz_head() will return 0 on
+ success or -1 on failure. Failures may include read errors or gzip header
+ errors. */
+local int gz_head(state)
+ gz_statep state;
+{
+ z_streamp strm = &(state->strm);
+ int flags;
+ unsigned len;
+
+ /* allocate read buffers and inflate memory */
+ if (state->size == 0) {
+ /* allocate buffers */
+ state->in = malloc(state->want);
+ state->out = malloc(state->want << 1);
+ if (state->in == NULL || state->out == NULL) {
+ if (state->out != NULL)
+ free(state->out);
+ if (state->in != NULL)
+ free(state->in);
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ state->size = state->want;
+
+ /* allocate inflate memory */
+ state->strm.zalloc = Z_NULL;
+ state->strm.zfree = Z_NULL;
+ state->strm.opaque = Z_NULL;
+ state->strm.avail_in = 0;
+ state->strm.next_in = Z_NULL;
+ if (inflateInit2(&(state->strm), -15) != Z_OK) { /* raw inflate */
+ free(state->out);
+ free(state->in);
+ state->size = 0;
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ }
+
+ /* get some data in the input buffer */
+ if (strm->avail_in == 0) {
+ if (gz_avail(state) == -1)
+ return -1;
+ if (strm->avail_in == 0)
+ return 0;
+ }
+
+ /* look for the gzip magic header bytes 31 and 139 */
+ if (strm->next_in[0] == 31) {
+ strm->avail_in--;
+ strm->next_in++;
+ if (strm->avail_in == 0 && gz_avail(state) == -1)
+ return -1;
+ if (strm->avail_in && strm->next_in[0] == 139) {
+ /* we have a gzip header, woo hoo! */
+ strm->avail_in--;
+ strm->next_in++;
+
+ /* skip rest of header */
+ if (NEXT() != 8) { /* compression method */
+ gz_error(state, Z_DATA_ERROR, "unknown compression method");
+ return -1;
+ }
+ flags = NEXT();
+ if (flags & 0xe0) { /* reserved flag bits */
+ gz_error(state, Z_DATA_ERROR, "unknown header flags set");
+ return -1;
+ }
+ NEXT(); /* modification time */
+ NEXT();
+ NEXT();
+ NEXT();
+ NEXT(); /* extra flags */
+ NEXT(); /* operating system */
+ if (flags & 4) { /* extra field */
+ len = (unsigned)NEXT();
+ len += (unsigned)NEXT() << 8;
+ while (len--)
+ if (NEXT() < 0)
+ break;
+ }
+ if (flags & 8) /* file name */
+ while (NEXT() > 0)
+ ;
+ if (flags & 16) /* comment */
+ while (NEXT() > 0)
+ ;
+ if (flags & 2) { /* header crc */
+ NEXT();
+ NEXT();
+ }
+ /* an unexpected end of file is not checked for here -- it will be
+ noticed on the first request for uncompressed data */
+
+ /* set up for decompression */
+ inflateReset(strm);
+ strm->adler = crc32(0L, Z_NULL, 0);
+ state->how = GZIP;
+ state->direct = 0;
+ return 0;
+ }
+ else {
+ /* not a gzip file -- save first byte (31) and fall to raw i/o */
+ state->out[0] = 31;
+ state->have = 1;
+ }
+ }
+
+ /* doing raw i/o, save start of raw data for seeking, copy any leftover
+ input to output -- this assumes that the output buffer is larger than
+ the input buffer, which also assures space for gzungetc() */
+ state->raw = state->pos;
+ state->next = state->out;
+ if (strm->avail_in) {
+ memcpy(state->next + state->have, strm->next_in, strm->avail_in);
+ state->have += strm->avail_in;
+ strm->avail_in = 0;
+ }
+ state->how = COPY;
+ state->direct = 1;
+ return 0;
+}
+
+/* Decompress from input to the provided next_out and avail_out in the state.
+ If the end of the compressed data is reached, then verify the gzip trailer
+ check value and length (modulo 2^32). state->have and state->next are set
+ to point to the just decompressed data, and the crc is updated. If the
+ trailer is verified, state->how is reset to LOOK to look for the next gzip
+ stream or raw data, once state->have is depleted. Returns 0 on success, -1
+ on failure. Failures may include invalid compressed data or a failed gzip
+ trailer verification. */
+local int gz_decomp(state)
+ gz_statep state;
+{
+ int ret;
+ unsigned had;
+ unsigned long crc, len;
+ z_streamp strm = &(state->strm);
+
+ /* fill output buffer up to end of deflate stream */
+ had = strm->avail_out;
+ do {
+ /* get more input for inflate() */
+ if (strm->avail_in == 0 && gz_avail(state) == -1)
+ return -1;
+ if (strm->avail_in == 0) {
+ gz_error(state, Z_DATA_ERROR, "unexpected end of file");
+ return -1;
+ }
+
+ /* decompress and handle errors */
+ ret = inflate(strm, Z_NO_FLUSH);
+ if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
+ gz_error(state, Z_STREAM_ERROR,
+ "internal error: inflate stream corrupt");
+ return -1;
+ }
+ if (ret == Z_MEM_ERROR) {
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+ if (ret == Z_DATA_ERROR) { /* deflate stream invalid */
+ gz_error(state, Z_DATA_ERROR,
+ strm->msg == NULL ? "compressed data error" : strm->msg);
+ return -1;
+ }
+ } while (strm->avail_out && ret != Z_STREAM_END);
+
+ /* update available output and crc check value */
+ state->have = had - strm->avail_out;
+ state->next = strm->next_out - state->have;
+ strm->adler = crc32(strm->adler, state->next, state->have);
+
+ /* check gzip trailer if at end of deflate stream */
+ if (ret == Z_STREAM_END) {
+ if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) {
+ gz_error(state, Z_DATA_ERROR, "unexpected end of file");
+ return -1;
+ }
+ if (crc != strm->adler) {
+ gz_error(state, Z_DATA_ERROR, "incorrect data check");
+ return -1;
+ }
+ if (len != (strm->total_out & 0xffffffffL)) {
+ gz_error(state, Z_DATA_ERROR, "incorrect length check");
+ return -1;
+ }
+ state->how = LOOK; /* ready for next stream, once have is 0 (leave
+ state->direct unchanged to remember how) */
+ }
+
+ /* good decompression */
+ return 0;
+}
+
+/* Make data and put in the output buffer. Assumes that state->have == 0.
+ Data is either copied from the input file or decompressed from the input
+ file depending on state->how. If state->how is LOOK, then a gzip header is
+ looked for (and skipped if found) to determine wither to copy or decompress.
+ Returns -1 on error, otherwise 0. gz_make() will leave state->have as COPY
+ or GZIP unless the end of the input file has been reached and all data has
+ been processed. */
+local int gz_make(state)
+ gz_statep state;
+{
+ z_streamp strm = &(state->strm);
+
+ if (state->how == LOOK) { /* look for gzip header */
+ if (gz_head(state) == -1)
+ return -1;
+ if (state->have) /* got some data from gz_head() */
+ return 0;
+ }
+ if (state->how == COPY) { /* straight copy */
+ if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1)
+ return -1;
+ state->next = state->out;
+ }
+ else if (state->how == GZIP) { /* decompress */
+ strm->avail_out = state->size << 1;
+ strm->next_out = state->out;
+ if (gz_decomp(state) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
+local int gz_skip(state, len)
+ gz_statep state;
+ z_off64_t len;
+{
+ unsigned n;
+
+ /* skip over len bytes or reach end-of-file, whichever comes first */
+ while (len)
+ /* skip over whatever is in output buffer */
+ if (state->have) {
+ n = GT_OFF(state->have) || (z_off64_t)state->have > len ?
+ (unsigned)len : state->have;
+ state->have -= n;
+ state->next += n;
+ state->pos += n;
+ len -= n;
+ }
+
+ /* output buffer empty -- return if we're at the end of the input */
+ else if (state->eof && state->strm.avail_in == 0)
+ break;
+
+ /* need more data to skip -- load up output buffer */
+ else {
+ /* get more output, looking for header if required */
+ if (gz_make(state) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzread(file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ unsigned got, n;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're reading and that there's no error */
+ if (state->mode != GZ_READ || state->err != Z_OK)
+ return -1;
+
+ /* since an int is returned, make sure len fits in one, otherwise return
+ with an error (this avoids the flaw in the interface) */
+ if ((int)len < 0) {
+ gz_error(state, Z_BUF_ERROR, "requested length does not fit in int");
+ return -1;
+ }
+
+ /* if len is zero, avoid unnecessary operations */
+ if (len == 0)
+ return 0;
+
+ /* process a skip request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_skip(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* get len bytes to buf, or less than len if at the end */
+ got = 0;
+ do {
+ /* first just try copying data from the output buffer */
+ if (state->have) {
+ n = state->have > len ? len : state->have;
+ memcpy(buf, state->next, n);
+ state->next += n;
+ state->have -= n;
+ }
+
+ /* output buffer empty -- return if we're at the end of the input */
+ else if (state->eof && strm->avail_in == 0)
+ break;
+
+ /* need output data -- for small len or new stream load up our output
+ buffer */
+ else if (state->how == LOOK || len < (state->size << 1)) {
+ /* get more output, looking for header if required */
+ if (gz_make(state) == -1)
+ return -1;
+ continue; /* no progress yet -- go back to memcpy() above */
+ /* the copy above assures that we will leave with space in the
+ output buffer, allowing at least one gzungetc() to succeed */
+ }
+
+ /* large len -- read directly into user buffer */
+ else if (state->how == COPY) { /* read directly */
+ if (gz_load(state, buf, len, &n) == -1)
+ return -1;
+ }
+
+ /* large len -- decompress directly into user buffer */
+ else { /* state->how == GZIP */
+ strm->avail_out = len;
+ strm->next_out = buf;
+ if (gz_decomp(state) == -1)
+ return -1;
+ n = state->have;
+ state->have = 0;
+ }
+
+ /* update progress */
+ len -= n;
+ buf = (char *)buf + n;
+ got += n;
+ state->pos += n;
+ } while (len);
+
+ /* return number of bytes read into user buffer (will fit in int) */
+ return (int)got;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ int ret;
+ unsigned char buf[1];
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no error */
+ if (state->mode != GZ_READ || state->err != Z_OK)
+ return -1;
+
+ /* try output buffer (no need to check for skip request) */
+ if (state->have) {
+ state->have--;
+ state->pos++;
+ return *(state->next)++;
+ }
+
+ /* nothing there -- try gzread() */
+ ret = gzread(file, buf, 1);
+ return ret < 1 ? -1 : buf[0];
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzungetc(c, file)
+ int c;
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no error */
+ if (state->mode != GZ_READ || state->err != Z_OK)
+ return -1;
+
+ /* process a skip request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_skip(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* can't push EOF */
+ if (c < 0)
+ return -1;
+
+ /* if output buffer empty, put byte at end (allows more pushing) */
+ if (state->have == 0) {
+ state->have = 1;
+ state->next = state->out + (state->size << 1) - 1;
+ state->next[0] = c;
+ state->pos--;
+ return c;
+ }
+
+ /* if no room, give up (must have already done a gzungetc()) */
+ if (state->have == (state->size << 1)) {
+ gz_error(state, Z_BUF_ERROR, "out of room to push characters");
+ return -1;
+ }
+
+ /* slide output data if needed and insert byte before existing data */
+ if (state->next == state->out) {
+ unsigned char *src = state->out + state->have;
+ unsigned char *dest = state->out + (state->size << 1);
+ while (src > state->out)
+ *--dest = *--src;
+ state->next = dest;
+ }
+ state->have++;
+ state->next--;
+ state->next[0] = c;
+ state->pos--;
+ return c;
+}
+
+/* -- see zlib.h -- */
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ unsigned left, n;
+ char *str;
+ unsigned char *eol;
+ gz_statep state;
+
+ /* check parameters and get internal structure */
+ if (file == NULL || buf == NULL || len < 1)
+ return NULL;
+ state = (gz_statep)file;
+
+ /* check that we're reading and that there's no error */
+ if (state->mode != GZ_READ || state->err != Z_OK)
+ return NULL;
+
+ /* process a skip request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_skip(state, state->skip) == -1)
+ return NULL;
+ }
+
+ /* copy output bytes up to new line or len - 1, whichever comes first --
+ append a terminating zero to the string (we don't check for a zero in
+ the contents, let the user worry about that) */
+ str = buf;
+ left = (unsigned)len - 1;
+ if (left) do {
+ /* assure that something is in the output buffer */
+ if (state->have == 0) {
+ if (gz_make(state) == -1)
+ return NULL; /* error */
+ if (state->have == 0) { /* end of file */
+ if (buf == str) /* got bupkus */
+ return NULL;
+ break; /* got something -- return it */
+ }
+ }
+
+ /* look for end-of-line in current output buffer */
+ n = state->have > left ? left : state->have;
+ eol = memchr(state->next, '\n', n);
+ if (eol != NULL)
+ n = (unsigned)(eol - state->next) + 1;
+
+ /* copy through end-of-line, or remainder if not found */
+ memcpy(buf, state->next, n);
+ state->have -= n;
+ state->next += n;
+ state->pos += n;
+ left -= n;
+ buf += n;
+ } while (left && eol == NULL);
+
+ /* found end-of-line or out of space -- terminate string and return it */
+ buf[0] = 0;
+ return str;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzdirect(file)
+ gzFile file;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return 0;
+ state = (gz_statep)file;
+
+ /* check that we're reading */
+ if (state->mode != GZ_READ)
+ return 0;
+
+ /* if the state is not known, but we can find out, then do so (this is
+ mainly for right after a gzopen() or gzdopen()) */
+ if (state->how == LOOK && state->have == 0)
+ (void)gz_head(state);
+
+ /* return 1 if reading direct, 0 if decompressing a gzip stream */
+ return state->direct;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_r(file)
+ gzFile file;
+{
+ int ret;
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ /* check that we're reading */
+ if (state->mode != GZ_READ)
+ return Z_STREAM_ERROR;
+
+ /* free memory and close file */
+ if (state->size) {
+ inflateEnd(&(state->strm));
+ free(state->out);
+ free(state->in);
+ }
+ gz_error(state, Z_OK, NULL);
+ free(state->path);
+ ret = close(state->fd);
+ free(state);
+ return ret ? Z_ERRNO : Z_OK;
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/gzwrite.c b/test/monniaux/glpk-4.65/src/zlib/gzwrite.c
new file mode 100644
index 00000000..13c5558e
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/gzwrite.c
@@ -0,0 +1,531 @@
+/* gzwrite.c -- zlib functions for writing gzip files
+ * Copyright (C) 2004, 2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_init OF((gz_statep));
+local int gz_comp OF((gz_statep, int));
+local int gz_zero OF((gz_statep, z_off64_t));
+
+/* Initialize state for writing a gzip file. Mark initialization by setting
+ state->size to non-zero. Return -1 on failure or 0 on success. */
+local int gz_init(state)
+ gz_statep state;
+{
+ int ret;
+ z_streamp strm = &(state->strm);
+
+ /* allocate input and output buffers */
+ state->in = malloc(state->want);
+ state->out = malloc(state->want);
+ if (state->in == NULL || state->out == NULL) {
+ if (state->out != NULL)
+ free(state->out);
+ if (state->in != NULL)
+ free(state->in);
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+
+ /* allocate deflate memory, set up for gzip compression */
+ strm->zalloc = Z_NULL;
+ strm->zfree = Z_NULL;
+ strm->opaque = Z_NULL;
+ ret = deflateInit2(strm, state->level, Z_DEFLATED,
+ 15 + 16, 8, state->strategy);
+ if (ret != Z_OK) {
+ free(state->in);
+ gz_error(state, Z_MEM_ERROR, "out of memory");
+ return -1;
+ }
+
+ /* mark state as initialized */
+ state->size = state->want;
+
+ /* initialize write buffer */
+ strm->avail_out = state->size;
+ strm->next_out = state->out;
+ state->next = strm->next_out;
+ return 0;
+}
+
+/* Compress whatever is at avail_in and next_in and write to the output file.
+ Return -1 if there is an error writing to the output file, otherwise 0.
+ flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH,
+ then the deflate() state is reset to start a new gzip stream. */
+local int gz_comp(state, flush)
+ gz_statep state;
+ int flush;
+{
+ int ret, got;
+ unsigned have;
+ z_streamp strm = &(state->strm);
+
+ /* allocate memory if this is the first time through */
+ if (state->size == 0 && gz_init(state) == -1)
+ return -1;
+
+ /* run deflate() on provided input until it produces no more output */
+ ret = Z_OK;
+ do {
+ /* write out current buffer contents if full, or if flushing, but if
+ doing Z_FINISH then don't write until we get to Z_STREAM_END */
+ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
+ (flush != Z_FINISH || ret == Z_STREAM_END))) {
+ have = (unsigned)(strm->next_out - state->next);
+ if (have && ((got = write(state->fd, state->next, have)) < 0 ||
+ (unsigned)got != have)) {
+ gz_error(state, Z_ERRNO, zstrerror());
+ return -1;
+ }
+ if (strm->avail_out == 0) {
+ strm->avail_out = state->size;
+ strm->next_out = state->out;
+ }
+ state->next = strm->next_out;
+ }
+
+ /* compress */
+ have = strm->avail_out;
+ ret = deflate(strm, flush);
+ if (ret == Z_STREAM_ERROR) {
+ gz_error(state, Z_STREAM_ERROR,
+ "internal error: deflate stream corrupt");
+ return -1;
+ }
+ have -= strm->avail_out;
+ } while (have);
+
+ /* if that completed a deflate stream, allow another to start */
+ if (flush == Z_FINISH)
+ deflateReset(strm);
+
+ /* all done, no errors */
+ return 0;
+}
+
+/* Compress len zeros to output. Return -1 on error, 0 on success. */
+local int gz_zero(state, len)
+ gz_statep state;
+ z_off64_t len;
+{
+ int first;
+ unsigned n;
+ z_streamp strm = &(state->strm);
+
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return -1;
+
+ /* compress len zeros (len guaranteed > 0) */
+ first = 1;
+ while (len) {
+ n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
+ (unsigned)len : state->size;
+ if (first) {
+ memset(state->in, 0, n);
+ first = 0;
+ }
+ strm->avail_in = n;
+ strm->next_in = state->in;
+ state->pos += n;
+ if (gz_comp(state, Z_NO_FLUSH) == -1)
+ return -1;
+ len -= n;
+ }
+ return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzwrite(file, buf, len)
+ gzFile file;
+ voidpc buf;
+ unsigned len;
+{
+ unsigned put = len;
+ unsigned n;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return 0;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return 0;
+
+ /* since an int is returned, make sure len fits in one, otherwise return
+ with an error (this avoids the flaw in the interface) */
+ if ((int)len < 0) {
+ gz_error(state, Z_BUF_ERROR, "requested length does not fit in int");
+ return 0;
+ }
+
+ /* if len is zero, avoid unnecessary operations */
+ if (len == 0)
+ return 0;
+
+ /* allocate memory if this is the first time through */
+ if (state->size == 0 && gz_init(state) == -1)
+ return 0;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return 0;
+ }
+
+ /* for small len, copy to input buffer, otherwise compress directly */
+ if (len < state->size) {
+ /* copy to input buffer, compress when full */
+ do {
+ if (strm->avail_in == 0)
+ strm->next_in = state->in;
+ n = state->size - strm->avail_in;
+ if (n > len)
+ n = len;
+ memcpy(strm->next_in + strm->avail_in, buf, n);
+ strm->avail_in += n;
+ state->pos += n;
+ buf = (char *)buf + n;
+ len -= n;
+ if (len && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+ } while (len);
+ }
+ else {
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+
+ /* directly compress user buffer to file */
+ strm->avail_in = len;
+ strm->next_in = (voidp)buf;
+ state->pos += len;
+ if (gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+ }
+
+ /* input was all buffered or compressed (put will fit in int) */
+ return (int)put;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned char buf[1];
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return -1;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* try writing to input buffer for speed (state->size == 0 if buffer not
+ initialized) */
+ if (strm->avail_in < state->size) {
+ if (strm->avail_in == 0)
+ strm->next_in = state->in;
+ strm->next_in[strm->avail_in++] = c;
+ state->pos++;
+ return c;
+ }
+
+ /* no room in buffer or not initialized, use gz_write() */
+ buf[0] = c;
+ if (gzwrite(file, buf, 1) != 1)
+ return -1;
+ return c;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputs(file, str)
+ gzFile file;
+ const char *str;
+{
+ int ret;
+ unsigned len;
+
+ /* write string */
+ len = (unsigned)strlen(str);
+ ret = gzwrite(file, str, len);
+ return ret == 0 && len != 0 ? -1 : ret;
+}
+
+#ifdef STDC
+#include <stdarg.h>
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzprintf (gzFile file, const char *format, ...)
+{
+ int size, len;
+ gz_statep state;
+ z_streamp strm;
+ va_list va;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return 0;
+
+ /* make sure we have some buffer space */
+ if (state->size == 0 && gz_init(state) == -1)
+ return 0;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return 0;
+ }
+
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+
+ /* do the printf() into the input buffer, put length in len */
+ size = (int)(state->size);
+ state->in[size - 1] = 0;
+ va_start(va, format);
+#ifdef NO_vsnprintf
+# ifdef HAS_vsprintf_void
+ (void)vsprintf(state->in, format, va);
+ va_end(va);
+ for (len = 0; len < size; len++)
+ if (state->in[len] == 0) break;
+# else
+ len = vsprintf((char *)state->in, format, va);
+ va_end(va);
+# endif
+#else
+# ifdef HAS_vsnprintf_void
+ (void)vsnprintf(state->in, size, format, va);
+ va_end(va);
+ len = strlen(state->in);
+# else
+ len = vsnprintf((char *)(state->in), size, format, va);
+ va_end(va);
+# endif
+#endif
+
+ /* check that printf() results fit in buffer */
+ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
+ return 0;
+
+ /* update buffer and position, defer compression until needed */
+ strm->avail_in = (unsigned)len;
+ strm->next_in = state->in;
+ state->pos += len;
+ return len;
+}
+
+#else /* !STDC */
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ int size, len;
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return 0;
+
+ /* make sure we have some buffer space */
+ if (state->size == 0 && gz_init(state) == -1)
+ return 0;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return 0;
+ }
+
+ /* consume whatever's left in the input buffer */
+ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+ return 0;
+
+ /* do the printf() into the input buffer, put length in len */
+ size = (int)(state->size);
+ state->in[size - 1] = 0;
+#ifdef NO_snprintf
+# ifdef HAS_sprintf_void
+ sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ for (len = 0; len < size; len++)
+ if (state->in[len] == 0) break;
+# else
+ len = sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#else
+# ifdef HAS_snprintf_void
+ snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ len = strlen(state->in);
+# else
+ len = snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#endif
+
+ /* check that printf() results fit in buffer */
+ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
+ return 0;
+
+ /* update buffer and position, defer compression until needed */
+ strm->avail_in = (unsigned)len;
+ strm->next_in = state->in;
+ state->pos += len;
+ return len;
+}
+
+#endif
+
+/* -- see zlib.h -- */
+int ZEXPORT gzflush(file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return -1;
+ state = (gz_statep)file;
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return Z_STREAM_ERROR;
+
+ /* check flush parameter */
+ if (flush < 0 || flush > Z_FINISH)
+ return Z_STREAM_ERROR;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* compress remaining data with requested flush */
+ gz_comp(state, flush);
+ return state->err;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzsetparams(file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_statep state;
+ z_streamp strm;
+
+ /* get internal structure */
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+ strm = &(state->strm);
+
+ /* check that we're writing and that there's no error */
+ if (state->mode != GZ_WRITE || state->err != Z_OK)
+ return Z_STREAM_ERROR;
+
+ /* if no change is requested, then do nothing */
+ if (level == state->level && strategy == state->strategy)
+ return Z_OK;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ if (gz_zero(state, state->skip) == -1)
+ return -1;
+ }
+
+ /* change compression parameters for subsequent input */
+ if (state->size) {
+ /* flush previous input with previous parameters before changing */
+ if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1)
+ return state->err;
+ deflateParams(strm, level, strategy);
+ }
+ state->level = level;
+ state->strategy = strategy;
+ return Z_OK;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_w(file)
+ gzFile file;
+{
+ int ret = 0;
+ gz_statep state;
+
+ /* get internal structure */
+ if (file == NULL)
+ return Z_STREAM_ERROR;
+ state = (gz_statep)file;
+
+ /* check that we're writing */
+ if (state->mode != GZ_WRITE)
+ return Z_STREAM_ERROR;
+
+ /* check for seek request */
+ if (state->seek) {
+ state->seek = 0;
+ ret += gz_zero(state, state->skip);
+ }
+
+ /* flush, free memory, and close file */
+ ret += gz_comp(state, Z_FINISH);
+ (void)deflateEnd(&(state->strm));
+ free(state->out);
+ free(state->in);
+ gz_error(state, Z_OK, NULL);
+ free(state->path);
+ ret += close(state->fd);
+ free(state);
+ return ret ? Z_ERRNO : Z_OK;
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/inffast.c b/test/monniaux/glpk-4.65/src/zlib/inffast.c
new file mode 100644
index 00000000..2f1d60b4
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/inffast.c
@@ -0,0 +1,340 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2008, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void ZLIB_INTERNAL inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *in; /* local strm->next_in */
+ unsigned char FAR *last; /* while in < last, enough input available */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned wnext; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code here; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ wnext = state->wnext;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ here = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(here.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(here.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ PUP(out) = (unsigned char)(here.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(here.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ here = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(here.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(here.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(here.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ if (state->sane) {
+ strm->msg =
+ (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ if (len <= op - whave) {
+ do {
+ PUP(out) = 0;
+ } while (--len);
+ continue;
+ }
+ len -= op - whave;
+ do {
+ PUP(out) = 0;
+ } while (--op > whave);
+ if (op == 0) {
+ from = out - dist;
+ do {
+ PUP(out) = PUP(from);
+ } while (--len);
+ continue;
+ }
+#endif
+ }
+ from = window - OFF;
+ if (wnext == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (wnext < op) { /* wrap around window */
+ from += wsize + wnext - op;
+ op -= wnext;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (wnext < len) { /* some from start of window */
+ op = wnext;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += wnext - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ here = dcode[here.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ here = lcode[here.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and wnext == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/test/monniaux/glpk-4.65/src/zlib/inffast.h b/test/monniaux/glpk-4.65/src/zlib/inffast.h
new file mode 100644
index 00000000..e5c1aa4c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/test/monniaux/glpk-4.65/src/zlib/inffixed.h b/test/monniaux/glpk-4.65/src/zlib/inffixed.h
new file mode 100644
index 00000000..75ed4b59
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications. It
+ is part of the implementation of the compression library and
+ is subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/test/monniaux/glpk-4.65/src/zlib/inflate.c b/test/monniaux/glpk-4.65/src/zlib/inflate.c
new file mode 100644
index 00000000..a8431abe
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/inflate.c
@@ -0,0 +1,1480 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common wnext == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ strm->adler = 1; /* to support ill-conceived Java test suite */
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->wsize = 0;
+ state->whave = 0;
+ state->wnext = 0;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ state->sane = 1;
+ state->back = -1;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateReset2(strm, windowBits)
+z_streamp strm;
+int windowBits;
+{
+ int wrap;
+ struct inflate_state FAR *state;
+
+ /* get the state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* extract wrap request from windowBits parameter */
+ if (windowBits < 0) {
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48)
+ windowBits &= 15;
+#endif
+ }
+
+ /* set number of window bits, free window if different */
+ if (windowBits && (windowBits < 8 || windowBits > 15))
+ return Z_STREAM_ERROR;
+ if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
+ ZFREE(strm, state->window);
+ state->window = Z_NULL;
+ }
+
+ /* update state and reset the rest of it */
+ state->wrap = wrap;
+ state->wbits = (unsigned)windowBits;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ int ret;
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->window = Z_NULL;
+ ret = inflateReset2(strm, windowBits);
+ if (ret != Z_OK) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ }
+ return ret;
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits < 0) {
+ state->hold = 0;
+ state->bits = 0;
+ return Z_OK;
+ }
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+ state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+ struct inflate_state FAR *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->wnext = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->wnext = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->wnext;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->wnext, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, strm->next_out - copy, copy);
+ state->wnext = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->wnext += dist;
+ if (state->wnext == state->wsize) state->wnext = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code here; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (state->wbits == 0)
+ state->wbits = len;
+ else if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN_; /* decode codes */
+ if (flush == Z_TREES) {
+ DROPBITS(2);
+ goto inf_leave;
+ }
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY_;
+ if (flush == Z_TREES) goto inf_leave;
+ case COPY_:
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.val < 16) {
+ NEEDBITS(here.bits);
+ DROPBITS(here.bits);
+ state->lens[state->have++] = here.val;
+ }
+ else {
+ if (here.val == 16) {
+ NEEDBITS(here.bits + 2);
+ DROPBITS(here.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (here.val == 17) {
+ NEEDBITS(here.bits + 3);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(here.bits + 7);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* check for end-of-block code (better have one) */
+ if (state->lens[256] == 0) {
+ strm->msg = (char *)"invalid code -- missing end-of-block";
+ state->mode = BAD;
+ break;
+ }
+
+ /* build code tables -- note: do not change the lenbits or distbits
+ values here (9 and 6) without reading the comments in inftrees.h
+ concerning the ENOUGH constants, which depend on those values */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN_;
+ if (flush == Z_TREES) goto inf_leave;
+ case LEN_:
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ if (state->mode == TYPE)
+ state->back = -1;
+ break;
+ }
+ state->back = 0;
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.op && (here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ state->back += last.bits;
+ }
+ DROPBITS(here.bits);
+ state->back += here.bits;
+ state->length = (unsigned)here.val;
+ if ((int)(here.op) == 0) {
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ state->mode = LIT;
+ break;
+ }
+ if (here.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->back = -1;
+ state->mode = TYPE;
+ break;
+ }
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(here.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ state->back += state->extra;
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->was = state->length;
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ here = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ state->back += last.bits;
+ }
+ DROPBITS(here.bits);
+ state->back += here.bits;
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)here.val;
+ state->extra = (unsigned)(here.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ state->back += state->extra;
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->whave) {
+ if (state->sane) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ Trace((stderr, "inflate.c too far\n"));
+ copy -= state->whave;
+ if (copy > state->length) copy = state->length;
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = 0;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+#endif
+ }
+ if (copy > state->wnext) {
+ copy -= state->wnext;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->wnext - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ if (updatewindow(strm, out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0) +
+ (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ if (state->mode == DICT) {
+ id = adler32(0L, Z_NULL, 0);
+ id = adler32(id, dictionary, dictLength);
+ if (id != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window */
+ if (updatewindow(strm, strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ if (dictLength > state->wsize) {
+ zmemcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ zmemcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy(dest, source, sizeof(z_stream));
+ zmemcpy(copy, state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
+
+int ZEXPORT inflateUndermine(strm, subvert)
+z_streamp strm;
+int subvert;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ state->sane = !subvert;
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ return Z_OK;
+#else
+ state->sane = 1;
+ return Z_DATA_ERROR;
+#endif
+}
+
+long ZEXPORT inflateMark(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16;
+ state = (struct inflate_state FAR *)strm->state;
+ return ((long)(state->back) << 16) +
+ (state->mode == COPY ? state->length :
+ (state->mode == MATCH ? state->was - state->length : 0));
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/inflate.h b/test/monniaux/glpk-4.65/src/zlib/inflate.h
new file mode 100644
index 00000000..95f4986d
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/inflate.h
@@ -0,0 +1,122 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY_, /* i/o: same as COPY below, but only first time in */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN_, /* i: same as LEN below, but only first time in */
+ LEN, /* i: waiting for length/lit/eob code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to BAD or MEM on error -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib) or (raw)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
+ HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ (raw) -> TYPEDO
+ Read deflate blocks:
+ TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
+ STORED -> COPY_ -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN_
+ LEN_ -> LEN
+ Read deflate codes in fixed or dynamic block:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 10K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned wnext; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+ int sane; /* if false, allow invalid distance too far */
+ int back; /* bits back of last unprocessed length/lit */
+ unsigned was; /* initial length of match */
+};
diff --git a/test/monniaux/glpk-4.65/src/zlib/inftrees.c b/test/monniaux/glpk-4.65/src/zlib/inftrees.c
new file mode 100644
index 00000000..11e9c52a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/inftrees.c
@@ -0,0 +1,330 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.5 Copyright 1995-2010 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code here; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ here.op = (unsigned char)64; /* invalid code marker */
+ here.bits = (unsigned char)1;
+ here.val = (unsigned short)0;
+ *(*table)++ = here; /* make a table to force an error */
+ *(*table)++ = here;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min < max; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked for LENS and DIST tables against
+ the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+ the initial root table size constants. See the comments in inftrees.h
+ for more information.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if ((type == LENS && used >= ENOUGH_LENS) ||
+ (type == DISTS && used >= ENOUGH_DISTS))
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ here.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ here.op = (unsigned char)0;
+ here.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ here.op = (unsigned char)(extra[work[sym]]);
+ here.val = base[work[sym]];
+ }
+ else {
+ here.op = (unsigned char)(32 + 64); /* end of block */
+ here.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = here;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if ((type == LENS && used >= ENOUGH_LENS) ||
+ (type == DISTS && used >= ENOUGH_DISTS))
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ here.op = (unsigned char)64; /* invalid code marker */
+ here.bits = (unsigned char)(len - drop);
+ here.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ here.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = here;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/inftrees.h b/test/monniaux/glpk-4.65/src/zlib/inftrees.h
new file mode 100644
index 00000000..baa53a0b
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/inftrees.h
@@ -0,0 +1,62 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of the dynamic table. The maximum number of code structures is
+ 1444, which is the sum of 852 for literal/length codes and 592 for distance
+ codes. These values were found by exhaustive searches using the program
+ examples/enough.c found in the zlib distribtution. The arguments to that
+ program are the number of symbols, the initial root table size, and the
+ maximum bit length of a code. "enough 286 9 15" for literal/length codes
+ returns returns 852, and "enough 30 6 15" for distance codes returns 592.
+ The initial root table size (9 or 6) is found in the fifth argument of the
+ inflate_table() calls in inflate.c and infback.c. If the root table size is
+ changed, then these maximum sizes would be need to be recalculated and
+ updated. */
+#define ENOUGH_LENS 852
+#define ENOUGH_DISTS 592
+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
+
+/* Type of code to build for inflate_table() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/test/monniaux/glpk-4.65/src/zlib/trees.c b/test/monniaux/glpk-4.65/src/zlib/trees.c
new file mode 100644
index 00000000..56e9bb1c
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/trees.c
@@ -0,0 +1,1244 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2010 Jean-loup Gailly
+ * detect_data_type() function provided freely by Cosmin Truta, 2006
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local int detect_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (ush)value << s->bi_valid;
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= (ush)value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (ush)val << s->bi_valid;\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (ush)(value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+#ifdef NO_INIT_GLOBAL_POINTERS
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+#endif
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header,
+ "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void ZLIB_INTERNAL _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int last; /* one if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void ZLIB_INTERNAL _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int last; /* one if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (s->strm->data_type == Z_UNKNOWN)
+ s->strm->data_type = detect_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, last);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+last, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+last, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (last) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*last));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ZLIB_INTERNAL _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ * a) There are no non-portable control characters belonging to the
+ * "black list" (0..6, 14..25, 28..31).
+ * b) There is at least one printable character belonging to the
+ * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ * "gray list" that is ignored in this detection algorithm:
+ * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local int detect_data_type(s)
+ deflate_state *s;
+{
+ /* black_mask is the bit mask of black-listed bytes
+ * set bits 0..6, 14..25, and 28..31
+ * 0xf3ffc07f = binary 11110011111111111100000001111111
+ */
+ unsigned long black_mask = 0xf3ffc07fUL;
+ int n;
+
+ /* Check for non-textual ("black-listed") bytes. */
+ for (n = 0; n <= 31; n++, black_mask >>= 1)
+ if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
+ return Z_BINARY;
+
+ /* Check for textual ("white-listed") bytes. */
+ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
+ || s->dyn_ltree[13].Freq != 0)
+ return Z_TEXT;
+ for (n = 32; n < LITERALS; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ return Z_TEXT;
+
+ /* There are no "black-listed" or "white-listed" bytes:
+ * this stream either is empty or has tolerated ("gray-listed") bytes only.
+ */
+ return Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/trees.h b/test/monniaux/glpk-4.65/src/zlib/trees.h
new file mode 100644
index 00000000..d35639d8
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/test/monniaux/glpk-4.65/src/zlib/uncompr.c b/test/monniaux/glpk-4.65/src/zlib/uncompr.c
new file mode 100644
index 00000000..ad98be3a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/uncompr.c
@@ -0,0 +1,59 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/test/monniaux/glpk-4.65/src/zlib/zconf.h b/test/monniaux/glpk-4.65/src/zlib/zconf.h
new file mode 100644
index 00000000..af6a4f0f
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/zconf.h
@@ -0,0 +1,168 @@
+/* zconf.h (configuration of the zlib compression library) */
+
+/* Modified by Andrew Makhorin <mao@gnu.org>, April 2011 */
+
+/* Copyright (C) 1995-2010 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in
+ * zlib.h */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h. */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/* (file adler32.c) */
+#define adler32 _glp_zlib_adler32
+#define adler32_combine _glp_zlib_adler32_combine
+#define adler32_combine64 _glp_zlib_adler32_combine64
+
+/* (file compress.c) */
+#define compress2 _glp_zlib_compress2
+#define compress _glp_zlib_compress
+#define compressBound _glp_zlib_compressBound
+
+/* (file crc32.c) */
+#define get_crc_table _glp_zlib_get_crc_table
+#define crc32 _glp_zlib_crc32
+#define crc32_combine _glp_zlib_crc32_combine
+#define crc32_combine64 _glp_zlib_crc32_combine64
+
+/* (file deflate.c) */
+#define deflateInit_ _glp_zlib_deflateInit_
+#define deflateInit2_ _glp_zlib_deflateInit2_
+#define deflateSetDictionary _glp_zlib_deflateSetDictionary
+#define deflateReset _glp_zlib_deflateReset
+#define deflateSetHeader _glp_zlib_deflateSetHeader
+#define deflatePrime _glp_zlib_deflatePrime
+#define deflateParams _glp_zlib_deflateParams
+#define deflateTune _glp_zlib_deflateTune
+#define deflateBound _glp_zlib_deflateBound
+#define deflate _glp_zlib_deflate
+#define deflateEnd _glp_zlib_deflateEnd
+#define deflateCopy _glp_zlib_deflateCopy
+#define deflate_copyright _glp_zlib_deflate_copyright
+
+/* (file gzclose.c) */
+#define gzclose _glp_zlib_gzclose
+
+/* (file gzlib.c) */
+#define gzopen _glp_zlib_gzopen
+#define gzopen64 _glp_zlib_gzopen64
+#define gzdopen _glp_zlib_gzdopen
+#define gzbuffer _glp_zlib_gzbuffer
+#define gzrewind _glp_zlib_gzrewind
+#define gzseek64 _glp_zlib_gzseek64
+#define gzseek _glp_zlib_gzseek
+#define gztell64 _glp_zlib_gztell64
+#define gztell _glp_zlib_gztell
+#define gzoffset64 _glp_zlib_gzoffset64
+#define gzoffset _glp_zlib_gzoffset
+#define gzeof _glp_zlib_gzeof
+#define gzerror _glp_zlib_gzerror
+#define gzclearerr _glp_zlib_gzclearerr
+#define gz_error _glp_zlib_gz_error
+
+/* (file gzread.c) */
+#define gzread _glp_zlib_gzread
+#define gzgetc _glp_zlib_gzgetc
+#define gzungetc _glp_zlib_gzungetc
+#define gzgets _glp_zlib_gzgets
+#define gzdirect _glp_zlib_gzdirect
+#define gzclose_r _glp_zlib_gzclose_r
+
+/* (file gzwrite.c) */
+#define gzwrite _glp_zlib_gzwrite
+#define gzputc _glp_zlib_gzputc
+#define gzputs _glp_zlib_gzputs
+#define gzprintf _glp_zlib_gzprintf
+#define gzflush _glp_zlib_gzflush
+#define gzsetparams _glp_zlib_gzsetparams
+#define gzclose_w _glp_zlib_gzclose_w
+
+/* (file infback.c) */
+#define inflateBackInit_ _glp_zlib_inflateBackInit_
+#define inflateBack _glp_zlib_inflateBack
+#define inflateBackEnd _glp_zlib_inflateBackEnd
+
+/* (file inffast.c) */
+#define inflate_fast _glp_zlib_inflate_fast
+
+/* (file inflate.c) */
+#define inflateReset _glp_zlib_inflateReset
+#define inflateReset2 _glp_zlib_inflateReset2
+#define inflateInit2_ _glp_zlib_inflateInit2_
+#define inflateInit_ _glp_zlib_inflateInit_
+#define inflatePrime _glp_zlib_inflatePrime
+#define inflate _glp_zlib_inflate
+#define inflateEnd _glp_zlib_inflateEnd
+#define inflateSetDictionary _glp_zlib_inflateSetDictionary
+#define inflateGetHeader _glp_zlib_inflateGetHeader
+#define inflateSync _glp_zlib_inflateSync
+#define inflateSyncPoint _glp_zlib_inflateSyncPoint
+#define inflateCopy _glp_zlib_inflateCopy
+#define inflateUndermine _glp_zlib_inflateUndermine
+#define inflateMark _glp_zlib_inflateMark
+
+/* (file inftrees.c) */
+#define inflate_table _glp_zlib_inflate_table
+#define inflate_copyright _glp_zlib_inflate_copyright
+
+/* (file trees.c) */
+#define _tr_init _glp_zlib_tr_init
+#define _tr_stored_block _glp_zlib_tr_stored_block
+#define _tr_align _glp_zlib_tr_align
+#define _tr_flush_block _glp_zlib_tr_flush_block
+#define _tr_tally _glp_zlib_tr_tally
+#define _dist_code _glp_zlib_dist_code
+#define _length_code _glp_zlib_length_code
+
+/* (file uncompr.c) */
+#define uncompress _glp_zlib_uncompress
+
+/* (file zutil.c) */
+#define zlibVersion _glp_zlib_zlibVersion
+#define zlibCompileFlags _glp_zlib_zlibCompileFlags
+#define zError _glp_zlib_zError
+#define zcalloc _glp_zlib_zcalloc
+#define zcfree _glp_zlib_zcfree
+#define z_errmsg _glp_zlib_z_errmsg
+
+#define STDC 1
+
+#define MAX_MEM_LEVEL 9
+
+#define MAX_WBITS 15
+
+#define OF(args) args
+
+#define ZEXTERN extern
+#define ZEXPORT
+#define ZEXPORTVA
+
+#define FAR
+
+typedef unsigned char Byte;
+typedef unsigned int uInt;
+typedef unsigned long uLong;
+
+typedef Byte Bytef;
+typedef char charf;
+typedef int intf;
+typedef uInt uIntf;
+typedef uLong uLongf;
+
+typedef void const *voidpc;
+typedef void *voidpf;
+typedef void *voidp;
+
+#define z_off_t long
+
+#define z_off64_t z_off_t
+
+#define NO_vsnprintf 1
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/zlib/zio.c b/test/monniaux/glpk-4.65/src/zlib/zio.c
new file mode 100644
index 00000000..a55b258a
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/zio.c
@@ -0,0 +1,92 @@
+/* zio.c (simulation of non-standard low-level i/o functions) */
+
+/* Written by Andrew Makhorin <mao@gnu.org>, April 2011
+ * For conditions of distribution and use, see copyright notice in
+ * zlib.h */
+
+/* (reserved for copyright notice) */
+
+#include <assert.h>
+#include <stdio.h>
+#include "zio.h"
+
+static FILE *file[FOPEN_MAX];
+static int initialized = 0;
+
+static void initialize(void)
+{ int fd;
+ assert(!initialized);
+ file[0] = stdin;
+ file[1] = stdout;
+ file[2] = stderr;
+ for (fd = 3; fd < FOPEN_MAX; fd++)
+ file[fd] = NULL;
+ initialized = 1;
+ return;
+}
+
+int open(const char *path, int oflag, ...)
+{ FILE *fp;
+ int fd;
+ if (!initialized) initialize();
+ /* see file gzlib.c, function gz_open */
+ if (oflag == O_RDONLY)
+ fp = fopen(path, "rb");
+ else if (oflag == (O_WRONLY | O_CREAT | O_TRUNC))
+ fp = fopen(path, "wb");
+ else if (oflag == (O_WRONLY | O_CREAT | O_APPEND))
+ fp = fopen(path, "ab");
+ else
+ assert(oflag != oflag);
+ if (fp == NULL)
+ return -1;
+ for (fd = 0; fd < FOPEN_MAX; fd++)
+ if (file[fd] == NULL) break;
+ assert(fd < FOPEN_MAX);
+ file[fd] = fp;
+ return fd;
+}
+
+long read(int fd, void *buf, unsigned long nbyte)
+{ unsigned long count;
+ if (!initialized) initialize();
+ assert(0 <= fd && fd < FOPEN_MAX);
+ assert(file[fd] != NULL);
+ count = fread(buf, 1, nbyte, file[fd]);
+ if (ferror(file[fd]))
+ return -1;
+ return count;
+}
+
+long write(int fd, const void *buf, unsigned long nbyte)
+{ unsigned long count;
+ if (!initialized) initialize();
+ assert(0 <= fd && fd < FOPEN_MAX);
+ assert(file[fd] != NULL);
+ count = fwrite(buf, 1, nbyte, file[fd]);
+ if (count != nbyte)
+ return -1;
+ if (fflush(file[fd]) != 0)
+ return -1;
+ return count;
+}
+
+long lseek(int fd, long offset, int whence)
+{ if (!initialized) initialize();
+ assert(0 <= fd && fd < FOPEN_MAX);
+ assert(file[fd] != NULL);
+ if (fseek(file[fd], offset, whence) != 0)
+ return -1;
+ return ftell(file[fd]);
+}
+
+int close(int fd)
+{ if (!initialized) initialize();
+ assert(0 <= fd && fd < FOPEN_MAX);
+ assert(file[fd] != NULL);
+ fclose(file[fd]);
+ file[fd] = NULL;
+ return 0;
+}
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/zlib/zio.h b/test/monniaux/glpk-4.65/src/zlib/zio.h
new file mode 100644
index 00000000..1626c4ae
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/zio.h
@@ -0,0 +1,37 @@
+/* zio.h (simulation of non-standard low-level i/o functions) */
+
+/* Written by Andrew Makhorin <mao@gnu.org>, April 2011
+ * For conditions of distribution and use, see copyright notice in
+ * zlib.h */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h. */
+
+#ifndef ZIO_H
+#define ZIO_H
+
+#define O_RDONLY 0x00
+#define O_WRONLY 0x01
+#define O_CREAT 0x10
+#define O_TRUNC 0x20
+#define O_APPEND 0x30
+
+#define open _glp_zlib_open
+int open(const char *path, int oflag, ...);
+
+#define read _glp_zlib_read
+long read(int fd, void *buf, unsigned long nbyte);
+
+#define write _glp_zlib_write
+long write(int fd, const void *buf, unsigned long nbyte);
+
+#define lseek _glp_zlib_lseek
+long lseek(int fd, long offset, int whence);
+
+#define close _glp_zlib_close
+int close(int fd);
+
+#endif
+
+/* eof */
diff --git a/test/monniaux/glpk-4.65/src/zlib/zlib.h b/test/monniaux/glpk-4.65/src/zlib/zlib.h
new file mode 100644
index 00000000..bfbba83e
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/zlib.h
@@ -0,0 +1,1613 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.5, April 19th, 2010
+
+ Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.5"
+#define ZLIB_VERNUM 0x1250
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 5
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed data.
+ This version of the library supports only one compression method (deflation)
+ but other algorithms will be added later and will have the same stream
+ interface.
+
+ Compression can be done in a single step if the buffers are large enough,
+ or can be done by repeated calls of the compression function. In the latter
+ case, the application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never crash
+ even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has dropped
+ to zero. It must update next_out and avail_out when avail_out has dropped
+ to zero. The application must initialize zalloc, zfree and opaque before
+ calling the init function. All other fields are set by the compression
+ library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this if
+ the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers
+ returned by zalloc for objects of exactly 65536 bytes *must* have their
+ offset normalized to zero. The default allocation function provided by this
+ library ensures this (see zutil.c). To reduce memory requirements and avoid
+ any allocation of 64K objects, at the expense of compression ratio, compile
+ the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or progress
+ reports. After compression, total_in holds the total size of the
+ uncompressed data and may be saved for use in the decompressor (particularly
+ if the decompressor wants to decompress everything in a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+#define Z_TREES 6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is not
+ compatible with the zlib.h header file used by the application. This check
+ is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller. If
+ zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+ allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at all
+ (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION
+ requests a default compromise between speed and compression (currently
+ equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if level is not a valid compression level, or
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION). msg is set to null
+ if there is no error message. deflateInit does not perform any compression:
+ this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications). Some
+ output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating avail_in or avail_out accordingly; avail_out should
+ never be zero before the call. The application can consume the compressed
+ output when it wants, for example when the output buffer is full (avail_out
+ == 0), or after each call of deflate(). If deflate returns Z_OK and with
+ zero avail_out, it must be called again after making room in the output
+ buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumulate before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In
+ particular avail_in is zero after the call if enough output space has been
+ provided before the call.) Flushing may degrade compression for some
+ compression algorithms and so it should be used only when necessary. This
+ completes the current deflate block and follows it with an empty stored block
+ that is three bits plus filler bits to the next byte, followed by four bytes
+ (00 00 ff ff).
+
+ If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+ output buffer, but the output is not aligned to a byte boundary. All of the
+ input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+ This completes the current deflate block and follows it with an empty fixed
+ codes block that is 10 bits long. This assures that enough bytes are output
+ in order for the decompressor to finish the block before the empty fixed code
+ block.
+
+ If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+ for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+ seven bits of the current block are held to be written as the next byte after
+ the next deflate block is completed. In this case, the decompressor may not
+ be provided enough bits at this point in order to complete decompression of
+ the data provided so far to the compressor. It may need to wait for the next
+ block to be emitted. This is for advanced applications that need to control
+ the emission of deflate blocks.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there was
+ enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the stream
+ are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least the
+ value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect the
+ compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case, msg
+ may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the
+ exact value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit() does not process any header information -- that is deferred
+ until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing will
+ resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there is
+ no more input data or no more space in the output buffer (see below about
+ the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating the next_* and avail_* values accordingly. The
+ application can consume the uncompressed output when it wants, for example
+ when the output buffer is full (avail_out == 0), or after each call of
+ inflate(). If inflate returns Z_OK and with zero avail_out, it must be
+ called again after making room in the output buffer because there might be
+ more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+ Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate()
+ stop if and when it gets to the next deflate block boundary. When decoding
+ the zlib or gzip format, this will cause inflate() to return immediately
+ after the header and before the first block. When doing a raw inflate,
+ inflate() will go ahead and process the first block, and will return when it
+ gets to the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64 if
+ inflate() is currently decoding the last block in the deflate stream, plus
+ 128 if inflate() returned immediately after decoding an end-of-block code or
+ decoding the complete header up to just before the first byte of the deflate
+ stream. The end-of-block will not be indicated until all of the uncompressed
+ data from that block has been written to strm->next_out. The number of
+ unused bits may in general be greater than seven, except when bit 7 of
+ data_type is set, in which case the number of unused bits will be less than
+ eight. data_type is set as noted here every time inflate() returns for all
+ flush options, and so can be used to determine the amount of currently
+ consumed input in bits.
+
+ The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+ end of each deflate block header is reached, before any actual data in that
+ block is decoded. This allows the caller to determine the length of the
+ deflate block header for later use in random access within a deflate block.
+ 256 is added to the value of strm->data_type when inflate() returns
+ immediately after reaching the end of the deflate block header.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step (a
+ single call of inflate), the parameter flush should be set to Z_FINISH. In
+ this case all pending input is processed and all pending output is flushed;
+ avail_out must be large enough to hold all the uncompressed data. (The size
+ of the uncompressed data may have been saved by the compressor for this
+ purpose.) The next operation on this stream must be inflateEnd to deallocate
+ the decompression state. The use of Z_FINISH is never required, but can be
+ used to inform inflate that a faster approach may be used for the single
+ inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK or Z_TREES is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically, if requested when
+ initializing with inflateInit2(). Any information contained in the gzip
+ header is not retained, so applications that need that information should
+ instead use raw inflate, see inflateInit2() below, or inflateBack() and
+ perform their own processing of the gzip header and trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may
+ then call inflateSync() to look for a good compression block if a partial
+ recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by the
+ caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero), no
+ header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but is
+ slow and reduces compression ratio; memLevel=9 uses maximum memory for
+ optimal speed. The default value is 8. See zconf.h for total memory usage
+ as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as
+ fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The
+ strategy parameter only affects the compression ratio but not the
+ correctness of the compressed output even if it is not set appropriately.
+ Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+ decoder for special applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+ method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+ incompatible with the version assumed by the caller (ZLIB_VERSION). msg is
+ set to null if there is no error message. deflateInit2 does not perform any
+ compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any call
+ of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size
+ provided in deflateInit or deflateInit2. Thus the strings most likely to be
+ useful should be put at the end of the dictionary, not at the front. In
+ addition, the current implementation of deflate will use at most the window
+ size minus 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and can
+ consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state. The
+ stream will keep the same compression level and any other attributes that
+ may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different strategy.
+ If the compression level is changed, the input available so far is
+ compressed with the old level (and may be flushed); the new level will take
+ effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to be
+ compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+ strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit() or
+ deflateInit2(), and after deflateSetHeader(), if used. This would be used
+ to allocate an output buffer for deflation in a single pass, and so would be
+ called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the bits
+ leftover from a previous deflate stream when appending to it. As such, this
+ function can only be used for raw deflate, and must be used before the first
+ deflate() call after a deflateInit2() or deflateReset(). bits must be less
+ than or equal to 16, and that many of the least significant bits of value
+ will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be zero to request that inflate use the window size in
+ the zlib header of the compressed stream.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a
+ crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit2 does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit2() does not process any header information -- that is
+ deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been
+ found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the
+ success case, the application may save the current current value of total_in
+ which indicates where valid compressed data was found. In the error case,
+ the application may repeatedly call inflateSync, providing more input each
+ time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state. The
+ stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+ int windowBits));
+/*
+ This function is the same as inflateReset, but it also permits changing
+ the wrap and window size requests. The windowBits parameter is interpreted
+ the same as it is for inflateInit2.
+
+ inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+ the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ If bits is negative, then the input stream bit buffer is emptied. Then
+ inflatePrime() can be called again to put bits in the buffer. This is used
+ to clear out bits leftover after feeding inflate a block description prior
+ to feeding inflate codes.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+ This function returns two values, one in the lower 16 bits of the return
+ value, and the other in the remaining upper bits, obtained by shifting the
+ return value down 16 bits. If the upper value is -1 and the lower value is
+ zero, then inflate() is currently decoding information outside of a block.
+ If the upper value is -1 and the lower value is non-zero, then inflate is in
+ the middle of a stored block, with the lower value equaling the number of
+ bytes from the input remaining to copy. If the upper value is not -1, then
+ it is the number of bits back from the current bit position in the input of
+ the code (literal or length/distance pair) currently being processed. In
+ that case the lower value is the number of bytes already emitted for that
+ code.
+
+ A code is being processed if inflate is waiting for more input to complete
+ decoding of the code, or if it has completed decoding but is waiting for
+ more output space to write the literal or match data.
+
+ inflateMark() is used to mark locations in the input data for random
+ access, which may be at bit positions, and to note those cases where the
+ output of a code may span boundaries of random access blocks. The current
+ location in the input stream can be determined from avail_in and data_type
+ as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+ inflateMark returns the value noted above or -1 << 16 if the provided
+ source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be
+ used to force inflate() to return immediately after header processing is
+ complete and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When any
+ of extra, name, or comment are not Z_NULL and the respective field is not
+ present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not be
+ allocated, or Z_VERSION_ERROR if the version of the library does not match
+ the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free the
+ allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects only
+ the raw deflate stream to decompress. This is different from the normal
+ behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+ in the deflate stream (in which case strm->msg is set to indicate the nature
+ of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+ In the case of Z_BUF_ERROR, an input or output error can be distinguished
+ using strm->next_in which will be Z_NULL only if in() returned an error. If
+ strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+ non-zero. (in() will always be called before out(), so strm->next_in is
+ assured to be defined if out() returns non-zero.) Note that inflateBack()
+ cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the basic
+ stream-oriented functions. To simplify the interface, some default options
+ are assumed (compression level and memory usage, standard memory allocation
+ functions). The source code of these utility functions can be modified if
+ you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before a
+ compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be large enough to hold the entire
+ uncompressed data. (The size of the uncompressed data must have been saved
+ previously by the compressor and transmitted to the decompressor by some
+ mechanism outside the scope of this compression library.) Upon exit, destLen
+ is the actual size of the uncompressed buffer.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+ /* gzip file access functions */
+
+/*
+ This library supports reading and writing files in gzip (.gz) format with
+ an interface similar to that of stdio, using the functions that start with
+ "gz". The gzip format is different from the zlib format. gzip is a gzip
+ wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef voidp gzFile; /* opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+ Opens a gzip (.gz) file for reading or writing. The mode parameter is as
+ in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+ a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+ compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+ for fixed code compression as in "wb9F". (See the description of
+ deflateInit2 for more information about the strategy parameter.) Also "a"
+ can be used instead of "w" to request that the gzip stream that will be
+ written be appended to the file. "+" will result in an error, since reading
+ and writing to the same gzip file is not supported.
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened, if there was
+ insufficient memory to allocate the gzFile state, or if an invalid mode was
+ specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+ errno can be checked to determine if the reason gzopen failed was that the
+ file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen associates a gzFile with the file descriptor fd. File descriptors
+ are obtained from calls like open, dup, creat, pipe or fileno (if the file
+ has been previously opened with fopen). The mode parameter is as in gzopen.
+
+ The next call of gzclose on the returned gzFile will also close the file
+ descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+ fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+ mode);. The duplicated descriptor should be saved to avoid a leak, since
+ gzdopen does not close fd if it fails.
+
+ gzdopen returns NULL if there was insufficient memory to allocate the
+ gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+ provided, or '+' was provided), or if fd is -1. The file descriptor is not
+ used until the next gz* read, write, seek, or close operation, so gzdopen
+ will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+ Set the internal buffer size used by this library's functions. The
+ default buffer size is 8192 bytes. This function must be called after
+ gzopen() or gzdopen(), and before any other calls that read or write the
+ file. The buffer memory allocation is always deferred to the first read or
+ write. Two buffers are allocated, either both of the specified size when
+ writing, or one of the specified size and the other twice that size when
+ reading. A larger buffer size of, for example, 64K or 128K bytes will
+ noticeably increase the speed of decompression (reading).
+
+ The new buffer size also affects the maximum length for gzprintf().
+
+ gzbuffer() returns 0 on success, or -1 on failure, such as being called
+ too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file. If
+ the input file was not in gzip format, gzread copies the given number of
+ bytes into the buffer.
+
+ After reaching the end of a gzip stream in the input, gzread will continue
+ to read, looking for another gzip stream, or failing that, reading the rest
+ of the input file directly without decompression. The entire input file
+ will be read if gzread is called until it returns less than the requested
+ len.
+
+ gzread returns the number of uncompressed bytes actually read, less than
+ len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes written or 0 in case of
+ error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the arguments to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written, or 0 in case of error. The number of
+ uncompressed bytes written is limited to 8191, or one less than the buffer
+ size given to gzbuffer(). The caller should assure that this limit is not
+ exceeded. If it is exceeded, then gzprintf() will return an error (0) with
+ nothing written. In this case, there may also be a buffer overflow with
+ unpredictable consequences, which is possible only if zlib was compiled with
+ the insecure functions sprintf() or vsprintf() because the secure snprintf()
+ or vsnprintf() functions were not available. This can be determined using
+ zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or a
+ newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. If any characters are read or if len == 1, the
+ string is terminated with a null character. If no characters are read due
+ to an end-of-file or len < 1, then the buffer is left untouched.
+
+ gzgets returns buf which is a null-terminated string, or it returns NULL
+ for end-of-file or in case of error. If there was an error, the contents at
+ buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file. gzputc
+ returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte or -1
+ in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read as the first character
+ on the next read. At least one character of push-back is allowed.
+ gzungetc() returns the character pushed, or -1 on failure. gzungetc() will
+ fail if c is -1, and may fail if a character has been pushed but not read
+ yet. If gzungetc is used immediately after gzopen or gzdopen, at least the
+ output buffer size of pushed characters is allowed. (See gzbuffer above.)
+ The pushed character will be discarded if the stream is repositioned with
+ gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter flush
+ is as in the deflate() function. The return value is the zlib error number
+ (see function gzerror below). gzflush is only permitted when writing.
+
+ If the flush parameter is Z_FINISH, the remaining data is written and the
+ gzip stream is completed in the output. If gzwrite() is called again, a new
+ gzip stream will be started in the output. gzread() is able to read such
+ concatented gzip streams.
+
+ gzflush should be called only when strictly necessary because it will
+ degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+
+ Returns the starting position for the next gzread or gzwrite on the given
+ compressed file. This position represents a number of bytes in the
+ uncompressed data stream, and is zero when starting, even if appending or
+ reading a gzip stream from the middle of a file using gzdopen().
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+ Returns the current offset in the file being read or written. This offset
+ includes the count of bytes that precede the gzip stream, for example when
+ appending or when using gzdopen() for reading. When reading, the offset
+ does not include as yet unused buffered input. This information can be used
+ for a progress indicator. On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns true (1) if the end-of-file indicator has been set while reading,
+ false (0) otherwise. Note that the end-of-file indicator is set only if the
+ read tried to go past the end of the input, but came up short. Therefore,
+ just like feof(), gzeof() may return false even if there is no more data to
+ read, in the event that the last read request was for the exact number of
+ bytes remaining in the input file. This will happen if the input file size
+ is an exact multiple of the buffer size.
+
+ If gzeof() returns true, then the read functions will return no more data,
+ unless the end-of-file indicator is reset by gzclearerr() and the input file
+ has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns true (1) if file is being copied directly while reading, or false
+ (0) if file is a gzip stream being decompressed. This state can change from
+ false to true while reading the input file if the end of a gzip stream is
+ reached, but is followed by data that is not another gzip stream.
+
+ If the input file is empty, gzdirect() will return true, since the input
+ does not contain a gzip stream.
+
+ If gzdirect() is used immediately after gzopen() or gzdopen() it will
+ cause buffers to be allocated to allow reading the file to determine if it
+ is a gzip file. Therefore if gzbuffer() is used, it should be called before
+ gzdirect().
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file and
+ deallocates the (de)compression state. Note that once file is closed, you
+ cannot call gzerror with file, since its structures have been deallocated.
+ gzclose must not be called more than once on the same file, just as free
+ must not be called more than once on the same allocation.
+
+ gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+ file operation error, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+ Same as gzclose(), but gzclose_r() is only for use when reading, and
+ gzclose_w() is only for use when writing or appending. The advantage to
+ using these instead of gzclose() is that they avoid linking in zlib
+ compression or decompression code that is not used when only reading or only
+ writing respectively. If gzclose() is used, then both compression and
+ decompression code will be included the application when linking to a static
+ zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the given
+ compressed file. errnum is set to zlib error number. If an error occurred
+ in the file system and not in the compression library, errnum is set to
+ Z_ERRNO and the application may consult errno to get the exact error code.
+
+ The application must not modify the returned string. Future calls to
+ this function may invalidate the previously returned string. If file is
+ closed, then the string previously returned by gzerror will no longer be
+ available.
+
+ gzerror() should be used to distinguish errors from end-of-file for those
+ functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the compression
+ library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is Z_NULL, this function returns the
+ required initial value for the checksum.
+
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster.
+
+ Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is Z_NULL, this function returns the required
+ initial value for the for the crc. Pre- and post-conditioning (one's
+ complement) is performed within this function so it shouldn't be done by the
+ application.
+
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+ ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0
+# define gzopen gzopen64
+# define gzseek gzseek64
+# define gztell gztell64
+# define gzoffset gzoffset64
+# define adler32_combine adler32_combine64
+# define crc32_combine crc32_combine64
+# ifdef _LARGEFILE64_SOURCE
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+# endif
+#else
+ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/test/monniaux/glpk-4.65/src/zlib/zutil.c b/test/monniaux/glpk-4.65/src/zlib/zutil.c
new file mode 100644
index 00000000..898ed345
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/zutil.c
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch ((int)(sizeof(uInt))) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch ((int)(sizeof(uLong))) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch ((int)(sizeof(voidpf))) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch ((int)(sizeof(z_off_t))) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#ifdef STDC
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int ZLIB_INTERNAL z_verbose = verbose;
+
+void ZLIB_INTERNAL z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void ZLIB_INTERNAL zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int ZLIB_INTERNAL zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void ZLIB_INTERNAL zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void ZLIB_INTERNAL zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/test/monniaux/glpk-4.65/src/zlib/zutil.h b/test/monniaux/glpk-4.65/src/zlib/zutil.h
new file mode 100644
index 00000000..737bd38f
--- /dev/null
+++ b/test/monniaux/glpk-4.65/src/zlib/zutil.h
@@ -0,0 +1,93 @@
+/* zutil.h (internal interface of the zlib compression library) */
+
+/* Modified by Andrew Makhorin <mao@gnu.org>, April 2011 */
+
+/* Copyright (C) 1995-2010 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in
+ * zlib.h */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h. */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+
+#include "zlib.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define local static
+
+typedef unsigned char uch;
+typedef uch uchf;
+typedef unsigned short ush;
+typedef ush ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10];
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm, err) \
+ return (strm->msg = (char *)ERR_MSG(err), (err))
+
+#define DEF_WBITS MAX_WBITS
+
+#if MAX_MEM_LEVEL >= 8
+#define DEF_MEM_LEVEL 8
+#else
+#define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+
+#define PRESET_DICT 0x20
+
+#define OS_CODE 0x03 /* assume Unix */
+
+#define HAVE_MEMCPY 1
+#define zmemcpy memcpy
+#define zmemzero(dest, len) memset(dest, 0, len)
+
+#ifdef DEBUG
+#include <stdio.h>
+extern int ZLIB_INTERNAL z_verbose;
+extern void ZLIB_INTERNAL z_error OF((char *m));
+#define Assert(cond, msg) { if(!(cond)) z_error(msg); }
+#define Trace(x) { if (z_verbose >= 0) fprintf x; }
+#define Tracev(x) { if (z_verbose > 0) fprintf x; }
+#define Tracevv(x) {if (z_verbose > 1) fprintf x; }
+#define Tracec(c, x) {if (z_verbose > 0 && (c)) fprintf x; }
+#define Tracecv(c, x) {if (z_verbose > 1 && (c)) fprintf x; }
+#else
+#define Assert(cond, msg)
+#define Trace(x)
+#define Tracev(x)
+#define Tracevv(x)
+#define Tracec(c, x)
+#define Tracecv(c, x)
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
+ unsigned size));
+void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) \
+ (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) { if (p) ZFREE(s, p); }
+
+#endif
+
+/* eof */